You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by bh...@apache.org on 2019/09/13 08:15:45 UTC

[incubator-dlab] 01/01: DLAB-927 added support of multiple endpoints

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

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

commit aee74dcf3479d996b765931700d0a4babb47391e
Author: bhliva <bo...@epam.com>
AuthorDate: Fri Sep 13 11:15:30 2019 +0300

    DLAB-927 added support of multiple endpoints
---
 .../epam/dlab/dto/base/project/ProjectResult.java  |  2 +
 .../java/com/epam/dlab/dto/status/EnvResource.java |  9 ++++-
 .../com/epam/dlab/rest/client/RESTService.java     | 12 ++++--
 .../epam/dlab/rest/client/RESTServiceFactory.java  | 47 ++++++++++------------
 .../dlab/rest/contracts/InfrasctructureAPI.java    |  2 +-
 .../epam/dlab/backendapi/core/DockerWarmuper.java  |  2 +-
 .../response/handlers/ProjectCallbackHandler.java  |  5 ++-
 .../service/impl/ProjectServiceImpl.java           | 14 ++++---
 .../java/com/epam/dlab/backendapi/dao/EnvDAO.java  | 37 ++++++++++-------
 .../com/epam/dlab/backendapi/dao/ProjectDAO.java   |  6 ++-
 .../epam/dlab/backendapi/dao/ProjectDAOImpl.java   | 35 +++++++++++-----
 .../dlab/backendapi/domain/CreateProjectDTO.java   | 21 ++++++++++
 .../epam/dlab/backendapi/domain/EndpointDTO.java   |  3 ++
 .../dlab/backendapi/domain/EnvStatusListener.java  | 25 ++++++------
 .../backendapi/domain/ExploratoryLibCache.java     | 15 +++++--
 .../epam/dlab/backendapi/domain/ProjectDTO.java    |  7 +---
 .../dlab/backendapi/domain/ProjectEndpointDTO.java | 12 ++++++
 .../resources/InfrastructureTemplateResource.java  | 14 ++++---
 .../dlab/backendapi/resources/ProjectResource.java | 22 +++++-----
 .../resources/callback/ProjectCallback.java        |  5 +--
 .../resources/dto/ProjectActionFormDTO.java        |  2 +
 .../resources/dto/ProjectInfrastructureInfo.java   |  2 +-
 .../dlab/backendapi/service/GuacamoleService.java  |  2 +-
 .../service/InfrastructureTemplateService.java     |  4 +-
 .../dlab/backendapi/service/ProjectService.java    |  4 +-
 .../service/impl/ComputationalServiceImpl.java     | 36 +++++++++++------
 .../service/impl/EnvironmentServiceImpl.java       | 24 +++++------
 .../service/impl/ExploratoryServiceImpl.java       | 17 +++++---
 .../service/impl/GitCredentialServiceImpl.java     |  6 ++-
 .../service/impl/GuacamoleServiceImpl.java         | 11 +++--
 .../impl/InfrastructureInfoServiceBase.java        | 15 +++++--
 .../impl/InfrastructureTemplateServiceBase.java    | 16 +++++---
 .../service/impl/LibraryServiceImpl.java           | 14 +++++--
 .../service/impl/ProjectServiceImpl.java           | 41 ++++++++++---------
 .../servlet/guacamole/GuacamoleServlet.java        | 16 ++++++--
 .../epam/dlab/backendapi/util/RequestBuilder.java  |  4 +-
 .../resources/webapp/src/app/app.routing.module.ts |  2 +-
 .../src/app/core/services/userResource.service.ts  |  8 ++--
 .../resources/webapp/src/app/core/util/patterns.ts |  2 +-
 ...mputational-resource-create-dialog.component.ts |  6 +--
 .../create-environment.component.html              |  4 +-
 .../create-environment.component.ts                | 11 +++--
 .../resources-grid/resources-grid.component.html   |  2 +-
 .../resources-grid/resources-grid.model.ts         | 18 ++++-----
 .../src/app/webterminal/webterminal.component.ts   |  8 ++--
 .../InfrastructureTemplateResourceTest.java        | 36 ++++++++---------
 .../InfrastructureTemplateServiceBaseTest.java     | 22 +++++-----
 47 files changed, 391 insertions(+), 237 deletions(-)

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
index 8d9bf8f..11a6db6 100644
--- 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
@@ -12,5 +12,7 @@ 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/status/EnvResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
index 3f5aef2..808581f 100644
--- 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
@@ -44,15 +44,18 @@ public class EnvResource {
 	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) {
+	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;
 	}
 
 	/**
@@ -138,6 +141,10 @@ public class EnvResource {
 		return this;
 	}
 
+	public String getEndpoint() {
+		return endpoint;
+	}
+
 	public ToStringHelper toStringHelper(Object self) {
 		return MoreObjects.toStringHelper(self)
 				.add("id", id)
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
index bfd1ba1..76e4c79 100644
--- 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
@@ -46,6 +46,11 @@ public class RESTService {
 		this.userAgent = userAgent;
 	}
 
+	RESTService(Client client, String userAgent) {
+		this.client = client;
+		this.userAgent = userAgent;
+	}
+
 	public <T> T get(String path, Class<T> clazz) {
 		Invocation.Builder builder = getBuilder(path);
 		log.debug("REST get {}", path);
@@ -54,7 +59,7 @@ public class RESTService {
 
 	public <T> T get(URI path, Class<T> clazz) {
 		log.debug("REST get {}", path);
-		return client.target(URI.create(url + path.toString()))
+		return getWebTarget(path.toString())
 				.request()
 				.get(clazz);
 	}
@@ -110,8 +115,7 @@ public class RESTService {
 	}
 
 	private WebTarget getWebTarget(String path) {
-		return client
-				.target(url)
-				.path(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
index 66ce8da..a7aa942 100644
--- 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
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.dropwizard.client.JerseyClientBuilder;
 import io.dropwizard.client.JerseyClientConfiguration;
 import io.dropwizard.setup.Environment;
-import org.hibernate.validator.constraints.NotEmpty;
+import org.apache.commons.lang3.StringUtils;
 
 import javax.validation.Valid;
 import javax.validation.constraints.Max;
@@ -32,34 +32,31 @@ import javax.validation.constraints.NotNull;
 import javax.ws.rs.client.Client;
 
 public class RESTServiceFactory {
-    @NotEmpty
-    @JsonProperty
-    private String protocol;
+	@JsonProperty
+	private String protocol;
 
-    @NotEmpty
-    @JsonProperty
-    private String host;
+	@JsonProperty
+	private String host;
 
-    @Min(1)
-    @Max(65535)
-    @JsonProperty
-    private int port;
+	@JsonProperty
+	private int port;
 
-    @Valid
-    @NotNull
-    @JsonProperty("jerseyClient")
-    private JerseyClientConfiguration jerseyClientConfiguration;
+	@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) {
+		return build(environment, name, null);
+	}
 
-    public RESTService build(Environment environment, String name, String userAgent) {
-        Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name);
-        return new RESTService(client, getURL(), userAgent);
-    }
+	public RESTService build(Environment environment, String name, String userAgent) {
+		Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name);
+		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);
-    }
+	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/InfrasctructureAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/InfrasctructureAPI.java
index 57fb6e0..38bf959 100644
--- 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
@@ -19,7 +19,7 @@
 package com.epam.dlab.rest.contracts;
 
 public final class InfrasctructureAPI {
-	public static final String INFRASTRUCTURE = "/infrastructure";
+	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";
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
index 1cc7441..74cc4ad 100644
--- 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
@@ -35,7 +35,6 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import io.dropwizard.lifecycle.Managed;
-import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,6 +43,7 @@ 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);
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
index d6b1f71..7f890d4 100644
--- 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
@@ -17,14 +17,16 @@ public class ProjectCallbackHandler extends ResourceCallbackHandler<ProjectResul
 	private final String callbackUri;
 	private final String projectName;
 	private final Class<? extends EdgeInfo> clazz;
+	private final String endpointName;
 
 	public ProjectCallbackHandler(SystemUserInfoService systemUserInfoService, RESTService selfService, String user,
 								  String uuid, DockerAction action, String callbackUri, String projectName,
-								  Class<? extends EdgeInfo> clazz) {
+								  Class<? extends EdgeInfo> clazz, String endpointName) {
 		super(systemUserInfoService, selfService, user, uuid, action);
 		this.callbackUri = callbackUri;
 		this.projectName = projectName;
 		this.clazz = clazz;
+		this.endpointName = endpointName;
 	}
 
 	@Override
@@ -35,6 +37,7 @@ public class ProjectCallbackHandler extends ResourceCallbackHandler<ProjectResul
 	@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 {
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
index 670cadc..956a4f5 100644
--- 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
@@ -39,32 +39,34 @@ public class ProjectServiceImpl implements ProjectService {
 
 	@Override
 	public String create(UserInfo userInfo, ProjectCreateDTO dto) {
-		return executeDocker(userInfo, dto, DockerAction.CREATE, dto.getName(), "project", PROJECT_IMAGE);
+		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);
+		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);
+		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);
+		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 resourceType, String image, String endpoint) {
 		String uuid = DockerCommands.generateUUID();
 
 		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
 				configuration.getKeyLoaderPollTimeout(),
 				new ProjectCallbackHandler(systemUserInfoService, selfService, userInfo.getName(), uuid,
-						action, CALLBACK_URI, projectName, getEdgeClass()));
+						action, CALLBACK_URI, projectName, getEdgeClass(), endpoint));
 
 		RunDockerCommand runDockerCommand = new RunDockerCommand()
 				.withInteractive()
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
index 8254abf..0ac2f9a 100644
--- 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
@@ -69,9 +69,10 @@ public class EnvDAO extends BaseDAO {
 	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,
+	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,
@@ -88,22 +89,26 @@ public class EnvDAO extends BaseDAO {
 	 *
 	 * @param user name.
 	 */
-	public EnvResourceList findEnvResources(String user) {
+	public Map<String, EnvResourceList> findEnvResources(String user) {
 		List<EnvResource> hostList = new ArrayList<>();
 		List<EnvResource> clusterList = new ArrayList<>();
 
-		//getEdgeNode(user).ifPresent(edge -> addResource(hostList, edge, EDGE_STATUS, ResourceType.EDGE, null));
-
 		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);
-					addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName, project);
+					final String endpoint = exp.getString(ENDPOINT);
+					addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName, project, endpoint);
 					addComputationalResources(hostList, clusterList, exp, exploratoryName);
 				});
-		return new EnvResourceList()
-				.withHostList(!hostList.isEmpty() ? hostList : Collections.emptyList())
-				.withClusterList(!clusterList.isEmpty() ? clusterList : Collections.emptyList());
+		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")
@@ -114,8 +119,9 @@ public class EnvDAO extends BaseDAO {
 				.collect(Collectors.toList());
 	}
 
-	private EnvResource toEnvResource(String name, String instanceId, ResourceType resType, String project) {
-		return new EnvResource(instanceId, name, resType, project);
+	private EnvResource toEnvResource(String name, String instanceId, ResourceType resType, String project,
+									  String endpoint) {
+		return new EnvResource(instanceId, name, resType, project, endpoint);
 	}
 
 	@SuppressWarnings("unchecked")
@@ -123,7 +129,8 @@ public class EnvDAO extends BaseDAO {
 										   String exploratoryName) {
 		final String project = exp.getString(PROJECT);
 		getComputationalResources(exp)
-				.forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp, project));
+				.forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp, project,
+						exp.getString(ENDPOINT)));
 	}
 
 	private List<Document> getComputationalResources(Document userInstanceDocument) {
@@ -131,12 +138,12 @@ public class EnvDAO extends BaseDAO {
 	}
 
 	private void addComputational(List<EnvResource> hostList, List<EnvResource> clusterList, String exploratoryName,
-								  Document computational, String project) {
+								  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);
+				String.join("_", exploratoryName, computational.getString(COMPUTATIONAL_NAME)), project, endpoint);
 	}
 
 	/**
@@ -489,13 +496,13 @@ public class EnvDAO extends BaseDAO {
 	 * @param resourceType    type if resource EDGE/NOTEBOOK
 	 */
 	private void addResource(List<EnvResource> list, Document document, String statusFieldName,
-							 ResourceType resourceType, String name, String project) {
+							 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))));
+						.ifPresent(s -> list.add(toEnvResource(name, instanceId, resourceType, project, endpoint))));
 	}
 
 	private boolean notEmpty(List<EnvResource> hostList) {
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
index b94b2e6..1bc806e 100644
--- 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
@@ -3,6 +3,7 @@ package com.epam.dlab.backendapi.dao;
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+import com.epam.dlab.dto.UserInstanceStatus;
 import com.epam.dlab.dto.base.edge.EdgeInfo;
 
 import java.util.List;
@@ -14,13 +15,14 @@ public interface ProjectDAO {
 
 	List<ProjectDTO> getProjectsWithStatus(ProjectDTO.Status status);
 
-	List<ProjectDTO> getUserProjectsWithStatus(UserInfo userInfo, ProjectDTO.Status status);
+	List<ProjectDTO> getUserProjects(UserInfo userInfo);
 
 	void create(ProjectDTO projectDTO);
 
 	void updateStatus(String projectName, ProjectDTO.Status status);
+	void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status);
 
-	void updateEdgeInfoAndStatus(String projectName, EdgeInfo edgeInfo, ProjectDTO.Status status);
+	void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo);
 
 	Optional<ProjectDTO> get(String name);
 
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
index dccc7df..7da6e15 100644
--- 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
@@ -3,16 +3,19 @@ package com.epam.dlab.backendapi.dao;
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+import com.epam.dlab.dto.UserInstanceStatus;
 import com.epam.dlab.dto.base.edge.EdgeInfo;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 import com.mongodb.BasicDBObject;
-import com.mongodb.client.result.UpdateResult;
 import org.bson.Document;
 import org.bson.conversions.Bson;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
 
 import static com.mongodb.client.model.Filters.*;
 
@@ -23,6 +26,7 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
 	private static final String ENDPOINTS = "endpoints";
 	private static final String STATUS_FIELD = "status";
 	private static final String EDGE_INFO_FIELD = "edgeInfo";
+	private static final String ENDPOINT_FIELD = "endpoints.$.";
 
 	private final UserGroupDao userGroupDao;
 
@@ -43,9 +47,9 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
 	}
 
 	@Override
-	public List<ProjectDTO> getUserProjectsWithStatus(UserInfo userInfo, ProjectDTO.Status status) {
+	public List<ProjectDTO> getUserProjects(UserInfo userInfo) {
 		return find(PROJECTS_COLLECTION, and(in(GROUPS, Sets.union(userGroupDao.getUserGroups(userInfo.getName()),
-				userInfo.getRoles())), eq(STATUS_FIELD, status.toString())), ProjectDTO.class);
+				userInfo.getRoles()))), ProjectDTO.class);
 	}
 
 	@Override
@@ -60,13 +64,20 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
 	}
 
 	@Override
-	public void updateEdgeInfoAndStatus(String projectName, EdgeInfo edgeInfo, ProjectDTO.Status status) {
+	public void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status) {
 		BasicDBObject dbObject = new BasicDBObject();
-		dbObject.put(STATUS_FIELD, status.toString());
-		dbObject.put(EDGE_INFO_FIELD, convertToBson(edgeInfo));
-		final UpdateResult updateResult = updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
-				new Document(SET, dbObject));
-		System.out.println(updateResult);
+		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
@@ -107,4 +118,8 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
 	private Bson projectCondition(String name) {
 		return eq("name", name);
 	}
+
+	private Bson projectAndEndpointCondition(String projectName, String endpointName) {
+		return and(eq("name", projectName), eq("endpoints.name", endpointName));
+	}
 }
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
new file mode 100644
index 0000000..82e44ca
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/CreateProjectDTO.java
@@ -0,0 +1,21 @@
+package com.epam.dlab.backendapi.domain;
+
+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-.*", message = "Wrong key format. Key should be in openSSH format")
+	private final String key;
+	@NotNull
+	private final String tag;
+}
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
index e2cdfb3..378d71b 100644
--- 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
@@ -4,11 +4,14 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 
+import javax.annotation.RegEx;
+
 @Data
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class EndpointDTO {
 
 	private final String name;
+
 	private final String url;
 	private final String account;
 	@JsonProperty("endpoint_tag")
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EnvStatusListener.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EnvStatusListener.java
index a1dae09..64e8a18 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EnvStatusListener.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EnvStatusListener.java
@@ -23,6 +23,7 @@ package com.epam.dlab.backendapi.domain;
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.SelfServiceApplicationConfiguration;
 import com.epam.dlab.backendapi.dao.EnvDAO;
+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.UserEnvironmentResources;
@@ -61,6 +62,8 @@ public class EnvStatusListener implements Managed {
 
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private EndpointService endpointService;
 
 	@Inject
 	public EnvStatusListener(SelfServiceApplicationConfiguration configuration, EnvDAO dao,
@@ -138,26 +141,24 @@ public class EnvStatusListener implements Managed {
 		 * Sends request to docker to check the status of user environment.
 		 *
 		 * @param userInfo username
-		 * @return UUID associated with async operation
 		 */
-		private String checkStatusThroughProvisioningService(UserInfo userInfo) {
+		private void checkStatusThroughProvisioningService(UserInfo userInfo) {
 
-			String uuid = null;
-			EnvResourceList resourceList = dao.findEnvResources(userInfo.getName());
+			final Map<String, EnvResourceList> envResources = dao.findEnvResources(userInfo.getName());
 			UserEnvironmentResources dto = requestBuilder.newUserEnvironmentStatus(userInfo);
 
-			log.trace("EnvStatus listener check status for user {} with resource list {}", userInfo.getName(),
-					resourceList);
-
-			if (resourceList.getHostList() != null || resourceList.getClusterList() != null) {
+			envResources.forEach((endpoint, resourceList) -> {
+				log.trace("EnvStatus listener check status for user {} with resource list {}", userInfo.getName(),
+						resourceList);
 				dto.withResourceList(resourceList);
 				log.trace("Ask docker for the status of resources for user {}: {}", userInfo.getName(), dto);
-				uuid = provisioningService.post(InfrasctructureAPI.INFRASTRUCTURE_STATUS, userInfo.getAccessToken(),
-						dto, String.class);
+				String uuid =
+						provisioningService.post(endpointService.get(endpoint).getUrl() + InfrasctructureAPI.INFRASTRUCTURE_STATUS,
+								userInfo.getAccessToken(),
+								dto, String.class);
 				requestId.put(userInfo.getName(), uuid);
-			}
 
-			return uuid;
+			});
 		}
 	}
 }
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
index 2ff1148..13c6cda 100644
--- 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
@@ -21,10 +21,11 @@
 package com.epam.dlab.backendapi.domain;
 
 import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.resources.dto.LibraryDTO;
+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.backendapi.resources.dto.LibraryDTO;
 import com.epam.dlab.dto.UserInstanceDTO;
 import com.epam.dlab.dto.base.DataEngineType;
 import com.epam.dlab.dto.computational.UserComputationalResource;
@@ -59,6 +60,8 @@ public class ExploratoryLibCache implements Managed, Runnable {
 
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private EndpointService endpointService;
 
 	/**
 	 * Instance of cache.
@@ -222,12 +225,16 @@ public class ExploratoryLibCache implements Managed, Runnable {
 				UserComputationalResource userComputationalResource = userInstance.getResources().get(0);
 				LibListComputationalDTO dto = requestBuilder.newLibComputationalList(userInfo, userInstance,
 						userComputationalResource);
-				uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_LIB_LIST, userInfo.getAccessToken(),
+				uuid = provisioningService.post(endpointService
+								.get(userInstance.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_LIST,
+						userInfo.getAccessToken(),
 						dto, String.class);
 			} else {
 				ExploratoryActionDTO<?> dto = requestBuilder.newLibExploratoryList(userInfo, userInstance);
-				uuid = provisioningService.post(ExploratoryAPI.EXPLORATORY_LIB_LIST, userInfo.getAccessToken(), dto,
-						String.class);
+				uuid =
+						provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + ExploratoryAPI.EXPLORATORY_LIB_LIST,
+								userInfo.getAccessToken(), dto,
+								String.class);
 			}
 
 			requestId.put(userInfo.getName(), uuid);
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
index 07d018d..5d48c69 100644
--- 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
@@ -1,12 +1,12 @@
 package com.epam.dlab.backendapi.domain;
 
 import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import lombok.Data;
 
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
+import java.util.List;
 import java.util.Set;
 
 @Data
@@ -15,8 +15,6 @@ public class ProjectDTO {
 	@NotNull
 	private final String name;
 	@NotNull
-	private final Set<String> endpoints;
-	@NotNull
 	private final Set<String> groups;
 	@NotNull
 	@Pattern(regexp = "^ssh-.*", message = "Wrong key format. Key should be in openSSH format")
@@ -24,8 +22,7 @@ public class ProjectDTO {
 	@NotNull
 	private final String tag;
 	private final Integer budget;
-	private final Status status = Status.CREATING;
-	private EdgeInfo edgeInfo;
+	private final List<ProjectEndpointDTO> endpoints;
 
 
 	public enum Status {
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
new file mode 100644
index 0000000..5a2f2ba
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectEndpointDTO.java
@@ -0,0 +1,12 @@
+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/resources/InfrastructureTemplateResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
index 14a6572..f58dbf6 100644
--- 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
@@ -58,12 +58,13 @@ public class InfrastructureTemplateResource implements DockerAPI {
 	 * @param userInfo user info.
 	 */
 	@GET
-	@Path("/{project}/computational_templates")
+	@Path("/{project}/{endpoint}/computational_templates")
 	@ApiOperation("Returns list of cluster's templates")
 	public Iterable<FullComputationalTemplate> getComputationalTemplates(@ApiParam(hidden = true)
 																		 @Auth UserInfo userInfo,
-																		 @PathParam("project") String project) {
-		return infrastructureTemplateService.getComputationalTemplates(userInfo, project);
+																		 @PathParam("project") String project,
+																		 @PathParam("endpoint") String endpoint) {
+		return infrastructureTemplateService.getComputationalTemplates(userInfo, project, endpoint);
 	}
 
 	/**
@@ -72,11 +73,12 @@ public class InfrastructureTemplateResource implements DockerAPI {
 	 * @param userInfo user info.
 	 */
 	@GET
-	@Path("/{project}/exploratory_templates")
+	@Path("/{project}/{endpoint}/exploratory_templates")
 	@ApiOperation("Returns list of notebook's templates")
 	public Iterable<ExploratoryMetadataDTO> getExploratoryTemplates(@ApiParam(hidden = true) @Auth UserInfo userInfo,
-																	@PathParam("project") String project) {
-		return infrastructureTemplateService.getExploratoryTemplates(userInfo, project);
+																	@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/ProjectResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
index 397d12d..1df46d9 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
@@ -1,11 +1,10 @@
 package com.epam.dlab.backendapi.resources;
 
 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 com.epam.dlab.backendapi.domain.*;
 import com.epam.dlab.backendapi.resources.dto.ProjectActionFormDTO;
 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;
@@ -56,8 +55,13 @@ public class ProjectResource {
 	@POST
 	@Consumes(MediaType.APPLICATION_JSON)
 	@RolesAllowed("/api/project")
-	public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo, @Valid ProjectDTO projectDTO) {
-		projectService.create(userInfo, projectDTO);
+	public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								  @Valid CreateProjectDTO projectDTO) {
+
+		projectService.create(userInfo, new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(),
+				projectDTO.getKey(), projectDTO.getTag(), null,
+				projectDTO.getEndpoints().stream().map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING,
+						null)).collect(Collectors.toList())));
 		final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build();
 		return Response
 				.ok()
@@ -78,7 +82,7 @@ public class ProjectResource {
 	@RolesAllowed("/api/project")
 	public Response startProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
 								 @Valid ProjectActionFormDTO startProjectDto) {
-		projectService.start(userInfo, startProjectDto.getProjectName());
+		projectService.start(userInfo, startProjectDto.getEndpoint(), startProjectDto.getProjectName());
 		return Response
 				.accepted()
 				.build();
@@ -96,8 +100,8 @@ public class ProjectResource {
 	@Consumes(MediaType.APPLICATION_JSON)
 	@RolesAllowed("/api/project")
 	public Response stopProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
-								@Valid ProjectActionFormDTO startProjectDto) {
-		projectService.stop(userInfo, startProjectDto.getProjectName());
+								@Valid ProjectActionFormDTO stopProjectDTO) {
+		projectService.stop(userInfo, stopProjectDTO.getEndpoint(), stopProjectDTO.getProjectName());
 		return Response
 				.accepted()
 				.build();
@@ -209,7 +213,7 @@ public class ProjectResource {
 					List<UpdateProjectBudgetDTO> dtos) {
 		final List<ProjectDTO> projects = dtos
 				.stream()
-				.map(dto -> new ProjectDTO(dto.getProject(), null, null, null, null, dto.getBudget()))
+				.map(dto -> new ProjectDTO(dto.getProject(), null, null, null, dto.getBudget(), null))
 				.collect(Collectors.toList());
 		projectService.updateBudget(projects);
 		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
index 971c0cc..b349f08 100644
--- 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
@@ -2,7 +2,6 @@ package com.epam.dlab.backendapi.resources.callback;
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.domain.RequestId;
 import com.epam.dlab.backendapi.service.ExploratoryService;
 import com.epam.dlab.dto.UserInstanceStatus;
@@ -41,10 +40,10 @@ public class ProjectCallback {
 		final String projectName = projectResult.getProjectName();
 		final UserInstanceStatus status = UserInstanceStatus.of(projectResult.getStatus());
 		if (UserInstanceStatus.RUNNING == status && Objects.nonNull(projectResult.getEdgeInfo())) {
-			projectDAO.updateEdgeInfoAndStatus(projectName, projectResult.getEdgeInfo(), ProjectDTO.Status.ACTIVE);
+			projectDAO.updateEdgeInfo(projectName, projectResult.getEndpointName(), projectResult.getEdgeInfo());
 		} else {
 			updateExploratoriesStatusIfNeeded(status, projectResult.getProjectName());
-			projectDAO.updateStatus(projectName, ProjectDTO.Status.from(status));
+			projectDAO.updateEdgeStatus(projectName, projectResult.getEndpointName(), status);
 		}
 		return Response.ok().build();
 	}
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
index ac3a561..e82f8f6 100644
--- 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
@@ -7,4 +7,6 @@ import lombok.Data;
 public class ProjectActionFormDTO {
 	@JsonProperty("project_name")
 	private final String projectName;
+	@JsonProperty("endpoint")
+	private final String endpoint;
 }
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
index 314e11d..950893e 100644
--- 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
@@ -34,7 +34,7 @@ public class ProjectInfrastructureInfo {
 	@JsonProperty
 	private int billingQuoteUsed;
 	@JsonProperty
-	private Map<String, String> shared;
+	private Map<String, Map<String, String>> shared;
 	@JsonProperty
 	private Iterable<Document> exploratory;
 }
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
index 760e701..06dc8b1 100644
--- 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
@@ -5,6 +5,6 @@ import org.apache.guacamole.net.GuacamoleTunnel;
 
 public interface GuacamoleService {
 
-	GuacamoleTunnel getTunnel(UserInfo userInfo, String host);
+	GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint);
 
 }
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
index 4d6eba5..c5219ee 100644
--- 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
@@ -26,7 +26,7 @@ import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
 import java.util.List;
 
 public interface InfrastructureTemplateService {
-	List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project);
+	List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project, String endpoint);
 
-	List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project);
+	List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
index 4c1a69c..c2b407b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
@@ -19,9 +19,9 @@ public interface ProjectService {
 
 	void terminate(UserInfo userInfo, String name);
 
-	void start(UserInfo userInfo, String name);
+	void start(UserInfo userInfo, String endpoint, String name);
 
-	void stop(UserInfo userInfo, String name);
+	void stop(UserInfo userInfo, String endpoint, String name);
 
 	void update(UpdateProjectDTO projectDTO);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
index 1fe97d5..63f6551 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
@@ -29,6 +29,7 @@ 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.ComputationalService;
+import com.epam.dlab.backendapi.service.EndpointService;
 import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.constants.ServiceConsts;
@@ -89,6 +90,8 @@ public class ComputationalServiceImpl implements ComputationalService {
 	private RequestId requestId;
 	@Inject
 	private TagService tagService;
+	@Inject
+	private EndpointService endpointService;
 
 
 	@BudgetLimited
@@ -106,8 +109,9 @@ public class ComputationalServiceImpl implements ComputationalService {
 			try {
 				ComputationalBase<?> dto = requestBuilder.newComputationalCreate(userInfo, instance, form);
 
-				String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK,
-						userInfo.getAccessToken(), dto, String.class);
+				String uuid =
+						provisioningService.post(endpointService.get(instance.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK,
+								userInfo.getAccessToken(), dto, String.class);
 				requestId.put(userInfo.getName(), uuid);
 				return true;
 			} catch (RuntimeException e) {
@@ -143,7 +147,9 @@ public class ComputationalServiceImpl implements ComputationalService {
 
 			final String provisioningUrl = Optional.ofNullable(DATA_ENGINE_TYPE_TERMINATE_URLS.get(dataEngineType))
 					.orElseThrow(UnsupportedOperationException::new);
-			String uuid = provisioningService.post(provisioningUrl, userInfo.getAccessToken(), dto, String.class);
+			String uuid =
+					provisioningService.post(endpointService.get(userInstanceDTO.getEndpoint()).getUrl() + provisioningUrl,
+							userInfo.getAccessToken(), dto, String.class);
 			requestId.put(userInfo.getName(), uuid);
 		} catch (RuntimeException re) {
 
@@ -172,8 +178,9 @@ public class ComputationalServiceImpl implements ComputationalService {
 
 		if (isAdded) {
 			try {
-				String uuid = provisioningService.post(COMPUTATIONAL_CREATE_CLOUD_SPECIFIC, userInfo.getAccessToken(),
-						requestBuilder.newComputationalCreate(userInfo, instance, formDTO), String.class);
+				String uuid =
+						provisioningService.post(endpointService.get(instance.getEndpoint()).getUrl() + COMPUTATIONAL_CREATE_CLOUD_SPECIFIC, userInfo.getAccessToken(),
+								requestBuilder.newComputationalCreate(userInfo, instance, formDTO), String.class);
 				requestId.put(userInfo.getName(), uuid);
 				return true;
 			} catch (Exception t) {
@@ -199,9 +206,10 @@ public class ComputationalServiceImpl implements ComputationalService {
 		if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
 			log.debug("{} spark cluster {} for userInstance {}", STOPPING.toString(), compName, expName);
 			updateComputationalStatus(userInfo.getName(), expName, compName, STOPPING);
-			final String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_STOP_SPARK,
-					userInfo.getAccessToken(),
-					requestBuilder.newComputationalStop(userInfo, userInstance, compName), String.class);
+			final String uuid =
+					provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_STOP_SPARK,
+							userInfo.getAccessToken(),
+							requestBuilder.newComputationalStop(userInfo, userInstance, compName), String.class);
 			requestId.put(userInfo.getName(), uuid);
 		} else {
 			throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT,
@@ -219,9 +227,10 @@ public class ComputationalServiceImpl implements ComputationalService {
 		if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
 			log.debug("{} spark cluster {} for userInstance {}", STARTING.toString(), compName, expName);
 			updateComputationalStatus(userInfo.getName(), expName, compName, STARTING);
-			final String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_START_SPARK,
-					userInfo.getAccessToken(), requestBuilder.newComputationalStart(userInfo, userInstance,
-							compName), String.class);
+			final String uuid =
+					provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_START_SPARK,
+							userInfo.getAccessToken(), requestBuilder.newComputationalStart(userInfo, userInstance,
+									compName), String.class);
 			requestId.put(userInfo.getName(), uuid);
 		} else {
 			throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT,
@@ -245,8 +254,9 @@ public class ComputationalServiceImpl implements ComputationalService {
 						computationalName, exploratoryName)));
 		final ComputationalClusterConfigDTO clusterConfigDto = requestBuilder.newClusterConfigUpdate(userInfo,
 				userInstanceDTO, compResource, config);
-		final String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK, token,
-				clusterConfigDto, String.class);
+		final String uuid =
+				provisioningService.post(endpointService.get(userInstanceDTO.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK, token,
+						clusterConfigDto, String.class);
 		computationalDAO.updateComputationalFields(new ComputationalStatusDTO()
 				.withComputationalName(computationalName)
 				.withExploratoryName(exploratoryName)
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
index 1db1eac..2e101d8 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -37,10 +37,7 @@ 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.*;
 import java.util.stream.Stream;
 
 import static com.epam.dlab.backendapi.resources.dto.UserDTO.Status.ACTIVE;
@@ -128,9 +125,9 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 		checkProjectResourceConditions(project, "stop");
 		exploratoryDAO.fetchRunningExploratoryFieldsForProject(project)
 				.forEach(this::stopNotebook);
-		if (projectService.get(project).getStatus() == ProjectDTO.Status.ACTIVE) {
+		/*if (projectService.get(project).getStatus() == ProjectDTO.Status.ACTIVE) {
 			projectService.stop(systemUserInfoService.create("admin"), project);
-		}
+		}*/
 	}
 
 	@Override
@@ -226,16 +223,19 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 	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.getEdgeInfo() != null) {
-			UserResourceInfo edgeResource = new UserResourceInfo().withResourceType(ResourceEnum.EDGE_NODE)
-					.withResourceStatus(ProjectDTO.Status.from(projectDTO.getStatus()).toString())
-					.withProject(projectDTO.getName())
-					.withIp(projectDTO.getEdgeInfo().getPublicIp());
+		/*if (projectDTO.getEndpointEdgeInfo() != null) {
+			final Stream<UserResourceInfo> edges = projectDTO.getEndpointEdgeInfo().values()
+					.stream()
+					.map(ei -> new UserResourceInfo().withResourceType(ResourceEnum.EDGE_NODE)
+							.withResourceStatus(ProjectDTO.Status.from(projectDTO.getStatus()).toString())
+							.withProject(projectDTO.getName())
+							.withIp(ei.getPublicIp()));
 			return Stream.concat(Stream.of(edgeResource), userResources)
 					.collect(toList());
 		} else {
 			return userResources.collect(toList());
-		}
+		}*/
+		return Collections.emptyList();
 	}
 
 	private UserResourceInfo toUserResourceInfo(UserInstanceDTO userInstance) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
index 572fc88..1fb1a9e 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
@@ -27,6 +27,7 @@ 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.RequestId;
+import com.epam.dlab.backendapi.service.EndpointService;
 import com.epam.dlab.backendapi.service.ExploratoryService;
 import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
@@ -76,6 +77,8 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 	private RequestId requestId;
 	@Inject
 	private TagService tagService;
+	@Inject
+	private EndpointService endpointService;
 
 	@BudgetLimited
 	@Override
@@ -103,9 +106,12 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 			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(EXPLORATORY_CREATE, userInfo.getAccessToken(),
-					requestBuilder.newExploratoryCreate(exploratory, userInfo, gitCreds, userInstanceDTO.getTags()),
-					String.class);
+			final String uuid =
+					provisioningService.post(endpointService.get(userInstanceDTO.getEndpoint()).getUrl() + EXPLORATORY_CREATE,
+							userInfo.getAccessToken(),
+							requestBuilder.newExploratoryCreate(exploratory, userInfo, gitCreds,
+									userInstanceDTO.getTags()),
+							String.class);
 			requestId.put(userInfo.getName(), uuid);
 			return uuid;
 		} catch (Exception t) {
@@ -169,7 +175,7 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 				exploratoryName);
 		final ExploratoryReconfigureSparkClusterActionDTO updateClusterConfigDTO =
 				requestBuilder.newClusterConfigUpdate(userInfo, userInstanceDTO, config);
-		final String uuid = provisioningService.post(EXPLORATORY_RECONFIGURE_SPARK, token, updateClusterConfigDTO,
+		final String uuid = provisioningService.post(endpointService.get(userInstanceDTO.getEndpoint()).getUrl() + EXPLORATORY_RECONFIGURE_SPARK, token, updateClusterConfigDTO,
 				String.class);
 		requestId.put(userName, uuid);
 		exploratoryDAO.updateExploratoryFields(new ExploratoryStatusDTO()
@@ -234,7 +240,8 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 			updateExploratoryStatus(exploratoryName, status, userInfo.getName());
 
 			UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), exploratoryName);
-			final String uuid = provisioningService.post(action, userInfo.getAccessToken(),
+			final String uuid = provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + action,
+					userInfo.getAccessToken(),
 					getExploratoryActionDto(userInfo, status, userInstance), String.class);
 			requestId.put(userInfo.getName(), uuid);
 			return uuid;
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
index f6f4cce..4931276 100644
--- 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
@@ -23,6 +23,7 @@ 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.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;
@@ -57,6 +58,8 @@ public class GitCredentialServiceImpl implements GitCredentialService {
 	private RequestBuilder requestBuilder;
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private EndpointService endpointService;
 
 	@Override
 	public void updateGitCredentials(UserInfo userInfo, ExploratoryGitCredsDTO formDTO) {
@@ -97,7 +100,8 @@ public class GitCredentialServiceImpl implements GitCredentialService {
 					userInfo.getName(), instance.getExploratoryName());
 			ExploratoryGitCredsUpdateDTO dto = requestBuilder.newGitCredentialsUpdate(userInfo, instance, formDTO);
 			final String uuid = provisioningService
-					.post(EXPLORATORY_GIT_CREDS, userInfo.getAccessToken(), dto, String.class);
+					.post(endpointService.get(instance.getEndpoint()).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(),
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
index 62721ec..2344432 100644
--- 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
@@ -2,6 +2,7 @@ package com.epam.dlab.backendapi.service.impl;
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.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;
@@ -28,18 +29,22 @@ public class GuacamoleServiceImpl implements GuacamoleService {
 	private static final String CONNECTION_PROTOCOL_PARAM = "connectionProtocol";
 	private final SelfServiceApplicationConfiguration conf;
 	private final RESTService provisioningService;
+	private final EndpointService endpointService;
 
 	@Inject
 	public GuacamoleServiceImpl(SelfServiceApplicationConfiguration conf,
-								@Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService) {
+								@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) {
+	public GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint) {
 		try {
-			String key = provisioningService.get(KeyAPI.GET_ADMIN_KEY, userInfo.getAccessToken(), String.class);
+			String key = provisioningService.get(endpointService.get(endpoint).getUrl() + KeyAPI.GET_ADMIN_KEY,
+					userInfo.getAccessToken(), String.class);
 			InetGuacamoleSocket socket = new InetGuacamoleSocket(conf.getGuacamoleHost(), conf.getGuacamolePort());
 			GuacamoleConfiguration guacamoleConfig = getGuacamoleConfig(key, conf.getGuacamole(), host);
 			return new SimpleGuacamoleTunnel(new ConfiguredGuacamoleSocket(socket, guacamoleConfig));
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
index 8c111e2..c92c179 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
@@ -25,6 +25,7 @@ import com.epam.dlab.backendapi.dao.BillingDAO;
 import com.epam.dlab.backendapi.dao.EnvDAO;
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.KeyDAO;
+import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
 import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
 import com.epam.dlab.backendapi.resources.dto.ProjectInfrastructureInfo;
 import com.epam.dlab.backendapi.service.InfrastructureInfoService;
@@ -77,10 +78,16 @@ public abstract class InfrastructureInfoServiceBase<T> implements Infrastructure
 					.collect(Collectors.groupingBy(d -> d.getString("project")))
 					.entrySet()
 					.stream()
-					.map(e -> new ProjectInfrastructureInfo(e.getKey(),
-							billingDAO.getBillingProjectQuoteUsed(e.getKey()),
-							getSharedInfo(projectService.get(e.getKey()).getEdgeInfo()),
-							e.getValue()))
+					.map(e -> {
+
+						final Map<String, Map<String, String>> projectEdges =
+								projectService.get(e.getKey()).getEndpoints().stream()
+										.collect(Collectors.toMap(ProjectEndpointDTO::getName,
+												endpointDTO -> getSharedInfo(endpointDTO.getEdgeInfo())));
+						return new ProjectInfrastructureInfo(e.getKey(),
+								billingDAO.getBillingProjectQuoteUsed(e.getKey()),
+								projectEdges, e.getValue());
+					})
 					.collect(Collectors.toList());
 		} catch (Exception e) {
 			log.error("Could not load list of provisioned resources for user: {}", user, e);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
index e597d94..0d7f1f2 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
@@ -27,6 +27,7 @@ import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.resources.dto.SparkStandaloneConfiguration;
 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;
@@ -61,6 +62,8 @@ public abstract class InfrastructureTemplateServiceBase implements Infrastructur
 	private SettingsDAO settingsDAO;
 	@Inject
 	private ProjectDAO projectDAO;
+	@Inject
+	private EndpointService endpointService;
 
 
 	@Inject
@@ -68,12 +71,14 @@ public abstract class InfrastructureTemplateServiceBase implements Infrastructur
 	private RESTService provisioningService;
 
 	@Override
-	public List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project) {
+	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 {
 			ExploratoryMetadataDTO[] array =
-					provisioningService.get(DOCKER_EXPLORATORY, user.getAccessToken(), ExploratoryMetadataDTO[].class);
+					provisioningService.get(endpointService.get(endpoint).getUrl() + DOCKER_EXPLORATORY,
+							user.getAccessToken(),
+							ExploratoryMetadataDTO[].class);
 
 			final Set<String> roles = getRoles(user, project);
 			return Arrays.stream(array)
@@ -105,13 +110,14 @@ public abstract class InfrastructureTemplateServiceBase implements Infrastructur
 	}
 
 	@Override
-	public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project) {
+	public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint) {
 
 		log.debug("Loading list of computational templates for user {}", user.getName());
 		try {
 			ComputationalMetadataDTO[] array =
-					provisioningService.get(DOCKER_COMPUTATIONAL, user.getAccessToken(), ComputationalMetadataDTO[]
-							.class);
+					provisioningService.get(endpointService.get(endpoint).getUrl() + DOCKER_COMPUTATIONAL,
+							user.getAccessToken(), ComputationalMetadataDTO[]
+									.class);
 
 			final Set<String> roles = getRoles(user, project);
 
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
index 4258172..afadbf6 100644
--- 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
@@ -27,6 +27,7 @@ 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;
@@ -72,6 +73,8 @@ public class LibraryServiceImpl implements LibraryService {
 
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private EndpointService endpointService;
 
 
 	@Override
@@ -124,9 +127,11 @@ public class LibraryServiceImpl implements LibraryService {
 										   List<LibInstallDTO> libs) {
 
 		final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(ui.getName(), expName, compName);
-		final String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_LIB_INSTALL,
-				ui.getAccessToken(), toComputationalLibraryInstallDto(ui, expName, compName, libs, userInstance),
-				String.class);
+		final String uuid =
+				provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_INSTALL,
+						ui.getAccessToken(), toComputationalLibraryInstallDto(ui, expName, compName, libs,
+								userInstance),
+						String.class);
 		requestId.put(ui.getName(), uuid);
 		return uuid;
 	}
@@ -134,7 +139,8 @@ public class LibraryServiceImpl implements LibraryService {
 	@Override
 	public String installExploratoryLibs(UserInfo ui, String expName, List<LibInstallDTO> libs) {
 		final UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(ui.getName(), expName);
-		final String uuid = provisioningService.post(ExploratoryAPI.EXPLORATORY_LIB_INSTALL, ui.getAccessToken(),
+		final String uuid =
+				provisioningService.post(endpointService.get(userInstance.getEndpoint()).getUrl() + ExploratoryAPI.EXPLORATORY_LIB_INSTALL, ui.getAccessToken(),
 				toExploratoryLibraryInstallDto(ui, expName, libs, userInstance), String.class);
 		requestId.put(ui.getName(), uuid);
 		return uuid;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
index 69aeef8..ac6c63d 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
@@ -8,6 +8,7 @@ import com.epam.dlab.backendapi.dao.UserGroupDao;
 import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.domain.RequestId;
 import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+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;
@@ -20,7 +21,6 @@ import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import lombok.extern.slf4j.Slf4j;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Supplier;
@@ -42,18 +42,20 @@ public class ProjectServiceImpl implements ProjectService {
 	private final RESTService provisioningService;
 	private final RequestId requestId;
 	private final RequestBuilder requestBuilder;
+	private final EndpointService endpointService;
 
 	@Inject
 	public ProjectServiceImpl(ProjectDAO projectDAO, ExploratoryService exploratoryService,
 							  UserGroupDao userGroupDao,
 							  @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
-							  RequestId requestId, RequestBuilder requestBuilder) {
+							  RequestId requestId, RequestBuilder requestBuilder, EndpointService endpointService) {
 		this.projectDAO = projectDAO;
 		this.exploratoryService = exploratoryService;
 		this.userGroupDao = userGroupDao;
 		this.provisioningService = provisioningService;
 		this.requestId = requestId;
 		this.requestBuilder = requestBuilder;
+		this.endpointService = endpointService;
 	}
 
 	@Override
@@ -64,7 +66,7 @@ public class ProjectServiceImpl implements ProjectService {
 	@Override
 	public List<ProjectDTO> getUserProjects(UserInfo userInfo) {
 		userInfo.getRoles().add(ANY_USER_ROLE);
-		return projectDAO.getUserProjectsWithStatus(userInfo, ProjectDTO.Status.ACTIVE);
+		return projectDAO.getUserProjects(userInfo);
 	}
 
 	@Override
@@ -91,27 +93,25 @@ public class ProjectServiceImpl implements ProjectService {
 
 	@Override
 	public void terminate(UserInfo userInfo, String name) {
-		projectActionOnCloud(userInfo, name, TERMINATE_PRJ_API, getEndpoint(name));
+		get(name).getEndpoints().forEach(endpoint -> projectActionOnCloud(userInfo, name, TERMINATE_PRJ_API,
+				endpoint.getName()));
+
 		exploratoryService.updateProjectExploratoryStatuses(name, UserInstanceStatus.TERMINATING);
 		projectDAO.updateStatus(name, ProjectDTO.Status.DELETING);
+
 	}
 
 	@BudgetLimited
 	@Override
-	public void start(UserInfo userInfo, @Project String name) {
-		getEndpoint(name);
-		projectActionOnCloud(userInfo, name, START_PRJ_API, getEndpoint(name));
+	public void start(UserInfo userInfo, String endpoint, @Project String name) {
+		projectActionOnCloud(userInfo, name, START_PRJ_API, endpoint);
 		projectDAO.updateStatus(name, ProjectDTO.Status.ACTIVATING);
 	}
 
-	private String getEndpoint(String project) {
-		return projectDAO.get(project).map(ProjectDTO::getEndpoints).orElse(Collections.singleton("")).iterator().next(); //TODO change hardcoded value
-	}
-
 	@Override
-	public void stop(UserInfo userInfo, String name) {
-		projectActionOnCloud(userInfo, name, STOP_PRJ_API, getEndpoint(name));
-		projectDAO.updateStatus(name, ProjectDTO.Status.DEACTIVATING);
+	public void stop(UserInfo userInfo, String endpoint, String name) {
+		projectActionOnCloud(userInfo, name, STOP_PRJ_API, endpoint);
+		projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.STOPPING);
 	}
 
 	@Override
@@ -141,9 +141,13 @@ public class ProjectServiceImpl implements ProjectService {
 
 	private void createProjectOnCloud(UserInfo user, ProjectDTO projectDTO) {
 		try {
-			String uuid = provisioningService.post(CREATE_PRJ_API, user.getAccessToken(),
-					requestBuilder.newProjectCreate(user, projectDTO), String.class);
-			requestId.put(user.getName(), uuid);
+			projectDTO.getEndpoints().forEach(endpoint -> {
+				String uuid =
+						provisioningService.post(endpointService.get(endpoint.getName()).getUrl() + CREATE_PRJ_API,
+								user.getAccessToken(),
+								requestBuilder.newProjectCreate(user, projectDTO, endpoint.getName()), String.class);
+				requestId.put(user.getName(), uuid);
+			});
 		} catch (Exception e) {
 			log.error("Can not create project due to: {}", e.getMessage());
 			projectDAO.updateStatus(projectDTO.getName(), ProjectDTO.Status.FAILED);
@@ -153,7 +157,8 @@ public class ProjectServiceImpl implements ProjectService {
 
 	private void projectActionOnCloud(UserInfo user, String projectName, String provisioningApiUri, String endpoint) {
 		try {
-			String uuid = provisioningService.post(provisioningApiUri, user.getAccessToken(),
+			String uuid = provisioningService.post(endpointService.get(endpoint).getUrl() + provisioningApiUri,
+					user.getAccessToken(),
 					requestBuilder.newProjectAction(user, projectName, endpoint), String.class);
 			requestId.put(user.getName(), uuid);
 		} catch (Exception e) {
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
index d0025ba..0c9135e 100644
--- 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
@@ -3,7 +3,9 @@ package com.epam.dlab.backendapi.servlet.guacamole;
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.service.GuacamoleService;
 import com.epam.dlab.exceptions.DlabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.inject.Inject;
+import lombok.Data;
 import org.apache.guacamole.net.GuacamoleTunnel;
 import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
 
@@ -13,9 +15,11 @@ import java.io.IOException;
 public class GuacamoleServlet extends GuacamoleHTTPTunnelServlet {
 	static final String USER_ATTRIBUTE = "user";
 	private final GuacamoleService guacamoleService;
+	private final ObjectMapper mapper;
 
 	@Inject
-	public GuacamoleServlet(GuacamoleService guacamoleService) {
+	public GuacamoleServlet(GuacamoleService guacamoleService, ObjectMapper mapper) {
+		this.mapper = mapper;
 		this.guacamoleService = guacamoleService;
 	}
 
@@ -23,10 +27,16 @@ public class GuacamoleServlet extends GuacamoleHTTPTunnelServlet {
 	protected GuacamoleTunnel doConnect(HttpServletRequest request) {
 		try {
 			final UserInfo userInfo = (UserInfo) request.getAttribute(USER_ATTRIBUTE);
-			final String host = request.getReader().readLine();
-			return guacamoleService.getTunnel(userInfo, host);
+			final CreateTerminalDTO createTerminalDTO = mapper.readValue(request.getReader(), CreateTerminalDTO.class);
+			return guacamoleService.getTunnel(userInfo, createTerminalDTO.getHost(), createTerminalDTO.getEndpoint());
 		} catch (IOException e) {
 			throw new DlabException("Can not read request body: " + e.getMessage(), e);
 		}
 	}
+
+	@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/RequestBuilder.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
index b7f6072..4e3f8ee 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
@@ -631,12 +631,12 @@ public class RequestBuilder {
 		return dto;
 	}
 
-	public ProjectCreateDTO newProjectCreate(UserInfo userInfo, ProjectDTO projectDTO) {
+	public ProjectCreateDTO newProjectCreate(UserInfo userInfo, ProjectDTO projectDTO, String endpoint) {
 		return ProjectCreateDTO.builder()
 				.key(projectDTO.getKey())
 				.name(projectDTO.getName())
 				.tag(projectDTO.getTag())
-				.endpoint(projectDTO.getEndpoints().iterator().next()) //TODO figure out how to deal with endpoints
+				.endpoint(endpoint)
 				.build()
 				.withCloudSettings(cloudSettings(userInfo));
 	}
diff --git a/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts b/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
index a608deb..ef0fba7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
@@ -77,7 +77,7 @@ const routes: Routes = [{
     }
   ]
 }, {
-  path: 'terminal/:id',
+  path: 'terminal/:id/:endpoint',
   component: WebterminalComponent
 }, {
   path: '403',
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
index b7aa70b..0ac58b5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
@@ -28,8 +28,8 @@ import { ApplicationServiceFacade } from './applicationServiceFacade.service';
 export class UserResourceService {
   constructor(private applicationServiceFacade: ApplicationServiceFacade) { }
 
-  public getExploratoryTemplates(project): Observable<any> {
-    const url = `/${project}/exploratory_templates`;
+  public getExploratoryTemplates(project, endpoint): Observable<any> {
+    const url = `/${project}/${endpoint}/exploratory_templates`;
     return this.applicationServiceFacade
       .buildGetTemplatesRequest(url)
       .pipe(
@@ -37,8 +37,8 @@ export class UserResourceService {
         catchError(ErrorUtils.handleServiceError));
   }
 
-  public getComputationalTemplates(project): Observable<any> {
-    const url = `/${project}/computational_templates`;
+  public getComputationalTemplates(project, endpoint): Observable<any> {
+    const url = `/${project}/${endpoint}/computational_templates`;
     return this.applicationServiceFacade
       .buildGetTemplatesRequest(url)
       .pipe(
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
index 767d7ec..52e2670 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
@@ -21,7 +21,7 @@ export const PATTERNS = {
   namePattern: '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+',
   projectName: '[a-zA-Z0-9]+',
   delimitersRegex: '[-_]?',
-  url: '[a-zA-Z0-9.://%#&\\.@:%-_\+~#=]*\.[^\s]*[a-zA-Z0-9]+',
+  url: '[a-zA-Z0-9.://%#&\\.@:%-_\+~#=]*\.[^\s]*[a-zA-Z0-9]/+',
   nodeCountPattern: '^[1-9]\\d*$',
   integerRegex: '^[0-9]*$'
 }
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 852d0a6..078e65e 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
@@ -77,7 +77,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     this.resourcesList = this.data.full_list;
     this.initFormModel();
 
-    this.getTemplates(this.notebook_instance.project);
+    this.getTemplates(this.notebook_instance.project, this.notebook_instance.endpoint);
   }
 
   public selectImage($event) {
@@ -237,8 +237,8 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       return control.value.length <= 10 ? null : { valid: false };
   }
 
-  private getTemplates(project) {
-    this.userResourceService.getComputationalTemplates(project).subscribe(
+  private getTemplates(project, endpoint) {
+    this.userResourceService.getComputationalTemplates(project, endpoint).subscribe(
       clusterTypes => {
         this.clusterTypes = clusterTypes;
         this.selectedImage = clusterTypes[0];
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 41c8434..984679f 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
@@ -31,7 +31,7 @@
             <mat-form-field>
               <mat-label>Select project</mat-label>
               <mat-select formControlName="project" disableOptionCentering>
-                <mat-option *ngFor="let project of projects" [value]="project.name" (click)="getTemplates(project)">
+                <mat-option *ngFor="let project of projects" [value]="project.name" (click)="setEndpoints(project)">
                   {{ project.name }}</mat-option>
                 <mat-option *ngIf="!projects.length" class="multiple-select ml-10" disabled>Projects list is empty
                 </mat-option>
@@ -49,7 +49,7 @@
             <mat-form-field>
               <mat-label>Select endpoint</mat-label>
               <mat-select formControlName="endpoint" disableOptionCentering [disabled]="!endpoints.length">
-                <mat-option *ngFor="let endpoint of endpoints" [value]="endpoint">{{ endpoint }}</mat-option>
+                <mat-option *ngFor="let endpoint of endpoints" [value]="endpoint" (click)="getTemplates(createExploratoryForm?.controls['project'].value, endpoint)">{{ endpoint }}</mat-option>
                 <mat-option *ngIf="!endpoints.length" class="multiple-select ml-10" disabled>Endpoints list is empty
                 </mat-option>
               </mat-select>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
index dd8a7f3..4718bc1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
@@ -72,9 +72,14 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
     this.projectService.getUserProjectsList().subscribe((projects: any) => this.projects = projects);
   }
 
-  public getTemplates(project) {
-    this.endpoints = project.endpoints;
-    this.userResourceService.getExploratoryTemplates(project.name).subscribe(templates => this.templates = templates);
+  public setEndpoints(project) {
+    this.endpoints = project.endpoints
+    .filter(e => e.status === 'RUNNING')
+    .map(e => e.name);
+  }
+
+  public getTemplates(project, endpoint) {
+    this.userResourceService.getExploratoryTemplates(project, endpoint).subscribe(templates => this.templates = templates);
   }
 
   public getShapes(template) {
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 3771bb8..2758534 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
@@ -194,7 +194,7 @@
                   <span>Manage libraries</span>
                 </li>
                 <li *ngIf="element.status === 'running'">
-                  <a target="_blank" [attr.href]="'/#/terminal/' + element.private_ip" class="navigate">
+                  <a target="_blank" [attr.href]="'/#/terminal/' + element.private_ip + '/' + element.endpoint" class="navigate">
                     <i class="material-icons">laptop</i>
                     <span>Open terminal</span>
                   </a>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
index 72317c0..d9e4089 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
@@ -64,22 +64,22 @@ export class ExploratoryModel {
             el.computational_resources,
             el.up_time,
             el.exploratory_url,
-            value.shared.edge_node_ip,
+            value.shared[el.endpoint].edge_node_ip,
             el.private_ip,
             el.exploratory_user,
             el.exploratory_pass,
-            value.shared[DICTIONARY.bucket_name],
-            value.shared[DICTIONARY.shared_bucket_name],
+            value.shared[el.endpoint][DICTIONARY.bucket_name],
+            value.shared[el.endpoint][DICTIONARY.shared_bucket_name],
             el.error_message,
             el[DICTIONARY.billing.cost],
             el[DICTIONARY.billing.currencyCode],
             el.billing,
             el.libs,
-            value.shared[DICTIONARY.user_storage_account_name],
-            value.shared[DICTIONARY.shared_storage_account_name],
-            value.shared[DICTIONARY.datalake_name],
-            value.shared[DICTIONARY.datalake_user_directory_name],
-            value.shared[DICTIONARY.datalake_shared_directory_name],
+            value.shared[el.endpoint][DICTIONARY.user_storage_account_name],
+            value.shared[el.endpoint][DICTIONARY.shared_storage_account_name],
+            value.shared[el.endpoint][DICTIONARY.datalake_name],
+            value.shared[el.endpoint][DICTIONARY.datalake_user_directory_name],
+            value.shared[el.endpoint][DICTIONARY.datalake_shared_directory_name],
             el.project,
             el.endpoint,
             el.tags
@@ -93,4 +93,4 @@ export class ExploratoryModel {
 export interface Exploratory {
   project: string;
   exploratory: ExploratoryModel[]
-}
\ No newline at end of file
+}
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 e11964f..b6429d0 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,6 +31,7 @@ import { StorageService } from '../core/services';
 })
 export class WebterminalComponent implements OnInit {
   public id: string;
+  public endpoint: string;
   @ViewChild('terminal', { read: ViewContainerRef }) terminal: ViewContainerRef;
 
   constructor(
@@ -41,11 +42,12 @@ export class WebterminalComponent implements OnInit {
 
   ngOnInit() {
     this.id = this.route.snapshot.paramMap.get('id');
+    this.endpoint = this.route.snapshot.paramMap.get('endpoint');
     console.log(this.id);
-    this.open(this.id);
+    this.open(this.id, this.endpoint);
   }
 
-  public open(id_parameter: string) {
+  public open(id_parameter: string, endpoint_parameter: string) {
     const tunnel = new Guacamole.HTTPTunnel(
       `${window.location.origin}/api/tunnel`, false,
       { 'Authorization': `Bearer ${this.storageService.getToken()}` }
@@ -57,7 +59,7 @@ export class WebterminalComponent implements OnInit {
     display.appendChild(guac.getDisplay().getElement());
     const guacDisplay = guac.getDisplay();
     const layer = guacDisplay.getDefaultLayer();
-    guac.connect(id_parameter);
+    guac.connect("{\"host\" : \""+ id_parameter + "\", \"endpoint\" : \"" + endpoint_parameter + "\"}");
 
     // Error handler
     guac.onerror = (error) => console.log(error.message);
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
index f4f57db..eeb6e06 100644
--- 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
@@ -60,10 +60,10 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 	public void getComputationalTemplates() {
 		FullComputationalTemplate fullComputationalTemplate =
 				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString()))
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
 				.thenReturn(Collections.singletonList(fullComputationalTemplate));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/computational_templates")
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -71,7 +71,7 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		assertEquals(HttpStatus.SC_OK, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -80,10 +80,10 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		authFailSetup();
 		FullComputationalTemplate fullComputationalTemplate =
 				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString()))
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
 				.thenReturn(Collections.singletonList(fullComputationalTemplate));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/computational_templates")
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -91,16 +91,16 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		assertEquals(HttpStatus.SC_OK, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
+		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());
+				.when(infrastructureTemplateService).getComputationalTemplates(any(UserInfo.class), anyString(), anyString());
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/computational_templates")
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -108,7 +108,7 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -116,10 +116,10 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 	public void getExploratoryTemplates() {
 		ExploratoryMetadataDTO exploratoryMetadataDTO =
 				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString()))
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
 				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/exploratory_templates")
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -130,7 +130,7 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 				}));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -139,10 +139,10 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		authFailSetup();
 		ExploratoryMetadataDTO exploratoryMetadataDTO =
 				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString()))
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
 				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/exploratory_templates")
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -153,7 +153,7 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 				}));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -161,9 +161,9 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 	@Test
 	public void getExploratoryTemplatesWithException() {
 		doThrow(new DlabException("Could not load list of exploratory templates for user"))
-				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class), anyString());
+				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class), anyString(), anyString());
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/exploratory_templates")
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -171,7 +171,7 @@ public class InfrastructureTemplateResourceTest extends TestBase {
 		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 }
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
index 834f2f1..907da6b 100644
--- 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
@@ -76,14 +76,14 @@ public class InfrastructureTemplateServiceBaseTest {
 						"someRam2", 6)));
 		emDto2.setExploratoryEnvironmentShapes(shapes2);
 		List<ExploratoryMetadataDTO> expectedEmdDtoList = Arrays.asList(emDto1, emDto2);
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
-				Collections.singleton("project"), null, null, null)));
+		/*when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null, null)));*/
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedEmdDtoList.toArray());
 		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		List<ExploratoryMetadataDTO> actualEmdDtoList =
-				infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project");
+				infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
 		assertNotNull(actualEmdDtoList);
 		assertEquals(expectedEmdDtoList, actualEmdDtoList);
 
@@ -99,7 +99,7 @@ public class InfrastructureTemplateServiceBaseTest {
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project");
+			infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
 		} catch (DlabException e) {
 			assertEquals("Could not load list of exploratory templates for user", e.getMessage());
 		}
@@ -115,8 +115,8 @@ public class InfrastructureTemplateServiceBaseTest {
 		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(
 				computationalMetadataDTO
 		);
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
-				Collections.singleton("project"), null, null, null)));
+		/*when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null, null)));*/
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
 
 		List<FullComputationalTemplate> expectedFullCmdDtoList = expectedCmdDtoList.stream()
@@ -125,7 +125,7 @@ public class InfrastructureTemplateServiceBaseTest {
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		List<FullComputationalTemplate> actualFullCmdDtoList =
-				infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
+				infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
 		assertNotNull(actualFullCmdDtoList);
 		assertEquals(expectedFullCmdDtoList.size(), actualFullCmdDtoList.size());
 		for (int i = 0; i < expectedFullCmdDtoList.size(); i++) {
@@ -143,7 +143,7 @@ public class InfrastructureTemplateServiceBaseTest {
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
+			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
 		} catch (DlabException e) {
 			assertEquals("Could not load list of computational templates for user", e.getMessage());
 		}
@@ -157,12 +157,12 @@ public class InfrastructureTemplateServiceBaseTest {
 		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
 		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(computationalMetadataDTO);
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
-				Collections.singleton("project"), null, null,null)));
+		/*when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null,null)));*/
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
+			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
 		} catch (IllegalArgumentException e) {
 			assertEquals("Unknown data engine null", e.getMessage());
 		}


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