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

[incubator-dlab] branch DLAB-927 created (now aee74dc)

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

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


      at aee74dc  DLAB-927 added support of multiple endpoints

This branch includes the following new commits:

     new aee74dc  DLAB-927 added support of multiple endpoints

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



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


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

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