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 <bohdan_hl...@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-unsubscr...@dlab.apache.org
For additional commands, e-mail: commits-h...@dlab.apache.org

Reply via email to