From af89b1609333f20a590f261360aff5cd13ea931f Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 13 Sep 2021 12:30:54 +0200 Subject: [PATCH 01/18] feat: Added NamespaceProvisioner that creates user information secrets Signed-off-by: xbaran4 --- .../infrastructure/kubernetes/Constants.java | 13 ++ .../server/KubernetesNamespaceService.java | 12 +- .../namespace/NamespaceProvisioner.java | 135 ++++++++++++++++++ 3 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java index 66d0012638..c6401ff32a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java @@ -46,5 +46,18 @@ public final class Constants { public static final String POD_STATUS_PHASE_FAILED = "Failed"; public static final String POD_STATUS_PHASE_SUCCEEDED = "Succeeded"; + /** Names for secrets with user information which are used with DevWorkspaces. */ + public static final String USER_PROFILE_SECRET_NAME = "user-profile"; + + public static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; + + /** DevWorkspace labels and annotations for mounting secrets and configmaps. */ + public static final String DEV_WORKSPACE_MOUNT_LABEL = + "controller.devfile.io/mount-to-devworkspace"; + + public static final String DEV_WORKSPACE_MOUNT_PATH_ANNOTATION = + "controller.devfile.io/mount-path"; + public static final String DEV_WORKSPACE_MOUNT_AS_ANNOTATION = "controller.devfile.io/mount-as"; + private Constants() {} } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java index fd19ca736c..745ec17658 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java @@ -27,12 +27,11 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import org.eclipse.che.api.core.rest.Service; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; -import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.dto.KubernetesNamespaceMetaDto; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.NamespaceProvisioner; /** @author Sergii Leshchenko */ @Api( @@ -43,10 +42,13 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN public class KubernetesNamespaceService extends Service { private final KubernetesNamespaceFactory namespaceFactory; + private final NamespaceProvisioner namespaceProvisioner; @Inject - public KubernetesNamespaceService(KubernetesNamespaceFactory namespaceFactory) { + public KubernetesNamespaceService( + KubernetesNamespaceFactory namespaceFactory, NamespaceProvisioner namespaceProvisioner) { this.namespaceFactory = namespaceFactory; + this.namespaceProvisioner = namespaceProvisioner; } @GET @@ -82,9 +84,7 @@ public class KubernetesNamespaceService extends Service { message = "Internal server error occurred during namespace provisioning") }) public KubernetesNamespaceMetaDto provision() throws InfrastructureException { - return asDto( - namespaceFactory.provision( - new NamespaceResolutionContext(EnvironmentContext.getCurrent().getSubject()))); + return asDto(namespaceProvisioner.provision()); } private KubernetesNamespaceMetaDto asDto(KubernetesNamespaceMeta kubernetesNamespaceMeta) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java new file mode 100644 index 0000000000..9a975a50d3 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.USER_PREFERENCES_SECRET_NAME; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.USER_PROFILE_SECRET_NAME; + +import io.fabric8.kubernetes.api.model.SecretBuilder; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.user.User; +import org.eclipse.che.api.core.notification.EventSubscriber; +import org.eclipse.che.api.user.server.PreferenceManager; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.user.server.event.PostUserPersistedEvent; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NamespaceProvisioner implements EventSubscriber { + private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); + private final KubernetesNamespaceFactory namespaceFactory; + private final PreferenceManager preferenceManager; + private final KubernetesClientFactory clientFactory; + private final UserManager userManager; + + @Inject + public NamespaceProvisioner( + KubernetesNamespaceFactory namespaceFactory, + KubernetesClientFactory clientFactory, + UserManager userManager, + PreferenceManager preferenceManager) { + this.namespaceFactory = namespaceFactory; + this.clientFactory = clientFactory; + this.userManager = userManager; + this.preferenceManager = preferenceManager; + } + + public KubernetesNamespaceMeta provision() throws InfrastructureException { + + Subject subject = EnvironmentContext.getCurrent().getSubject(); + KubernetesNamespaceMeta kubernetesNamespaceMeta = + namespaceFactory.provision(new NamespaceResolutionContext(subject)); + + try { + createOrUpdateSecrets(userManager.getById(subject.getUserId())); + } catch (NotFoundException | ServerException e) { + LOG.error("Could not find current user. Skipping creation of user information secrets.", e); + } catch (InfrastructureException e) { + LOG.error("There was a failure while creating user information secrets.", e); + } + + return kubernetesNamespaceMeta; + }; + + @Override + public void onEvent(PostUserPersistedEvent event) { + try { + createOrUpdateSecrets(event.getUser()); + } catch (InfrastructureException e) { + LOG.error("There was a failure while creating user information secrets.", e); + } + } + + private void createOrUpdateSecrets(User user) throws InfrastructureException { + + final Map userProfileData = new HashMap<>(); + userProfileData.put("id", user.getId()); + userProfileData.put("name", user.getName()); + userProfileData.put("email", user.getEmail()); + + String namespace = + namespaceFactory.evaluateNamespaceName( + new NamespaceResolutionContext(null, user.getId(), user.getName())); + + clientFactory + .create() + .secrets() + .inNamespace(namespace) + .withName(USER_PROFILE_SECRET_NAME) + .createOrReplace( + new SecretBuilder() + .addToData(userProfileData) + .withNewMetadata() + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, "/config/user/profile") + .endMetadata() + .build()); + + Map preferences; + try { + preferences = preferenceManager.find(user.getId()); + } catch (ServerException e) { + LOG.error( + "Could not find user preferences. Skipping creation of user preferences secrets.", e); + return; + } + + clientFactory + .create() + .secrets() + .inNamespace(namespace) + .withName(USER_PREFERENCES_SECRET_NAME) + .createOrReplace( + new SecretBuilder() + .addToData(preferences) + .withNewMetadata() + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, "/config/user/preferences") + .endMetadata() + .build()); + } +} From d0aed8657de0b1b21c1e89ebafeee41e4ba219bc Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 13 Sep 2021 14:04:49 +0200 Subject: [PATCH 02/18] feat: adapted test for namespacesProvisioner Signed-off-by: xbaran4 --- .../api/server/KubernetesNamespaceService.java | 6 +++++- .../kubernetes/namespace/NamespaceProvisioner.java | 11 ++++------- .../api/server/KubernetesNamespaceServiceTest.java | 10 ++++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java index fdb8f8e7a4..f619569d30 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java @@ -29,6 +29,8 @@ import java.util.stream.Collectors; import javax.inject.Inject; import org.eclipse.che.api.core.rest.Service; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.dto.KubernetesNamespaceMetaDto; @@ -89,7 +91,9 @@ public class KubernetesNamespaceService extends Service { description = "Internal server error occurred during namespace provisioning") }) public KubernetesNamespaceMetaDto provision() throws InfrastructureException { - return asDto(namespaceProvisioner.provision()); + return asDto( + namespaceProvisioner.provision( + new NamespaceResolutionContext(EnvironmentContext.getCurrent().getSubject()))); } private KubernetesNamespaceMetaDto asDto(KubernetesNamespaceMeta kubernetesNamespaceMeta) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java index 9a975a50d3..f6c58e3b7c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java @@ -30,8 +30,6 @@ import org.eclipse.che.api.user.server.UserManager; import org.eclipse.che.api.user.server.event.PostUserPersistedEvent; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.slf4j.Logger; @@ -56,14 +54,13 @@ public class NamespaceProvisioner implements EventSubscriber captor = ArgumentCaptor.forClass(NamespaceResolutionContext.class); - verify(namespaceFactory).provision(captor.capture()); + verify(namespaceProvisioner).provision(captor.capture()); NamespaceResolutionContext actualContext = captor.getValue(); assertEquals(actualContext.getUserId(), SUBJECT.getUserId()); assertEquals(actualContext.getUserName(), SUBJECT.getUserName()); From bd46d1c2181f03bf403b54cae28dcabe94cb6b4d Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Sun, 19 Sep 2021 22:39:28 +0200 Subject: [PATCH 03/18] refactor: decomposing NamespaceProvisioner createOrUpdate() Signed-off-by: xbaran4 --- .../infrastructure/kubernetes/Constants.java | 5 - .../server/KubernetesNamespaceService.java | 2 +- .../NamespaceProvisioner.java | 124 +++++++++++------- .../KubernetesNamespaceServiceTest.java | 2 +- .../provision/NamespaceProvisionerTest.java | 20 +++ 5 files changed, 100 insertions(+), 53 deletions(-) rename infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/{namespace => provision}/NamespaceProvisioner.java (50%) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java index c6401ff32a..10f1f93fcc 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Constants.java @@ -46,11 +46,6 @@ public final class Constants { public static final String POD_STATUS_PHASE_FAILED = "Failed"; public static final String POD_STATUS_PHASE_SUCCEEDED = "Succeeded"; - /** Names for secrets with user information which are used with DevWorkspaces. */ - public static final String USER_PROFILE_SECRET_NAME = "user-profile"; - - public static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; - /** DevWorkspace labels and annotations for mounting secrets and configmaps. */ public static final String DEV_WORKSPACE_MOUNT_LABEL = "controller.devfile.io/mount-to-devworkspace"; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java index f619569d30..e7409b9368 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceService.java @@ -35,7 +35,7 @@ import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.dto.KubernetesNamespaceMetaDto; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.NamespaceProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.NamespaceProvisioner; /** @author Sergii Leshchenko */ @Tag(name = "kubernetes-namespace", description = "Kubernetes REST API for working with Namespaces") diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java similarity index 50% rename from infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java rename to infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index f6c58e3b7c..b3a9b81235 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -9,15 +9,17 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ -package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; +package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.USER_PREFERENCES_SECRET_NAME; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.USER_PROFILE_SECRET_NAME; +import com.google.common.annotations.VisibleForTesting; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClientException; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; @@ -32,11 +34,17 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NamespaceProvisioner implements EventSubscriber { private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); + private static final String USER_PROFILE_SECRET_NAME = "user-profile"; + private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; + private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; + private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; + private final KubernetesNamespaceFactory namespaceFactory; private final PreferenceManager preferenceManager; private final KubernetesClientFactory clientFactory; @@ -63,70 +71,94 @@ public class NamespaceProvisioner implements EventSubscriber userProfileData = new HashMap<>(); - userProfileData.put("id", user.getId()); - userProfileData.put("name", user.getName()); - userProfileData.put("email", user.getEmail()); + userProfileData.put("id", enc.encodeToString(user.getId().getBytes())); + userProfileData.put("name", enc.encodeToString(user.getName().getBytes())); + userProfileData.put("email", enc.encodeToString(user.getEmail().getBytes())); - String namespace = - namespaceFactory.evaluateNamespaceName( - new NamespaceResolutionContext(null, user.getId(), user.getName())); - - clientFactory - .create() - .secrets() - .inNamespace(namespace) + return new SecretBuilder() + .addToData(userProfileData) + .withNewMetadata() .withName(USER_PROFILE_SECRET_NAME) - .createOrReplace( - new SecretBuilder() - .addToData(userProfileData) - .withNewMetadata() - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, "/config/user/profile") - .endMetadata() - .build()); + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PROFILE_SECRET_MOUNT_PATH) + .endMetadata() + .build(); + } + private Secret preparePreferencesSecret(User user) { + Base64.Encoder enc = Base64.getEncoder(); Map preferences; try { preferences = preferenceManager.find(user.getId()); } catch (ServerException e) { LOG.error( "Could not find user preferences. Skipping creation of user preferences secrets.", e); - return; + return null; + } + if (preferences == null || preferences.isEmpty()){ + LOG.error( + "User preferences are empty. Skipping creation of user preferences secrets."); + return null; } - clientFactory - .create() - .secrets() - .inNamespace(namespace) + Map preferencesEncoded = new HashMap<>(); + preferences.forEach( + (key, value) -> + preferencesEncoded.put(normalizeDataKey(key), enc.encodeToString(value.getBytes()))); + + return new SecretBuilder() + .addToData(preferencesEncoded) + .withNewMetadata() .withName(USER_PREFERENCES_SECRET_NAME) - .createOrReplace( - new SecretBuilder() - .addToData(preferences) - .withNewMetadata() - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, "/config/user/preferences") - .endMetadata() - .build()); + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) + .endMetadata() + .build(); + } + + /** + * Some preferences names are not compatible with k8s restrictions on key field in secret. This + * method replaces illegal characters with "-" (dash). + * + * @param name original preference name + * @return k8s compatible preference name used as a key field in Secret + */ + @VisibleForTesting + String normalizeDataKey(String name) { + return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceServiceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceServiceTest.java index fc701e05b6..1ed81fd830 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceServiceTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/api/server/KubernetesNamespaceServiceTest.java @@ -35,7 +35,7 @@ import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.dto.KubernetesNamespaceMetaDto; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.NamespaceProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.NamespaceProvisioner; import org.everrest.assured.EverrestJetty; import org.everrest.core.Filter; import org.everrest.core.GenericContainerRequest; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java new file mode 100644 index 0000000000..1437b9bb22 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.kubernetes.provision; + +import org.testng.annotations.Test; + +public class NamespaceProvisionerTest { + + @Test + public void normalizePreferenceNameTest() {} +} From 3d3cbee7e15c6eabbaded3dd54fd217bb1356ffc Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 20 Sep 2021 13:23:13 +0200 Subject: [PATCH 04/18] test: added tests for exception handling in NamespaceProvisioner Signed-off-by: xbaran4 --- .../provision/NamespaceProvisioner.java | 66 ++++++---- .../provision/NamespaceProvisionerTest.java | 118 +++++++++++++++++- 2 files changed, 156 insertions(+), 28 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index b3a9b81235..4fd9834155 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -22,6 +22,7 @@ import io.fabric8.kubernetes.client.KubernetesClientException; import java.util.Base64; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import javax.inject.Inject; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; @@ -46,9 +47,9 @@ public class NamespaceProvisioner implements EventSubscriber userPreferencesSecret = preparePreferencesSecret(user); try { String namespace = - namespaceFactory.evaluateNamespaceName( - new NamespaceResolutionContext(null, user.getId(), user.getName())); + namespaceFactory.evaluateNamespaceName( + new NamespaceResolutionContext(null, user.getId(), user.getName())); clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); - if (userPreferencesSecret != null) { - clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userPreferencesSecret); + if (userPreferencesSecret.isPresent()) { + clientFactory + .create() + .secrets() + .inNamespace(namespace) + .createOrReplace(userPreferencesSecret.get()); } } catch (InfrastructureException | KubernetesClientException e) { LOG.error("There was a failure while creating user information secrets.", e); } - } private Secret prepareProfileSecret(User user) { @@ -118,7 +127,7 @@ public class NamespaceProvisioner implements EventSubscriber preparePreferencesSecret(User user) { Base64.Encoder enc = Base64.getEncoder(); Map preferences; try { @@ -126,39 +135,42 @@ public class NamespaceProvisioner implements EventSubscriber preferencesEncoded = new HashMap<>(); preferences.forEach( (key, value) -> - preferencesEncoded.put(normalizeDataKey(key), enc.encodeToString(value.getBytes()))); + preferencesEncoded.put( + normalizePreferenceName(key), enc.encodeToString(value.getBytes()))); - return new SecretBuilder() - .addToData(preferencesEncoded) - .withNewMetadata() - .withName(USER_PREFERENCES_SECRET_NAME) - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) - .endMetadata() - .build(); + return Optional.of( + new SecretBuilder() + .addToData(preferencesEncoded) + .withNewMetadata() + .withName(USER_PREFERENCES_SECRET_NAME) + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations( + DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) + .endMetadata() + .build()); } /** - * Some preferences names are not compatible with k8s restrictions on key field in secret. This - * method replaces illegal characters with "-" (dash). + * Some preferences names are not compatible with k8s restrictions on key field in secret. The + * keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal + * characters with - * * @param name original preference name * @return k8s compatible preference name used as a key field in Secret */ @VisibleForTesting - String normalizeDataKey(String name) { + String normalizePreferenceName(String name) { return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java index 1437b9bb22..b323d4c521 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java @@ -11,10 +11,126 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.user.server.PreferenceManager; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; import org.testng.annotations.Test; +@Listeners(MockitoTestNGListener.class) public class NamespaceProvisionerTest { + @Mock private KubernetesNamespaceFactory namespaceFactory; + @Mock private KubernetesClientFactory clientFactory; + @Mock private UserManager userManager; + @Mock private PreferenceManager preferenceManager; + @InjectMocks private NamespaceProvisioner namespaceProvisioner; + + private static final String USER_ID = "user-id"; + private static final String USER_NAME = "user-name"; + private static final String USER_EMAIL = "user-email"; + private static final String USER_NAMESPACE = "user-namespace"; + + private KubernetesServer kubernetesServer; + + @BeforeMethod + public void setUp() throws InfrastructureException, NotFoundException, ServerException { + kubernetesServer = new KubernetesServer(true, true); + kubernetesServer.before(); + + Map preferences = new HashMap<>(); + preferences.put("preference-name", "preference"); + + lenient().when(clientFactory.create()).thenReturn(kubernetesServer.getClient()); + lenient() + .when(namespaceFactory.provision(any())) + .thenReturn(new KubernetesNamespaceMetaImpl(USER_NAMESPACE, Collections.emptyMap())); + lenient() + .when(userManager.getById(USER_ID)) + .thenReturn(new UserImpl(USER_ID, USER_EMAIL, USER_NAME)); + lenient().when(namespaceFactory.evaluateNamespaceName(any())).thenReturn(USER_NAMESPACE); + lenient().when(preferenceManager.find(USER_ID)).thenReturn(preferences); + } + + @AfterMethod + public void cleanUp() { + kubernetesServer.after(); + } + @Test - public void normalizePreferenceNameTest() {} + public void shouldCreateSecretsOnNamespaceProvision() throws InfrastructureException { + namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); + List createdSecrets = + kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); + assertEquals(createdSecrets.size(), 2); + assertTrue( + createdSecrets + .stream() + .anyMatch(secret -> secret.getMetadata().getName().equals("user-profile"))); + assertTrue( + createdSecrets + .stream() + .anyMatch(secret -> secret.getMetadata().getName().equals("user-preferences"))); + } + + @Test + public void shouldCreateOnlyProfileSecret() throws InfrastructureException, ServerException { + when(preferenceManager.find(USER_ID)).thenReturn(Collections.emptyMap()); + namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); + List createdSecrets = + kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); + assertEquals(createdSecrets.size(), 1); + assertEquals(createdSecrets.get(0).getMetadata().getName(), "user-profile"); + } + + @Test + public void shouldCreateNoSecretOnException() throws InfrastructureException, NotFoundException, ServerException { + when(userManager.getById(USER_ID)).thenThrow(new ServerException("Test server exception")); + namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); + assertTrue(kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems().isEmpty()); + verifyNoInteractions(clientFactory); + } + + @Test + public void shouldNormalizePreferenceName() { + assertEquals(namespaceProvisioner.normalizePreferenceName("codename:bond"), "codename-bond"); + assertEquals(namespaceProvisioner.normalizePreferenceName("some--:pref"), "some-pref"); + assertEquals(namespaceProvisioner.normalizePreferenceName("pref[name].sub"), "pref-name-.sub"); + } + + @Test + public void shouldKeepPreferenceName() { + assertEquals(namespaceProvisioner.normalizePreferenceName("codename.bond"), "codename.bond"); + assertEquals(namespaceProvisioner.normalizePreferenceName("pref_name"), "pref_name"); + assertEquals( + namespaceProvisioner.normalizePreferenceName("some-name.over_rainbow"), + "some-name.over_rainbow"); + } } From a41e86ae2635a3cfff61b86dbc7d67f0ea0a0204 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 20 Sep 2021 13:25:01 +0200 Subject: [PATCH 05/18] format: mvn fmt:format Signed-off-by: xbaran4 --- .../provision/NamespaceProvisionerTest.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java index b323d4c521..8342e9ca9d 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java @@ -13,7 +13,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -38,7 +37,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; -import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; @@ -111,10 +109,18 @@ public class NamespaceProvisionerTest { } @Test - public void shouldCreateNoSecretOnException() throws InfrastructureException, NotFoundException, ServerException { + public void shouldCreateNoSecretOnException() + throws InfrastructureException, NotFoundException, ServerException { when(userManager.getById(USER_ID)).thenThrow(new ServerException("Test server exception")); namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); - assertTrue(kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems().isEmpty()); + assertTrue( + kubernetesServer + .getClient() + .secrets() + .inNamespace(USER_NAMESPACE) + .list() + .getItems() + .isEmpty()); verifyNoInteractions(clientFactory); } From 048e35863cb715d62200b2d6ae17e478cd04948a Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Tue, 21 Sep 2021 11:05:05 +0200 Subject: [PATCH 06/18] doc: added javadoc for NamespaceProvisioner Signed-off-by: xbaran4 --- .../kubernetes/provision/NamespaceProvisioner.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 4fd9834155..cc993c928d 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -39,6 +39,14 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * On namespace provisioning, creates k8s {@link Secret} profile and preferences + * from information about the User. + * + * Implements {@link EventSubscriber} for updating these Secrets. + * + * @author Pavol Baran + */ public class NamespaceProvisioner implements EventSubscriber { private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); private static final String USER_PROFILE_SECRET_NAME = "user-profile"; @@ -85,7 +93,7 @@ public class NamespaceProvisioner implements EventSubscriber Date: Wed, 22 Sep 2021 12:15:09 +0200 Subject: [PATCH 07/18] fix: removed secrets creation on event Signed-off-by: xbaran4 --- .../provision/NamespaceProvisioner.java | 19 ++++++------------- .../provision/NamespaceProvisionerTest.java | 16 +++------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index cc993c928d..41af44e268 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -27,10 +27,8 @@ import javax.inject.Inject; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.user.server.PreferenceManager; import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.api.user.server.event.PostUserPersistedEvent; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; @@ -40,14 +38,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * On namespace provisioning, creates k8s {@link Secret} profile and preferences - * from information about the User. - * - * Implements {@link EventSubscriber} for updating these Secrets. + * On namespace provisioning, creates k8s {@link Secret} profile and preferences from information + * about the User. * * @author Pavol Baran */ -public class NamespaceProvisioner implements EventSubscriber { +public class NamespaceProvisioner { private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); private static final String USER_PROFILE_SECRET_NAME = "user-profile"; private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; @@ -79,16 +75,13 @@ public class NamespaceProvisioner implements EventSubscriber Date: Fri, 24 Sep 2021 09:16:57 +0200 Subject: [PATCH 08/18] feat: created configurator package with configurators Signed-off-by: xbaran4 --- .../namespace/configurator/NamespaceConfigurator.java | 4 ++++ .../namespace/configurator/UserPreferencesConfigurator.java | 4 ++++ .../namespace/configurator/UserProfileConfigurator.java | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java new file mode 100644 index 0000000000..2c52cba6d8 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java @@ -0,0 +1,4 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; + +public interface NamespaceConfigurator{ +} \ No newline at end of file diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java new file mode 100644 index 0000000000..a7e9f3f94c --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -0,0 +1,4 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; + +public class UserPreferencesConfigurator implements NamespaceConfigurator { +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java new file mode 100644 index 0000000000..cfad4371d7 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java @@ -0,0 +1,4 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; + +public class UserProfileConfigurator implements NamespaceConfigurator{ +} From 33f1a887489883559f7ba5ad9aa2bce5f3d205b9 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Fri, 24 Sep 2021 10:00:48 +0200 Subject: [PATCH 09/18] refactor: moving provision method from NamespaceFactory to NamespaceProvisioner Signed-off-by: xbaran4 --- .../namespace/KubernetesNamespaceFactory.java | 17 +------------ .../provision/NamespaceProvisioner.java | 25 +++++++++++++------ .../project/OpenShiftProjectFactory.java | 2 +- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java index 7871c8a834..c1ae7ce7df 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java @@ -255,7 +255,7 @@ public class KubernetesNamespaceFactory { * @return optional with kubernetes namespace meta * @throws InfrastructureException when any error occurs during namespace fetching */ - protected Optional fetchNamespace(String name) + public Optional fetchNamespace(String name) throws InfrastructureException { try { Namespace namespace = clientFactory.create().namespaces().withName(name).get(); @@ -372,21 +372,6 @@ public class KubernetesNamespaceFactory { return namespace; } - public KubernetesNamespaceMeta provision(NamespaceResolutionContext namespaceResolutionContext) - throws InfrastructureException { - KubernetesNamespace namespace = - getOrCreate( - new RuntimeIdentityImpl( - null, - null, - namespaceResolutionContext.getUserId(), - evaluateNamespaceName(namespaceResolutionContext))); - - return fetchNamespace(namespace.getName()) - .orElseThrow( - () -> new InfrastructureException("Not able to find namespace " + namespace.getName())); - } - public KubernetesNamespace get(RuntimeIdentity identity) throws InfrastructureException { String workspaceId = identity.getWorkspaceId(); String namespaceName = identity.getInfrastructureNamespace(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 41af44e268..b9751ede05 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -29,10 +29,12 @@ import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.user.User; import org.eclipse.che.api.user.server.PreferenceManager; import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,19 +70,28 @@ public class NamespaceProvisioner { } public KubernetesNamespaceMeta provision(NamespaceResolutionContext namespaceResolutionContext) - throws InfrastructureException { + throws InfrastructureException { + KubernetesNamespace namespace = + namespaceFactory.getOrCreate( + new RuntimeIdentityImpl( + null, + null, + namespaceResolutionContext.getUserId(), + namespaceFactory.evaluateNamespaceName(namespaceResolutionContext))); + + KubernetesNamespaceMeta namespaceMeta = namespaceFactory.fetchNamespace(namespace.getName()) + .orElseThrow( + () -> new InfrastructureException("Not able to find namespace " + namespace.getName())); - KubernetesNamespaceMeta kubernetesNamespaceMeta = - namespaceFactory.provision(namespaceResolutionContext); try { createOrUpdateSecrets(userManager.getById(namespaceResolutionContext.getUserId())); } catch (NotFoundException | ServerException e) { throw new InfrastructureException( - "Could not find current user. Because of this, cannot create user profile and preferences secrets.", - e); + "Could not find current user. Because of this, cannot create user profile and preferences secrets.", + e); } - return kubernetesNamespaceMeta; - }; + return namespaceMeta; + } /** * Creates k8s user profile and user preferences k8s secrets. This serves as a way for diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectFactory.java index 220f633075..547f55c02a 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectFactory.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectFactory.java @@ -207,7 +207,7 @@ public class OpenShiftProjectFactory extends KubernetesNamespaceFactory { } @Override - protected Optional fetchNamespace(String name) + public Optional fetchNamespace(String name) throws InfrastructureException { return fetchNamespaceObject(name).map(this::asNamespaceMeta); } From b73d4968e1a0b2a18e33c8198a0215f833a1b48e Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Fri, 24 Sep 2021 11:13:44 +0200 Subject: [PATCH 10/18] refactor: moved profile secret creation from NamespaceProvisioner to UserProfileConfigurator Signed-off-by: xbaran4 --- .../configurator/NamespaceConfigurator.java | 4 + .../UserPreferencesConfigurator.java | 71 +++++++++++++++++ .../configurator/UserProfileConfigurator.java | 74 +++++++++++++++++- .../provision/NamespaceProvisioner.java | 76 ------------------- 4 files changed, 148 insertions(+), 77 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java index 2c52cba6d8..9da57a0a54 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java @@ -1,4 +1,8 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; + public interface NamespaceConfigurator{ + public void configure(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException; } \ No newline at end of file diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index a7e9f3f94c..b8c9e0e123 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -1,4 +1,75 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; +import com.google.common.annotations.VisibleForTesting; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.user.User; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; + public class UserPreferencesConfigurator implements NamespaceConfigurator { + private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; + private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; + + + @Override + public void configure(NamespaceResolutionContext namespaceResolutionContext) { + + } + + private Optional preparePreferencesSecret(User user) { + Base64.Encoder enc = Base64.getEncoder(); + Map preferences; + try { + preferences = preferenceManager.find(user.getId()); + } catch (ServerException e) { + LOG.error( + "Could not find user preferences. Skipping creation of user preferences secrets.", e); + return Optional.empty(); + } + if (preferences == null || preferences.isEmpty()) { + LOG.error("User preferences are empty. Skipping creation of user preferences secrets."); + return Optional.empty(); + } + + Map preferencesEncoded = new HashMap<>(); + preferences.forEach( + (key, value) -> + preferencesEncoded.put( + normalizePreferenceName(key), enc.encodeToString(value.getBytes()))); + + return Optional.of( + new SecretBuilder() + .addToData(preferencesEncoded) + .withNewMetadata() + .withName(USER_PREFERENCES_SECRET_NAME) + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations( + DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) + .endMetadata() + .build()); + } + + /** + * Some preferences names are not compatible with k8s restrictions on key field in secret. The + * keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal + * characters with - + * + * @param name original preference name + * @return k8s compatible preference name used as a key field in Secret + */ + @VisibleForTesting + String normalizePreferenceName(String name) { + return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java index cfad4371d7..16cd5e1d32 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java @@ -1,4 +1,76 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; -public class UserProfileConfigurator implements NamespaceConfigurator{ +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClientException; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.user.User; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; + +import javax.inject.Inject; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; + +public class UserProfileConfigurator implements NamespaceConfigurator { + private static final String USER_PROFILE_SECRET_NAME = "user-profile"; + private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; + + private final KubernetesNamespaceFactory namespaceFactory; + private final KubernetesClientFactory clientFactory; + private final UserManager userManager; + + + @Inject + public UserProfileConfigurator(KubernetesNamespaceFactory namespaceFactory, KubernetesClientFactory clientFactory, + UserManager userManager) { + this.namespaceFactory = namespaceFactory; + this.clientFactory = clientFactory; + this.userManager = userManager; + } + + @Override + public void configure(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { + Secret userProfileSecret = prepareProfileSecret(namespaceResolutionContext); + String namespace = namespaceFactory.evaluateNamespaceName(namespaceResolutionContext); + try { + clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); + } catch (KubernetesClientException e) { + throw new InfrastructureException(e); + } + } + + private Secret prepareProfileSecret(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { + User user; + try { + user = userManager.getById(namespaceResolutionContext.getUserId()); + } catch (NotFoundException | ServerException e) { + throw new InfrastructureException(e); + } + + Base64.Encoder enc = Base64.getEncoder(); + final Map userProfileData = new HashMap<>(); + userProfileData.put("id", enc.encodeToString(user.getId().getBytes())); + userProfileData.put("name", enc.encodeToString(user.getName().getBytes())); + userProfileData.put("email", enc.encodeToString(user.getEmail().getBytes())); + + return new SecretBuilder() + .addToData(userProfileData) + .withNewMetadata() + .withName(USER_PROFILE_SECRET_NAME) + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PROFILE_SECRET_MOUNT_PATH) + .endMetadata() + .build(); + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index b9751ede05..9cb1cd9548 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -47,15 +47,10 @@ import org.slf4j.LoggerFactory; */ public class NamespaceProvisioner { private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); - private static final String USER_PROFILE_SECRET_NAME = "user-profile"; - private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; - private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; - private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; private final KubernetesNamespaceFactory namespaceFactory; private final KubernetesClientFactory clientFactory; private final UserManager userManager; - private final PreferenceManager preferenceManager; @Inject public NamespaceProvisioner( @@ -100,15 +95,9 @@ public class NamespaceProvisioner { * @param user from information about this user are the secrets created */ private void createOrUpdateSecrets(User user) { - Secret userProfileSecret = prepareProfileSecret(user); Optional userPreferencesSecret = preparePreferencesSecret(user); try { - String namespace = - namespaceFactory.evaluateNamespaceName( - new NamespaceResolutionContext(null, user.getId(), user.getName())); - - clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); if (userPreferencesSecret.isPresent()) { clientFactory .create() @@ -120,69 +109,4 @@ public class NamespaceProvisioner { LOG.error("There was a failure while creating user information secrets.", e); } } - - private Secret prepareProfileSecret(User user) { - Base64.Encoder enc = Base64.getEncoder(); - final Map userProfileData = new HashMap<>(); - userProfileData.put("id", enc.encodeToString(user.getId().getBytes())); - userProfileData.put("name", enc.encodeToString(user.getName().getBytes())); - userProfileData.put("email", enc.encodeToString(user.getEmail().getBytes())); - - return new SecretBuilder() - .addToData(userProfileData) - .withNewMetadata() - .withName(USER_PROFILE_SECRET_NAME) - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PROFILE_SECRET_MOUNT_PATH) - .endMetadata() - .build(); - } - - private Optional preparePreferencesSecret(User user) { - Base64.Encoder enc = Base64.getEncoder(); - Map preferences; - try { - preferences = preferenceManager.find(user.getId()); - } catch (ServerException e) { - LOG.error( - "Could not find user preferences. Skipping creation of user preferences secrets.", e); - return Optional.empty(); - } - if (preferences == null || preferences.isEmpty()) { - LOG.error("User preferences are empty. Skipping creation of user preferences secrets."); - return Optional.empty(); - } - - Map preferencesEncoded = new HashMap<>(); - preferences.forEach( - (key, value) -> - preferencesEncoded.put( - normalizePreferenceName(key), enc.encodeToString(value.getBytes()))); - - return Optional.of( - new SecretBuilder() - .addToData(preferencesEncoded) - .withNewMetadata() - .withName(USER_PREFERENCES_SECRET_NAME) - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations( - DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) - .endMetadata() - .build()); - } - - /** - * Some preferences names are not compatible with k8s restrictions on key field in secret. The - * keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal - * characters with - - * - * @param name original preference name - * @return k8s compatible preference name used as a key field in Secret - */ - @VisibleForTesting - String normalizePreferenceName(String name) { - return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); - } } From 5f4cd273dffa94f8d260c6e293bdea1a99094b12 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Fri, 24 Sep 2021 11:54:10 +0200 Subject: [PATCH 11/18] refactor: moved preferences secret creation from NamespaceProvisioner to UserPreferencesConfigurator Signed-off-by: xbaran4 --- .../namespace/KubernetesNamespaceFactory.java | 1 - .../configurator/NamespaceConfigurator.java | 7 +- .../UserPreferencesConfigurator.java | 155 +++++++++++------- .../configurator/UserProfileConfigurator.java | 110 +++++++------ .../provision/NamespaceProvisioner.java | 44 ++--- 5 files changed, 170 insertions(+), 147 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java index c1ae7ce7df..3e0e533f36 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactory.java @@ -53,7 +53,6 @@ import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.user.server.PreferenceManager; import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.commons.annotation.Nullable; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java index 9da57a0a54..15454c23b5 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java @@ -3,6 +3,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurat import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; -public interface NamespaceConfigurator{ - public void configure(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException; -} \ No newline at end of file +public interface NamespaceConfigurator { + public void configure(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException; +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index b8c9e0e123..132fe91740 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -1,75 +1,108 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; -import com.google.common.annotations.VisibleForTesting; -import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.SecretBuilder; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; - -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; +import com.google.common.annotations.VisibleForTesting; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClientException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.user.User; +import org.eclipse.che.api.user.server.PreferenceManager; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; + public class UserPreferencesConfigurator implements NamespaceConfigurator { - private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; - private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; + private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; + private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; + private final KubernetesNamespaceFactory namespaceFactory; + private final KubernetesClientFactory clientFactory; + private final UserManager userManager; + private final PreferenceManager preferenceManager; - @Override - public void configure(NamespaceResolutionContext namespaceResolutionContext) { + @Inject + public UserPreferencesConfigurator( + KubernetesNamespaceFactory namespaceFactory, + KubernetesClientFactory clientFactory, + UserManager userManager, + PreferenceManager preferenceManager) { + this.namespaceFactory = namespaceFactory; + this.clientFactory = clientFactory; + this.userManager = userManager; + this.preferenceManager = preferenceManager; + } + @Override + public void configure(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException { + Secret userPreferencesSecret = preparePreferencesSecret(namespaceResolutionContext); + String namespace = namespaceFactory.evaluateNamespaceName(namespaceResolutionContext); + + try { + clientFactory + .create() + .secrets() + .inNamespace(namespace) + .createOrReplace(userPreferencesSecret); + } catch (KubernetesClientException e) { + throw new InfrastructureException(e); + } + } + + private Secret preparePreferencesSecret(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException { + Base64.Encoder enc = Base64.getEncoder(); + User user; + Map preferences; + + try { + user = userManager.getById(namespaceResolutionContext.getUserId()); + preferences = preferenceManager.find(user.getId()); + } catch (NotFoundException | ServerException e) { + throw new InfrastructureException(e); + } + if (preferences == null || preferences.isEmpty()) { + throw new InfrastructureException( + "User preferences are empty. Skipping creation of user preferences secrets."); } - private Optional preparePreferencesSecret(User user) { - Base64.Encoder enc = Base64.getEncoder(); - Map preferences; - try { - preferences = preferenceManager.find(user.getId()); - } catch (ServerException e) { - LOG.error( - "Could not find user preferences. Skipping creation of user preferences secrets.", e); - return Optional.empty(); - } - if (preferences == null || preferences.isEmpty()) { - LOG.error("User preferences are empty. Skipping creation of user preferences secrets."); - return Optional.empty(); - } + Map preferencesEncoded = new HashMap<>(); + preferences.forEach( + (key, value) -> + preferencesEncoded.put( + normalizePreferenceName(key), enc.encodeToString(value.getBytes()))); + return new SecretBuilder() + .addToData(preferencesEncoded) + .withNewMetadata() + .withName(USER_PREFERENCES_SECRET_NAME) + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) + .endMetadata() + .build(); + } - Map preferencesEncoded = new HashMap<>(); - preferences.forEach( - (key, value) -> - preferencesEncoded.put( - normalizePreferenceName(key), enc.encodeToString(value.getBytes()))); - - return Optional.of( - new SecretBuilder() - .addToData(preferencesEncoded) - .withNewMetadata() - .withName(USER_PREFERENCES_SECRET_NAME) - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations( - DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH) - .endMetadata() - .build()); - } - - /** - * Some preferences names are not compatible with k8s restrictions on key field in secret. The - * keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal - * characters with - - * - * @param name original preference name - * @return k8s compatible preference name used as a key field in Secret - */ - @VisibleForTesting - String normalizePreferenceName(String name) { - return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); - } + /** + * Some preferences names are not compatible with k8s restrictions on key field in secret. The + * keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal + * characters with - + * + * @param name original preference name + * @return k8s compatible preference name used as a key field in Secret + */ + @VisibleForTesting + String normalizePreferenceName(String name) { + return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java index 16cd5e1d32..9b69abdd04 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java @@ -1,8 +1,16 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; + import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.user.User; @@ -12,65 +20,59 @@ import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import javax.inject.Inject; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; - public class UserProfileConfigurator implements NamespaceConfigurator { - private static final String USER_PROFILE_SECRET_NAME = "user-profile"; - private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; + private static final String USER_PROFILE_SECRET_NAME = "user-profile"; + private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; - private final KubernetesNamespaceFactory namespaceFactory; - private final KubernetesClientFactory clientFactory; - private final UserManager userManager; + private final KubernetesNamespaceFactory namespaceFactory; + private final KubernetesClientFactory clientFactory; + private final UserManager userManager; + @Inject + public UserProfileConfigurator( + KubernetesNamespaceFactory namespaceFactory, + KubernetesClientFactory clientFactory, + UserManager userManager) { + this.namespaceFactory = namespaceFactory; + this.clientFactory = clientFactory; + this.userManager = userManager; + } - @Inject - public UserProfileConfigurator(KubernetesNamespaceFactory namespaceFactory, KubernetesClientFactory clientFactory, - UserManager userManager) { - this.namespaceFactory = namespaceFactory; - this.clientFactory = clientFactory; - this.userManager = userManager; + @Override + public void configure(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException { + Secret userProfileSecret = prepareProfileSecret(namespaceResolutionContext); + String namespace = namespaceFactory.evaluateNamespaceName(namespaceResolutionContext); + try { + clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); + } catch (KubernetesClientException e) { + throw new InfrastructureException(e); + } + } + + private Secret prepareProfileSecret(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException { + User user; + try { + user = userManager.getById(namespaceResolutionContext.getUserId()); + } catch (NotFoundException | ServerException e) { + throw new InfrastructureException(e); } - @Override - public void configure(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { - Secret userProfileSecret = prepareProfileSecret(namespaceResolutionContext); - String namespace = namespaceFactory.evaluateNamespaceName(namespaceResolutionContext); - try { - clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); - } catch (KubernetesClientException e) { - throw new InfrastructureException(e); - } - } + Base64.Encoder enc = Base64.getEncoder(); + final Map userProfileData = new HashMap<>(); + userProfileData.put("id", enc.encodeToString(user.getId().getBytes())); + userProfileData.put("name", enc.encodeToString(user.getName().getBytes())); + userProfileData.put("email", enc.encodeToString(user.getEmail().getBytes())); - private Secret prepareProfileSecret(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { - User user; - try { - user = userManager.getById(namespaceResolutionContext.getUserId()); - } catch (NotFoundException | ServerException e) { - throw new InfrastructureException(e); - } - - Base64.Encoder enc = Base64.getEncoder(); - final Map userProfileData = new HashMap<>(); - userProfileData.put("id", enc.encodeToString(user.getId().getBytes())); - userProfileData.put("name", enc.encodeToString(user.getName().getBytes())); - userProfileData.put("email", enc.encodeToString(user.getEmail().getBytes())); - - return new SecretBuilder() - .addToData(userProfileData) - .withNewMetadata() - .withName(USER_PROFILE_SECRET_NAME) - .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") - .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") - .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PROFILE_SECRET_MOUNT_PATH) - .endMetadata() - .build(); - } + return new SecretBuilder() + .addToData(userProfileData) + .withNewMetadata() + .withName(USER_PROFILE_SECRET_NAME) + .addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true") + .addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file") + .addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PROFILE_SECRET_MOUNT_PATH) + .endMetadata() + .build(); + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 9cb1cd9548..398eb07bbf 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -11,23 +11,13 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_LABEL; -import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_PATH_ANNOTATION; -import com.google.common.annotations.VisibleForTesting; import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; import javax.inject.Inject; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.user.server.PreferenceManager; import org.eclipse.che.api.user.server.UserManager; import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; @@ -36,8 +26,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFacto import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * On namespace provisioning, creates k8s {@link Secret} profile and preferences from information @@ -46,7 +34,6 @@ import org.slf4j.LoggerFactory; * @author Pavol Baran */ public class NamespaceProvisioner { - private static final Logger LOG = LoggerFactory.getLogger(NamespaceProvisioner.class); private final KubernetesNamespaceFactory namespaceFactory; private final KubernetesClientFactory clientFactory; @@ -56,34 +43,36 @@ public class NamespaceProvisioner { public NamespaceProvisioner( KubernetesNamespaceFactory namespaceFactory, KubernetesClientFactory clientFactory, - UserManager userManager, - PreferenceManager preferenceManager) { + UserManager userManager) { this.namespaceFactory = namespaceFactory; this.clientFactory = clientFactory; this.userManager = userManager; - this.preferenceManager = preferenceManager; } public KubernetesNamespaceMeta provision(NamespaceResolutionContext namespaceResolutionContext) - throws InfrastructureException { + throws InfrastructureException { KubernetesNamespace namespace = - namespaceFactory.getOrCreate( - new RuntimeIdentityImpl( - null, - null, - namespaceResolutionContext.getUserId(), - namespaceFactory.evaluateNamespaceName(namespaceResolutionContext))); + namespaceFactory.getOrCreate( + new RuntimeIdentityImpl( + null, + null, + namespaceResolutionContext.getUserId(), + namespaceFactory.evaluateNamespaceName(namespaceResolutionContext))); - KubernetesNamespaceMeta namespaceMeta = namespaceFactory.fetchNamespace(namespace.getName()) + KubernetesNamespaceMeta namespaceMeta = + namespaceFactory + .fetchNamespace(namespace.getName()) .orElseThrow( - () -> new InfrastructureException("Not able to find namespace " + namespace.getName())); + () -> + new InfrastructureException( + "Not able to find namespace " + namespace.getName())); try { createOrUpdateSecrets(userManager.getById(namespaceResolutionContext.getUserId())); } catch (NotFoundException | ServerException e) { throw new InfrastructureException( - "Could not find current user. Because of this, cannot create user profile and preferences secrets.", - e); + "Could not find current user. Because of this, cannot create user profile and preferences secrets.", + e); } return namespaceMeta; } @@ -95,7 +84,6 @@ public class NamespaceProvisioner { * @param user from information about this user are the secrets created */ private void createOrUpdateSecrets(User user) { - Optional userPreferencesSecret = preparePreferencesSecret(user); try { if (userPreferencesSecret.isPresent()) { From dece8232929e36866dc7e9fe39c9f6721996d5e8 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Fri, 24 Sep 2021 12:21:49 +0200 Subject: [PATCH 12/18] refactor: adapted NamespaceProvisioner for UserProfileConfigurator and UserPreferencesConfigurator Signed-off-by: xbaran4 --- .../provision/NamespaceProvisioner.java | 48 +++++-------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 398eb07bbf..6045aa5bce 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -13,19 +13,15 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.client.KubernetesClientException; import javax.inject.Inject; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.model.user.User; -import org.eclipse.che.api.user.server.UserManager; import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; /** * On namespace provisioning, creates k8s {@link Secret} profile and preferences from information @@ -34,19 +30,16 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN * @author Pavol Baran */ public class NamespaceProvisioner { - private final KubernetesNamespaceFactory namespaceFactory; - private final KubernetesClientFactory clientFactory; - private final UserManager userManager; + private final UserProfileConfigurator userProfileConfigurator; + private final UserPreferencesConfigurator userPreferencesConfigurator; @Inject public NamespaceProvisioner( - KubernetesNamespaceFactory namespaceFactory, - KubernetesClientFactory clientFactory, - UserManager userManager) { + KubernetesNamespaceFactory namespaceFactory, UserProfileConfigurator userProfileConfigurator, UserPreferencesConfigurator userPreferencesConfigurator) { this.namespaceFactory = namespaceFactory; - this.clientFactory = clientFactory; - this.userManager = userManager; + this.userProfileConfigurator = userProfileConfigurator; + this.userPreferencesConfigurator = userPreferencesConfigurator; } public KubernetesNamespaceMeta provision(NamespaceResolutionContext namespaceResolutionContext) @@ -66,35 +59,16 @@ public class NamespaceProvisioner { () -> new InfrastructureException( "Not able to find namespace " + namespace.getName())); - - try { - createOrUpdateSecrets(userManager.getById(namespaceResolutionContext.getUserId())); - } catch (NotFoundException | ServerException e) { - throw new InfrastructureException( - "Could not find current user. Because of this, cannot create user profile and preferences secrets.", - e); - } + configureNamespace(namespaceResolutionContext); return namespaceMeta; } /** * Creates k8s user profile and user preferences k8s secrets. This serves as a way for * DevWorkspaces to acquire information about the user. - * - * @param user from information about this user are the secrets created */ - private void createOrUpdateSecrets(User user) { - - try { - if (userPreferencesSecret.isPresent()) { - clientFactory - .create() - .secrets() - .inNamespace(namespace) - .createOrReplace(userPreferencesSecret.get()); - } - } catch (InfrastructureException | KubernetesClientException e) { - LOG.error("There was a failure while creating user information secrets.", e); - } + private void configureNamespace(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { + userProfileConfigurator.configure(namespaceResolutionContext); + userPreferencesConfigurator.configure(namespaceResolutionContext); } } From e96aa25fb550f7b598e44c733b7b30ab90642480 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Fri, 24 Sep 2021 14:46:29 +0200 Subject: [PATCH 13/18] doc: added javadoc for NamespaceConfigurator classes Signed-off-by: xbaran4 --- .../configurator/NamespaceConfigurator.java | 26 +++++++++++++++++++ .../UserPreferencesConfigurator.java | 17 ++++++++++++ .../configurator/UserProfileConfigurator.java | 17 ++++++++++++ .../provision/NamespaceProvisioner.java | 19 +++++++------- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java index 15454c23b5..e42e9fb1d4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/NamespaceConfigurator.java @@ -1,9 +1,35 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; +import io.fabric8.kubernetes.api.model.Secret; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.NamespaceProvisioner; +/** + * Configures user's namespace after provisioning in {@link NamespaceProvisioner} with whatever is + * needed. Such as creating user profile and preferences {@link Secret} in user namespace. + * + * @author Pavol Baran + */ public interface NamespaceConfigurator { + + /** + * Configures user's namespace after provisioning. + * + * @param namespaceResolutionContext users namespace context + * @throws InfrastructureException when any error occurs + */ public void configure(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index 132fe91740..040bcf8d20 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; @@ -22,6 +33,12 @@ import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +/** + * Creates {@link Secret} with user preferences. This serves as a way for DevWorkspaces to acquire + * information about the user. + * + * @author Pavol Baran + */ public class UserPreferencesConfigurator implements NamespaceConfigurator { private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java index 9b69abdd04..4810d83514 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.DEV_WORKSPACE_MOUNT_AS_ANNOTATION; @@ -20,6 +31,12 @@ import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +/** + * Creates {@link Secret} with user profile information such as his id, name and email. This serves + * as a way for DevWorkspaces to acquire information about the user. + * + * @author Pavol Baran + */ public class UserProfileConfigurator implements NamespaceConfigurator { private static final String USER_PROFILE_SECRET_NAME = "user-profile"; private static final String USER_PROFILE_SECRET_MOUNT_PATH = "/config/user/profile"; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 6045aa5bce..5ea07cf8fe 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -11,8 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; - -import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.Namespace; import javax.inject.Inject; import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; @@ -20,12 +19,13 @@ import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; /** - * On namespace provisioning, creates k8s {@link Secret} profile and preferences from information - * about the User. + * Provisions the k8s {@link Namespace}. After provisioning, configures the namespace through {@link + * NamespaceConfigurator}. * * @author Pavol Baran */ @@ -36,7 +36,9 @@ public class NamespaceProvisioner { @Inject public NamespaceProvisioner( - KubernetesNamespaceFactory namespaceFactory, UserProfileConfigurator userProfileConfigurator, UserPreferencesConfigurator userPreferencesConfigurator) { + KubernetesNamespaceFactory namespaceFactory, + UserProfileConfigurator userProfileConfigurator, + UserPreferencesConfigurator userPreferencesConfigurator) { this.namespaceFactory = namespaceFactory; this.userProfileConfigurator = userProfileConfigurator; this.userPreferencesConfigurator = userPreferencesConfigurator; @@ -63,11 +65,8 @@ public class NamespaceProvisioner { return namespaceMeta; } - /** - * Creates k8s user profile and user preferences k8s secrets. This serves as a way for - * DevWorkspaces to acquire information about the user. - */ - private void configureNamespace(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { + private void configureNamespace(NamespaceResolutionContext namespaceResolutionContext) + throws InfrastructureException { userProfileConfigurator.configure(namespaceResolutionContext); userPreferencesConfigurator.configure(namespaceResolutionContext); } From 31366691ec0046b62928bd7c9a52f9a21c9bc820 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 27 Sep 2021 00:49:46 +0200 Subject: [PATCH 14/18] test: added test for UserPreferencesConfigurator Signed-off-by: xbaran4 --- .../UserPreferencesConfigurator.java | 14 +- .../configurator/UserProfileConfigurator.java | 8 +- .../provision/NamespaceProvisioner.java | 1 + .../KubernetesNamespaceFactoryTest.java | 23 ++- .../UserPreferencesConfiguratorTest.java | 113 +++++++++++++++ .../UserProfileConfiguratorTest.java | 82 +++++++++++ .../provision/NamespaceProvisionerTest.java | 132 ------------------ 7 files changed, 233 insertions(+), 140 deletions(-) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java delete mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index 040bcf8d20..e11c8b0b0c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -73,7 +73,8 @@ public class UserPreferencesConfigurator implements NamespaceConfigurator { .inNamespace(namespace) .createOrReplace(userPreferencesSecret); } catch (KubernetesClientException e) { - throw new InfrastructureException(e); + throw new InfrastructureException( + "Error occurred while trying to create user preferences secret.", e); } } @@ -87,11 +88,18 @@ public class UserPreferencesConfigurator implements NamespaceConfigurator { user = userManager.getById(namespaceResolutionContext.getUserId()); preferences = preferenceManager.find(user.getId()); } catch (NotFoundException | ServerException e) { - throw new InfrastructureException(e); + throw new InfrastructureException( + String.format( + "Preferences of user with id:%s cannot be retrieved.", + namespaceResolutionContext.getUserId()), + e); } + if (preferences == null || preferences.isEmpty()) { throw new InfrastructureException( - "User preferences are empty. Skipping creation of user preferences secrets."); + String.format( + "Preferences of user with id:%s are empty. Cannot create user preferences secrets.", + namespaceResolutionContext.getUserId())); } Map preferencesEncoded = new HashMap<>(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java index 4810d83514..ecfe5a2845 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfigurator.java @@ -63,7 +63,8 @@ public class UserProfileConfigurator implements NamespaceConfigurator { try { clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret); } catch (KubernetesClientException e) { - throw new InfrastructureException(e); + throw new InfrastructureException( + "Error occurred while trying to create user profile secret.", e); } } @@ -73,7 +74,10 @@ public class UserProfileConfigurator implements NamespaceConfigurator { try { user = userManager.getById(namespaceResolutionContext.getUserId()); } catch (NotFoundException | ServerException e) { - throw new InfrastructureException(e); + throw new InfrastructureException( + String.format( + "Could not find current user with id:%s.", namespaceResolutionContext.getUserId()), + e); } Base64.Encoder enc = Base64.getEncoder(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 5ea07cf8fe..032476ab26 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -44,6 +44,7 @@ public class NamespaceProvisioner { this.userPreferencesConfigurator = userPreferencesConfigurator; } + /** Tests for this method are in KubernetesFactoryTest. */ public KubernetesNamespaceMeta provision(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { KubernetesNamespace namespace = diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java index e51309fa2a..d8c99c683f 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; @@ -86,6 +87,9 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesCl import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.NamespaceProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -136,6 +140,9 @@ public class KubernetesNamespaceFactoryTest { @Mock private NamespaceList namespaceList; + @Mock private UserProfileConfigurator userProfileConfigurator; + @Mock private UserPreferencesConfigurator userPreferencesConfigurator; + @BeforeMethod public void setUp() throws Exception { serverMock = new KubernetesServer(true, true); @@ -1248,7 +1255,7 @@ public class KubernetesNamespaceFactoryTest { // when NamespaceResolutionContext context = new NamespaceResolutionContext("workspace123", "user123", "jondoe"); - KubernetesNamespaceMeta actual = namespaceFactory.provision(context); + KubernetesNamespaceMeta actual = testProvisioning(context); // then assertEquals(actual.getName(), "jondoe-che"); @@ -1288,7 +1295,7 @@ public class KubernetesNamespaceFactoryTest { // when NamespaceResolutionContext context = new NamespaceResolutionContext("workspace123", "user123", "jondoe"); - namespaceFactory.provision(context); + testProvisioning(context); // then fail("should not reach this point since exception has to be thrown"); @@ -1329,7 +1336,8 @@ public class KubernetesNamespaceFactoryTest { // when NamespaceResolutionContext context = new NamespaceResolutionContext("workspace123", "user123", "jondoe"); - namespaceFactory.provision(context); + + testProvisioning(context); // then fail("should not reach this point since exception has to be thrown"); @@ -1535,4 +1543,13 @@ public class KubernetesNamespaceFactoryTest { .endStatus() .build(); } + + private KubernetesNamespaceMeta testProvisioning(NamespaceResolutionContext context) + throws InfrastructureException { + doNothing().when(userProfileConfigurator).configure(any()); + doNothing().when(userPreferencesConfigurator).configure(any()); + return new NamespaceProvisioner( + namespaceFactory, userProfileConfigurator, userPreferencesConfigurator) + .provision(context); + } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java new file mode 100644 index 0000000000..a6bfaca9e6 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java @@ -0,0 +1,113 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.user.server.PreferenceManager; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** + * Tests for {@link UserPreferencesConfigurator}. + * + * @author Pavol Baran + */ +@Listeners(MockitoTestNGListener.class) +public class UserPreferencesConfiguratorTest { + + private static final String USER_ID = "user-id"; + private static final String USER_NAME = "user-name"; + private static final String USER_EMAIL = "user-email"; + private static final String USER_NAMESPACE = "user-namespace"; + + @Mock private KubernetesNamespaceFactory namespaceFactory; + @Mock private KubernetesClientFactory clientFactory; + @Mock private UserManager userManager; + @Mock private PreferenceManager preferenceManager; + + @InjectMocks private UserPreferencesConfigurator userPreferencesConfigurator; + + private KubernetesServer kubernetesServer; + private NamespaceResolutionContext context; + + @BeforeMethod + public void setUp() throws InfrastructureException, NotFoundException, ServerException { + context = new NamespaceResolutionContext(null, USER_ID, USER_NAME); + kubernetesServer = new KubernetesServer(true, true); + kubernetesServer.before(); + + Map preferences = new HashMap<>(); + preferences.put("preference-name", "preference"); + + lenient() + .when(userManager.getById(USER_ID)) + .thenReturn(new UserImpl(USER_ID, USER_EMAIL, USER_NAME)); + lenient().when(namespaceFactory.evaluateNamespaceName(any())).thenReturn(USER_NAMESPACE); + lenient().when(clientFactory.create()).thenReturn(kubernetesServer.getClient()); + lenient().when(preferenceManager.find(USER_ID)).thenReturn(preferences); + } + + @AfterMethod + public void cleanUp() { + kubernetesServer.after(); + } + + @Test + public void shouldCreatePreferencesSecret() throws InfrastructureException { + userPreferencesConfigurator.configure(context); + List secrets = + kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); + assertEquals(secrets.size(), 1); + assertEquals(secrets.get(0).getMetadata().getName(), "user-preferences"); + } + + @Test( + expectedExceptions = InfrastructureException.class, + expectedExceptionsMessageRegExp = + "Preferences of user with id:" + USER_ID + " cannot be retrieved.") + public void shouldNotCreateSecretOnException() throws ServerException, InfrastructureException { + when(preferenceManager.find(USER_ID)).thenThrow(new ServerException("test exception")); + userPreferencesConfigurator.configure(context); + fail("InfrastructureException should have been thrown."); + } + + @Test + public void shouldNormalizePreferenceName() { + assertEquals( + userPreferencesConfigurator.normalizePreferenceName("codename:bond"), "codename-bond"); + assertEquals(userPreferencesConfigurator.normalizePreferenceName("some--:pref"), "some-pref"); + assertEquals( + userPreferencesConfigurator.normalizePreferenceName("pref[name].sub"), "pref-name-.sub"); + } + + @Test + public void shouldKeepPreferenceName() { + assertEquals( + userPreferencesConfigurator.normalizePreferenceName("codename.bond"), "codename.bond"); + assertEquals(userPreferencesConfigurator.normalizePreferenceName("pref_name"), "pref_name"); + assertEquals( + userPreferencesConfigurator.normalizePreferenceName("some-name.over_rainbow"), + "some-name.over_rainbow"); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java new file mode 100644 index 0000000000..288587e490 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java @@ -0,0 +1,82 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import java.util.List; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.user.server.UserManager; +import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** + * Tests for {@link UserProfileConfigurator}. + * + * @author Pavol Baran + */ +@Listeners(MockitoTestNGListener.class) +public class UserProfileConfiguratorTest { + private static final String USER_ID = "user-id"; + private static final String USER_NAME = "user-name"; + private static final String USER_EMAIL = "user-email"; + private static final String USER_NAMESPACE = "user-namespace"; + + @Mock private KubernetesNamespaceFactory namespaceFactory; + @Mock private KubernetesClientFactory clientFactory; + @Mock private UserManager userManager; + + @InjectMocks private UserProfileConfigurator userProfileConfigurator; + + private KubernetesServer kubernetesServer; + private NamespaceResolutionContext context; + + @BeforeMethod + public void setUp() throws InfrastructureException, NotFoundException, ServerException { + context = new NamespaceResolutionContext(null, USER_ID, USER_NAME); + kubernetesServer = new KubernetesServer(true, true); + kubernetesServer.before(); + + when(userManager.getById(USER_ID)).thenReturn(new UserImpl(USER_ID, USER_EMAIL, USER_NAME)); + when(namespaceFactory.evaluateNamespaceName(any())).thenReturn(USER_NAMESPACE); + when(clientFactory.create()).thenReturn(kubernetesServer.getClient()); + } + + @AfterMethod + public void cleanUp() { + kubernetesServer.after(); + } + + @Test + public void shouldCreateProfileSecret() throws InfrastructureException { + userProfileConfigurator.configure(context); + List secrets = + kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); + assertEquals(secrets.size(), 1); + assertEquals(secrets.get(0).getMetadata().getName(), "user-profile"); + } + + @Test( + expectedExceptions = InfrastructureException.class, + expectedExceptionsMessageRegExp = "Could not find current user with id:" + USER_ID + ".") + public void shouldNotCreateSecretOnException() + throws NotFoundException, ServerException, InfrastructureException { + when(userManager.getById(USER_ID)).thenThrow(new ServerException("test exception")); + userProfileConfigurator.configure(context); + fail("InfrastructureException should have been thrown."); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java deleted file mode 100644 index 420df065b0..0000000000 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisionerTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2012-2021 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.workspace.infrastructure.kubernetes.provision; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.client.server.mock.KubernetesServer; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.user.server.PreferenceManager; -import org.eclipse.che.api.user.server.UserManager; -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -@Listeners(MockitoTestNGListener.class) -public class NamespaceProvisionerTest { - - @Mock private KubernetesNamespaceFactory namespaceFactory; - @Mock private KubernetesClientFactory clientFactory; - @Mock private UserManager userManager; - @Mock private PreferenceManager preferenceManager; - @InjectMocks private NamespaceProvisioner namespaceProvisioner; - - private static final String USER_ID = "user-id"; - private static final String USER_NAME = "user-name"; - private static final String USER_EMAIL = "user-email"; - private static final String USER_NAMESPACE = "user-namespace"; - - private KubernetesServer kubernetesServer; - - @BeforeMethod - public void setUp() throws InfrastructureException, NotFoundException, ServerException { - kubernetesServer = new KubernetesServer(true, true); - kubernetesServer.before(); - - Map preferences = new HashMap<>(); - preferences.put("preference-name", "preference"); - - lenient().when(clientFactory.create()).thenReturn(kubernetesServer.getClient()); - lenient() - .when(namespaceFactory.provision(any())) - .thenReturn(new KubernetesNamespaceMetaImpl(USER_NAMESPACE, Collections.emptyMap())); - lenient() - .when(userManager.getById(USER_ID)) - .thenReturn(new UserImpl(USER_ID, USER_EMAIL, USER_NAME)); - lenient().when(namespaceFactory.evaluateNamespaceName(any())).thenReturn(USER_NAMESPACE); - lenient().when(preferenceManager.find(USER_ID)).thenReturn(preferences); - } - - @AfterMethod - public void cleanUp() { - kubernetesServer.after(); - } - - @Test - public void shouldCreateSecretsOnNamespaceProvision() throws InfrastructureException { - namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); - List createdSecrets = - kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); - assertEquals(createdSecrets.size(), 2); - assertTrue( - createdSecrets - .stream() - .anyMatch(secret -> secret.getMetadata().getName().equals("user-profile"))); - assertTrue( - createdSecrets - .stream() - .anyMatch(secret -> secret.getMetadata().getName().equals("user-preferences"))); - } - - @Test - public void shouldCreateOnlyProfileSecret() throws InfrastructureException, ServerException { - when(preferenceManager.find(USER_ID)).thenReturn(Collections.emptyMap()); - namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); - List createdSecrets = - kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems(); - assertEquals(createdSecrets.size(), 1); - assertEquals(createdSecrets.get(0).getMetadata().getName(), "user-profile"); - } - - @Test(expectedExceptions = InfrastructureException.class) - public void shouldCreateNoSecretWithInvalidUser() - throws InfrastructureException, NotFoundException, ServerException { - when(userManager.getById(USER_ID)).thenThrow(new NotFoundException("Test exception")); - namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME)); - } - - @Test - public void shouldNormalizePreferenceName() { - assertEquals(namespaceProvisioner.normalizePreferenceName("codename:bond"), "codename-bond"); - assertEquals(namespaceProvisioner.normalizePreferenceName("some--:pref"), "some-pref"); - assertEquals(namespaceProvisioner.normalizePreferenceName("pref[name].sub"), "pref-name-.sub"); - } - - @Test - public void shouldKeepPreferenceName() { - assertEquals(namespaceProvisioner.normalizePreferenceName("codename.bond"), "codename.bond"); - assertEquals(namespaceProvisioner.normalizePreferenceName("pref_name"), "pref_name"); - assertEquals( - namespaceProvisioner.normalizePreferenceName("some-name.over_rainbow"), - "some-name.over_rainbow"); - } -} From e73266e957733aa7480f6e5e3da82bb8f790f77f Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 27 Sep 2021 11:54:44 +0200 Subject: [PATCH 15/18] refactor: replaced individual convigurators with set Signed-off-by: xbaran4 --- .../kubernetes/KubernetesInfraModule.java | 8 ++++++++ .../provision/NamespaceProvisioner.java | 17 +++++++---------- .../KubernetesNamespaceFactoryTest.java | 13 ++----------- .../UserPreferencesConfiguratorTest.java | 11 +++++++++++ .../UserProfileConfiguratorTest.java | 11 +++++++++++ 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 3d2d9b7673..f520c54734 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -48,6 +48,9 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesDev import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.RemoveNamespaceOnWorkspaceRemove; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PerWorkspacePVCStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.UniqueWorkspacePVCStrategy; @@ -98,6 +101,11 @@ public class KubernetesInfraModule extends AbstractModule { workspaceAttributeValidators.addBinding().to(K8sInfraNamespaceWsAttributeValidator.class); workspaceAttributeValidators.addBinding().to(AsyncStorageModeValidator.class); + Multibinder namespaceConfigurators = + Multibinder.newSetBinder(binder(), NamespaceConfigurator.class); + namespaceConfigurators.addBinding().to(UserProfileConfigurator.class); + namespaceConfigurators.addBinding().to(UserPreferencesConfigurator.class); + bind(KubernetesNamespaceService.class); MapBinder factories = diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java index 032476ab26..eb96ea011a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/NamespaceProvisioner.java @@ -12,6 +12,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import io.fabric8.kubernetes.api.model.Namespace; +import java.util.Set; import javax.inject.Inject; import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; @@ -20,8 +21,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.Kubernetes import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; /** * Provisions the k8s {@link Namespace}. After provisioning, configures the namespace through {@link @@ -31,17 +30,14 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurato */ public class NamespaceProvisioner { private final KubernetesNamespaceFactory namespaceFactory; - private final UserProfileConfigurator userProfileConfigurator; - private final UserPreferencesConfigurator userPreferencesConfigurator; + private final Set namespaceConfigurators; @Inject public NamespaceProvisioner( KubernetesNamespaceFactory namespaceFactory, - UserProfileConfigurator userProfileConfigurator, - UserPreferencesConfigurator userPreferencesConfigurator) { + Set namespaceConfigurators) { this.namespaceFactory = namespaceFactory; - this.userProfileConfigurator = userProfileConfigurator; - this.userPreferencesConfigurator = userPreferencesConfigurator; + this.namespaceConfigurators = namespaceConfigurators; } /** Tests for this method are in KubernetesFactoryTest. */ @@ -68,7 +64,8 @@ public class NamespaceProvisioner { private void configureNamespace(NamespaceResolutionContext namespaceResolutionContext) throws InfrastructureException { - userProfileConfigurator.configure(namespaceResolutionContext); - userPreferencesConfigurator.configure(namespaceResolutionContext); + for (NamespaceConfigurator configurator : namespaceConfigurators) { + configurator.configure(namespaceResolutionContext); + } } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java index d8c99c683f..47ed7f0fb6 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceFactoryTest.java @@ -12,6 +12,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_INFRASTRUCTURE_NAMESPACE_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta.DEFAULT_ATTRIBUTE; @@ -23,7 +24,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; @@ -87,8 +87,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesCl import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.NamespaceProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool; import org.mockito.ArgumentCaptor; @@ -140,9 +138,6 @@ public class KubernetesNamespaceFactoryTest { @Mock private NamespaceList namespaceList; - @Mock private UserProfileConfigurator userProfileConfigurator; - @Mock private UserPreferencesConfigurator userPreferencesConfigurator; - @BeforeMethod public void setUp() throws Exception { serverMock = new KubernetesServer(true, true); @@ -1546,10 +1541,6 @@ public class KubernetesNamespaceFactoryTest { private KubernetesNamespaceMeta testProvisioning(NamespaceResolutionContext context) throws InfrastructureException { - doNothing().when(userProfileConfigurator).configure(any()); - doNothing().when(userPreferencesConfigurator).configure(any()); - return new NamespaceProvisioner( - namespaceFactory, userProfileConfigurator, userPreferencesConfigurator) - .provision(context); + return new NamespaceProvisioner(namespaceFactory, emptySet()).provision(context); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java index a6bfaca9e6..8bf7f86989 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfiguratorTest.java @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; import static org.mockito.ArgumentMatchers.any; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java index 288587e490..33d175742f 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserProfileConfiguratorTest.java @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2012-2021 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator; import static org.mockito.ArgumentMatchers.any; From a6059bfea59b4e7ace2378b47c6032c5b1986401 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 27 Sep 2021 15:38:38 +0200 Subject: [PATCH 16/18] fix: trimmed preference name Signed-off-by: xbaran4 --- .../namespace/configurator/UserPreferencesConfigurator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index e11c8b0b0c..1880b9b20f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -42,6 +42,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN public class UserPreferencesConfigurator implements NamespaceConfigurator { private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; + private static final int PREFERNCE_NAME_MAX_LENGTH = 253; private final KubernetesNamespaceFactory namespaceFactory; private final KubernetesClientFactory clientFactory; @@ -128,6 +129,8 @@ public class UserPreferencesConfigurator implements NamespaceConfigurator { */ @VisibleForTesting String normalizePreferenceName(String name) { - return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); + return name.replaceAll("[^-._a-zA-Z0-9]+", "-") + .replaceAll("-+", "-") + .substring(0, Math.min(name.length(), PREFERNCE_NAME_MAX_LENGTH)); } } From 0423215112eb39646278ee18dabc00775b58b2e6 Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Mon, 27 Sep 2021 16:49:23 +0200 Subject: [PATCH 17/18] fix: trimed preference name bug Signed-off-by: xbaran4 --- .../configurator/UserPreferencesConfigurator.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java index 1880b9b20f..fb69ac251b 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/configurator/UserPreferencesConfigurator.java @@ -42,7 +42,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesN public class UserPreferencesConfigurator implements NamespaceConfigurator { private static final String USER_PREFERENCES_SECRET_NAME = "user-preferences"; private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences"; - private static final int PREFERNCE_NAME_MAX_LENGTH = 253; + private static final int PREFERENCE_NAME_MAX_LENGTH = 253; private final KubernetesNamespaceFactory namespaceFactory; private final KubernetesClientFactory clientFactory; @@ -129,8 +129,7 @@ public class UserPreferencesConfigurator implements NamespaceConfigurator { */ @VisibleForTesting String normalizePreferenceName(String name) { - return name.replaceAll("[^-._a-zA-Z0-9]+", "-") - .replaceAll("-+", "-") - .substring(0, Math.min(name.length(), PREFERNCE_NAME_MAX_LENGTH)); + name = name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-"); + return name.substring(0, Math.min(name.length(), PREFERENCE_NAME_MAX_LENGTH)); } } From 8969d93bac44fcaee721f953b57de6c97ce0c98f Mon Sep 17 00:00:00 2001 From: xbaran4 Date: Wed, 29 Sep 2021 12:43:43 +0200 Subject: [PATCH 18/18] fix: added module binding in openshiftInfra Signed-off-by: xbaran4 --- .../infrastructure/openshift/OpenShiftInfraModule.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java index 2610d524e9..0bfd6c80f5 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java @@ -53,6 +53,9 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesDev import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PerWorkspacePVCStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.UniqueWorkspacePVCStrategy; @@ -110,6 +113,11 @@ public class OpenShiftInfraModule extends AbstractModule { workspaceAttributeValidators.addBinding().to(K8sInfraNamespaceWsAttributeValidator.class); workspaceAttributeValidators.addBinding().to(AsyncStorageModeValidator.class); + Multibinder namespaceConfigurators = + Multibinder.newSetBinder(binder(), NamespaceConfigurator.class); + namespaceConfigurators.addBinding().to(UserProfileConfigurator.class); + namespaceConfigurators.addBinding().to(UserPreferencesConfigurator.class); + bind(KubernetesNamespaceService.class); MapBinder factories =