From 6b7b1c646882bbbb64c51fc767a4c65a8e976249 Mon Sep 17 00:00:00 2001 From: Oleksandr Garagatyi Date: Thu, 7 Dec 2017 17:14:58 +0200 Subject: [PATCH] CHE-7561: add internal server concept into workspace API Signed-off-by: Oleksandr Garagatyi --- .../model/workspace/config/ServerConfig.java | 8 + .../WorkspacePermissionsFilterTest.java | 6 +- .../workspace/server/WorkspaceService.java | 41 ++- .../server/WorkspaceServiceTest.java | 261 ++++++++++++++++++ 4 files changed, 311 insertions(+), 5 deletions(-) diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java index c74688c705..d44c2494f3 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java @@ -11,6 +11,7 @@ package org.eclipse.che.api.core.model.workspace.config; import java.util.Map; +import org.eclipse.che.api.core.model.workspace.runtime.Server; import org.eclipse.che.commons.annotation.Nullable; /** @@ -20,6 +21,13 @@ import org.eclipse.che.commons.annotation.Nullable; */ public interface ServerConfig { + /** + * {@link ServerConfig} and {@link Server} attribute name which can identify server as internal or + * external. Attribute value {@code true} makes a server internal, any other value or lack of the + * attribute makes the server external. + */ + String INTERNAL_SERVER_ATTRIBUTE = "internal"; + /** * Port used by server. * diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspacePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspacePermissionsFilterTest.java index 5a29bd00d5..cc3ef3603c 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspacePermissionsFilterTest.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/filters/WorkspacePermissionsFilterTest.java @@ -306,7 +306,7 @@ public class WorkspacePermissionsFilterTest { assertEquals(response.getStatusCode(), 204); verify(superPrivilegesChecker).hasSuperPrivileges(); - verify(workspaceService).getByKey(eq("workspace123")); + verify(workspaceService).getByKey(eq("workspace123"), eq("false")); verify(subject).hasPermission(eq("workspace"), eq("workspace123"), eq("read")); } @@ -327,7 +327,7 @@ public class WorkspacePermissionsFilterTest { assertEquals(response.getStatusCode(), 204); verify(superPrivilegesChecker).hasSuperPrivileges(); - verify(workspaceService).getByKey(eq("workspace123")); + verify(workspaceService).getByKey(eq("workspace123"), eq("false")); verify(subject, never()).hasPermission(eq("workspace"), eq("workspace123"), eq("read")); } @@ -351,7 +351,7 @@ public class WorkspacePermissionsFilterTest { .get(SECURE_PATH + "/workspace/{key}"); assertEquals(response.getStatusCode(), 204); - verify(workspaceService).getByKey(eq("userok:myWorkspace")); + verify(workspaceService).getByKey(eq("userok:myWorkspace"), eq("false")); verify(subject).hasPermission(eq("workspace"), eq("workspace123"), eq("read")); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index a6e4ec7538..23a4dce45c 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -10,6 +10,7 @@ */ package org.eclipse.che.api.workspace.server; +import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toList; @@ -47,6 +48,7 @@ import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.core.rest.Service; import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; @@ -56,9 +58,11 @@ import org.eclipse.che.api.workspace.server.token.MachineTokenException; import org.eclipse.che.api.workspace.server.token.MachineTokenProvider; import org.eclipse.che.api.workspace.shared.dto.CommandDto; import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; +import org.eclipse.che.api.workspace.shared.dto.MachineDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.RecipeDto; import org.eclipse.che.api.workspace.shared.dto.RuntimeDto; +import org.eclipse.che.api.workspace.shared.dto.ServerDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; import org.eclipse.che.commons.env.EnvironmentContext; @@ -184,10 +188,17 @@ public class WorkspaceService extends Service { }) ) @PathParam("key") - String key) + String key, + @ApiParam("Whether to include internal servers into runtime or not") + @DefaultValue("false") + @QueryParam("includeInternalServers") + String includeInternalServers) throws NotFoundException, ServerException, ForbiddenException, BadRequestException { validateKey(key); - return asDtoWithLinksAndToken(workspaceManager.getWorkspace(key)); + boolean bIncludeInternalServers = + isNullOrEmpty(includeInternalServers) || Boolean.parseBoolean(includeInternalServers); + return filterServers( + asDtoWithLinksAndToken(workspaceManager.getWorkspace(key)), bIncludeInternalServers); } @GET @@ -797,4 +808,30 @@ public class WorkspaceService extends Service { return workspaceDto; } + + private WorkspaceDto filterServers(WorkspaceDto workspace, boolean includeInternal) { + // no runtime - nothing to filter + if (workspace.getRuntime() == null) { + return workspace; + } + // if it is needed to include internal there is nothing to filter + if (includeInternal) { + return workspace; + } + for (MachineDto machine : workspace.getRuntime().getMachines().values()) { + Map filteredServers = new HashMap<>(); + machine + .getServers() + .forEach( + (name, server) -> { + if (!"true" + .equals(server.getAttributes().get(ServerConfig.INTERNAL_SERVER_ATTRIBUTE))) { + filteredServers.put(name, server); + } + }); + machine.withServers(filteredServers); + } + + return workspace; + } } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java index 38285333d0..d5d6442c99 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; @@ -45,19 +46,28 @@ import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.config.ProjectConfig; +import org.eclipse.che.api.core.model.workspace.config.ServerConfig; +import org.eclipse.che.api.core.model.workspace.runtime.Machine; +import org.eclipse.che.api.core.model.workspace.runtime.Server; +import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus; import org.eclipse.che.api.core.rest.ApiExceptionMapper; import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.MachineImpl; import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl; import org.eclipse.che.api.workspace.server.model.impl.RuntimeImpl; +import org.eclipse.che.api.workspace.server.model.impl.ServerImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.token.MachineTokenProvider; import org.eclipse.che.api.workspace.shared.dto.CommandDto; import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; +import org.eclipse.che.api.workspace.shared.dto.MachineDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; +import org.eclipse.che.api.workspace.shared.dto.RuntimeDto; +import org.eclipse.che.api.workspace.shared.dto.ServerDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; @@ -308,6 +318,241 @@ public class WorkspaceServiceTest { return new Object[][] {{"workspaceId"}, {"namespace:name"}, {":name"}}; } + @Test + public void shouldGetWorkspaceWithExternalServersByDefault() throws Exception { + // given + WorkspaceImpl workspace = createWorkspace(createConfigDto()); + String externalServerKey = "server2"; + ServerImpl externalServer = createExternalServer(); + Map servers = + ImmutableMap.of("server1", createInternalServer(), externalServerKey, externalServer); + Map machines = + singletonMap("machine1", new MachineImpl(singletonMap("key", "value"), servers)); + workspace.setRuntime(new RuntimeImpl("activeEnv", machines, "user123")); + when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace); + Map expected = + singletonMap( + "machine1", + newDto(MachineDto.class) + .withAttributes(singletonMap("key", "value")) + .withServers( + singletonMap( + externalServerKey, + newDto(ServerDto.class) + .withUrl(externalServer.getUrl()) + .withStatus(externalServer.getStatus()) + .withAttributes(externalServer.getAttributes())))); + + // when + Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .when() + .get(SECURE_PATH + "/workspace/" + workspace.getId()); + + // then + assertEquals(response.getStatusCode(), 200); + RuntimeDto retrievedRuntime = unwrapDto(response, WorkspaceDto.class).getRuntime(); + assertNotNull(retrievedRuntime); + assertEquals(expected, retrievedRuntime.getMachines()); + } + + @Test + public void shouldTreatServerWithInternalServerAttributeNotEqualToTrueExternal() + throws Exception { + // given + WorkspaceImpl workspace = createWorkspace(createConfigDto()); + String externalServerKey = "server2"; + ServerImpl externalServer = + createInternalServer() + .withAttributes(singletonMap(ServerConfig.INTERNAL_SERVER_ATTRIBUTE, "")); + Map servers = + ImmutableMap.of("server1", createInternalServer(), externalServerKey, externalServer); + Map machines = + singletonMap("machine1", new MachineImpl(singletonMap("key", "value"), servers)); + workspace.setRuntime(new RuntimeImpl("activeEnv", machines, "user123")); + when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace); + Map expected = + singletonMap( + "machine1", + newDto(MachineDto.class) + .withAttributes(singletonMap("key", "value")) + .withServers( + singletonMap( + externalServerKey, + newDto(ServerDto.class) + .withUrl(externalServer.getUrl()) + .withStatus(externalServer.getStatus()) + .withAttributes(externalServer.getAttributes())))); + + // when + Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .when() + .get(SECURE_PATH + "/workspace/" + workspace.getId()); + + // then + assertEquals(response.getStatusCode(), 200); + RuntimeDto retrievedRuntime = unwrapDto(response, WorkspaceDto.class).getRuntime(); + assertNotNull(retrievedRuntime); + assertEquals(expected, retrievedRuntime.getMachines()); + } + + @Test + public void shouldGetWorkspaceWithInternalServers() throws Exception { + // given + WorkspaceImpl workspace = createWorkspace(createConfigDto()); + String externalServerKey = "server2"; + String internalServerKey = "server1"; + ServerImpl externalServer = createExternalServer(); + ServerImpl internalServer = createInternalServer(); + Map servers = + ImmutableMap.of( + internalServerKey, createInternalServer(), externalServerKey, externalServer); + Map machines = + singletonMap("machine1", new MachineImpl(singletonMap("key", "value"), servers)); + workspace.setRuntime(new RuntimeImpl("activeEnv", machines, "user123")); + when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace); + + Map expected = + singletonMap( + "machine1", + newDto(MachineDto.class) + .withAttributes(singletonMap("key", "value")) + .withServers( + ImmutableMap.of( + externalServerKey, + newDto(ServerDto.class) + .withUrl(externalServer.getUrl()) + .withStatus(externalServer.getStatus()) + .withAttributes(externalServer.getAttributes()), + internalServerKey, + newDto(ServerDto.class) + .withUrl(createInternalServer().getUrl()) + .withStatus(internalServer.getStatus()) + .withAttributes(internalServer.getAttributes())))); + + // when + Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .queryParameter("includeInternalServers", Boolean.TRUE.toString()) + .when() + .get(SECURE_PATH + "/workspace/" + workspace.getId()); + + // then + assertEquals(response.getStatusCode(), 200); + RuntimeDto retrievedRuntime = unwrapDto(response, WorkspaceDto.class).getRuntime(); + assertNotNull(retrievedRuntime); + assertEquals(expected, retrievedRuntime.getMachines()); + } + + @Test + public void shouldGetWorkspaceWithInternalServersIfCorrespondingQueryParamHasEmptyValue() + throws Exception { + // given + WorkspaceImpl workspace = createWorkspace(createConfigDto()); + String externalServerKey = "server2"; + String internalServerKey = "server1"; + ServerImpl externalServer = createExternalServer(); + ServerImpl internalServer = createInternalServer(); + Map servers = + ImmutableMap.of( + internalServerKey, createInternalServer(), externalServerKey, externalServer); + Map machines = + singletonMap("machine1", new MachineImpl(singletonMap("key", "value"), servers)); + workspace.setRuntime(new RuntimeImpl("activeEnv", machines, "user123")); + when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace); + + Map expected = + singletonMap( + "machine1", + newDto(MachineDto.class) + .withAttributes(singletonMap("key", "value")) + .withServers( + ImmutableMap.of( + externalServerKey, + newDto(ServerDto.class) + .withUrl(externalServer.getUrl()) + .withStatus(externalServer.getStatus()) + .withAttributes(externalServer.getAttributes()), + internalServerKey, + newDto(ServerDto.class) + .withUrl(createInternalServer().getUrl()) + .withStatus(internalServer.getStatus()) + .withAttributes(internalServer.getAttributes())))); + + // when + Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .queryParameter("includeInternalServers", "") + .when() + .get(SECURE_PATH + "/workspace/" + workspace.getId()); + + // then + assertEquals(response.getStatusCode(), 200); + RuntimeDto retrievedRuntime = unwrapDto(response, WorkspaceDto.class).getRuntime(); + assertNotNull(retrievedRuntime); + assertEquals(expected, retrievedRuntime.getMachines()); + } + + @Test + public void shouldGetWorkspaceWithInternalServersIfCorrespondingQueryParamHasNoValue() + throws Exception { + // given + WorkspaceImpl workspace = createWorkspace(createConfigDto()); + String externalServerKey = "server2"; + String internalServerKey = "server1"; + ServerImpl externalServer = createExternalServer(); + ServerImpl internalServer = createInternalServer(); + Map servers = + ImmutableMap.of( + internalServerKey, createInternalServer(), externalServerKey, externalServer); + Map machines = + singletonMap("machine1", new MachineImpl(singletonMap("key", "value"), servers)); + workspace.setRuntime(new RuntimeImpl("activeEnv", machines, "user123")); + when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace); + + Map expected = + singletonMap( + "machine1", + newDto(MachineDto.class) + .withAttributes(singletonMap("key", "value")) + .withServers( + ImmutableMap.of( + externalServerKey, + newDto(ServerDto.class) + .withUrl(externalServer.getUrl()) + .withStatus(externalServer.getStatus()) + .withAttributes(externalServer.getAttributes()), + internalServerKey, + newDto(ServerDto.class) + .withUrl(createInternalServer().getUrl()) + .withStatus(internalServer.getStatus()) + .withAttributes(internalServer.getAttributes())))); + + // when + Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .queryParameter("includeInternalServers") + .when() + .get(SECURE_PATH + "/workspace/" + workspace.getId()); + + // then + assertEquals(response.getStatusCode(), 200); + RuntimeDto retrievedRuntime = unwrapDto(response, WorkspaceDto.class).getRuntime(); + assertNotNull(retrievedRuntime); + assertEquals(expected, retrievedRuntime.getMachines()); + } + @Test public void shouldReturnWorkspaceWithTokenIfRuntimeExists() throws Exception { final WorkspaceImpl workspace = createWorkspace(createConfigDto()); @@ -935,6 +1180,22 @@ public class WorkspaceServiceTest { return DtoConverter.asDto(config); } + private ServerImpl createInternalServer() { + return new ServerImpl() + .withStatus(ServerStatus.UNKNOWN) + .withUrl("http://localhost:7070") + .withAttributes( + singletonMap(ServerConfig.INTERNAL_SERVER_ATTRIBUTE, Boolean.TRUE.toString())); + } + + private ServerImpl createExternalServer() { + return new ServerImpl() + .withStatus(ServerStatus.UNKNOWN) + .withUrl("http://localhost:7070") + .withAttributes( + singletonMap(ServerConfig.INTERNAL_SERVER_ATTRIBUTE, Boolean.FALSE.toString())); + } + @Filter public static class EnvironmentFilter implements RequestFilter { @Override