Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Removing dependency on usr, accout, profile db entries #398

Merged
merged 2 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
Expand Down Expand Up @@ -41,10 +41,8 @@
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.inject.Named;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.ValidationException;
import org.eclipse.che.api.core.model.user.User;
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;
Expand Down Expand Up @@ -275,30 +273,21 @@ private KubernetesNamespaceMeta asNamespaceMeta(Namespace namespace) {
* the context.
*
* @param identity the identity of the workspace runtime
* @param userName the user name
* @return true if the namespace can be created, false if the namespace is expected to already
* exist
* @throws InfrastructureException on failure
*/
protected boolean canCreateNamespace(RuntimeIdentity identity) throws InfrastructureException {
protected boolean canCreateNamespace(RuntimeIdentity identity, String userName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I look at canCreateNamespace and getOrCreate I would consider

  • Add username to both methods
  • Or add username/ownerName to RuntimeIdentity
    Since RuntimeIdentity has already ownerId I think second option is better

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also thought about that, but this would require quite a few changes in the obsolete classes like PluginBrokerManager which are planned to be removed completely in Phase 2 of the db removal procedure. The goal of this PR is to make all the stored data in Postgres irrelevant. In the future PR, major cleanup / refactoring is going to happen when the whole DAO layer will be removed completely (currently targeted for 7.61)

throws InfrastructureException {
if (!namespaceCreationAllowed) {
return false;
}

// we need to make sure that the provided namespace is indeed the one provided by our
// configuration
User owner;
try {
owner = userManager.getById(identity.getOwnerId());
} catch (NotFoundException | ServerException e) {
throw new InfrastructureException(
"Failed to resolve workspace owner. Cause: " + e.getMessage(), e);
}

String requiredNamespace = identity.getInfrastructureNamespace();

NamespaceResolutionContext resolutionContext =
new NamespaceResolutionContext(
identity.getWorkspaceId(), identity.getOwnerId(), owner.getName());
new NamespaceResolutionContext(identity.getWorkspaceId(), identity.getOwnerId(), userName);

String resolvedDefaultNamespace = evaluateNamespaceName(resolutionContext);

Expand All @@ -320,14 +309,14 @@ public KubernetesNamespace getOrCreate(RuntimeIdentity identity) throws Infrastr
KubernetesNamespace namespace = get(identity);

var subject = EnvironmentContext.getCurrent().getSubject();
var userName = subject.getUserName();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment to canCreateNamespace method

NamespaceResolutionContext resolutionCtx =
new NamespaceResolutionContext(
identity.getWorkspaceId(), subject.getUserId(), subject.getUserName());
new NamespaceResolutionContext(identity.getWorkspaceId(), subject.getUserId(), userName);
Map<String, String> namespaceAnnotationsEvaluated =
evaluateAnnotationPlaceholders(resolutionCtx);

namespace.prepare(
canCreateNamespace(identity),
canCreateNamespace(identity, userName),
labelNamespaces ? namespaceLabels : emptyMap(),
annotateNamespaces ? namespaceAnnotationsEvaluated : emptyMap());

Expand Down Expand Up @@ -515,9 +504,6 @@ private String evalDefaultNamespace(NamespaceResolutionContext resolutionCtx)
"Evaluated the namespace for workspace {} using the namespace default to {}",
resolutionCtx.getWorkspaceId(),
namespace);

recordEvaluatedNamespaceName(namespace, resolutionCtx);

return namespace;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Collections.singletonMap;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.AbstractWorkspaceServiceAccount.GIT_USERDATA_CONFIGMAP_NAME;

Expand All @@ -21,18 +20,13 @@
import java.util.Map;
import java.util.Set;
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.factory.server.scm.GitUserData;
import org.eclipse.che.api.factory.server.scm.GitUserDataFetcher;
import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException;
import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException;
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.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -80,17 +74,6 @@ public void configure(NamespaceResolutionContext namespaceResolutionContext, Str
"true",
"controller.devfile.io/watch-configmap",
"true");
if (gitUserData == null) {
Subject cheSubject = EnvironmentContext.getCurrent().getSubject();
try {
User user = userManager.getById(cheSubject.getUserId());
if (!isNullOrEmpty(user.getName()) && !isNullOrEmpty(user.getEmail())) {
gitUserData = new GitUserData(user.getName(), user.getEmail());
}
} catch (NotFoundException | ServerException e) {
LOG.error(e.getMessage());
}
}
if (gitUserData != null
&& client
.configMaps()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
Expand All @@ -11,36 +11,27 @@
*/
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 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 javax.inject.Singleton;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Creates {@link Secret} with user preferences. This serves as a way for DevWorkspaces to acquire
* information about the user.
*
* @author Pavol Baran
*/
@Deprecated
@Singleton
public class UserPreferencesConfigurator implements NamespaceConfigurator {
private static final Logger LOG = LoggerFactory.getLogger(UserProfileConfigurator.class);
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 PREFERENCE_NAME_MAX_LENGTH = 253;
Expand All @@ -60,60 +51,9 @@ public UserPreferencesConfigurator(
}

@Override
public void configure(NamespaceResolutionContext namespaceResolutionContext, String namespaceName)
throws InfrastructureException {
Secret userPreferencesSecret = preparePreferencesSecret(namespaceResolutionContext);

try {
clientFactory
.create()
.secrets()
.inNamespace(namespaceName)
.createOrReplace(userPreferencesSecret);
} catch (KubernetesClientException e) {
throw new InfrastructureException(
"Error occurred while trying to create user preferences secret.", e);
}
}

private Secret preparePreferencesSecret(NamespaceResolutionContext namespaceResolutionContext)
throws InfrastructureException {
Base64.Encoder enc = Base64.getEncoder();
User user;
Map<String, String> preferences;

try {
user = userManager.getById(namespaceResolutionContext.getUserId());
preferences = preferenceManager.find(user.getId());
} catch (NotFoundException | ServerException 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(
String.format(
"Preferences of user with id:%s are empty. Cannot create user preferences secrets.",
namespaceResolutionContext.getUserId()));
}

Map<String, String> 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();
public void configure(
NamespaceResolutionContext namespaceResolutionContext, String namespaceName) {
LOG.debug("'user-preferences' secret is obsolete and not configured anymore for DevWorkspaces");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
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;
Expand Down Expand Up @@ -70,21 +67,15 @@ public void configure(NamespaceResolutionContext namespaceResolutionContext, Str

private Secret prepareProfileSecret(NamespaceResolutionContext namespaceResolutionContext)
throws InfrastructureException {
User user;
try {
user = userManager.getById(namespaceResolutionContext.getUserId());
} catch (NotFoundException | ServerException e) {
throw new InfrastructureException(
String.format(
"Could not find current user with id:%s.", namespaceResolutionContext.getUserId()),
e);
}
var userId = namespaceResolutionContext.getUserId();
var userName = namespaceResolutionContext.getUserName();
var userEmail = userName + "@che";

Base64.Encoder enc = Base64.getEncoder();
final Map<String, String> 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()));
userProfileData.put("id", enc.encodeToString(userId.getBytes()));
userProfileData.put("name", enc.encodeToString(userName.getBytes()));
userProfileData.put("email", enc.encodeToString(userEmail.getBytes()));

return new SecretBuilder()
.addToData(userProfileData)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator;

import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.AbstractWorkspaceServiceAccount.GIT_USERDATA_CONFIGMAP_NAME;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

Expand All @@ -25,9 +23,6 @@
import java.util.Collections;
import java.util.Map;
import java.util.Set;
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.factory.server.scm.GitUserData;
import org.eclipse.che.api.factory.server.scm.GitUserDataFetcher;
import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException;
Expand Down Expand Up @@ -95,19 +90,6 @@ public void createUserdataConfigmapWhenDoesNotExist()
.get());
}

@Test
public void doNothingWhenGitUserDataAndCheUserAreNull()
throws InfrastructureException, ServerException, NotFoundException {
// when
when(userManager.getById(anyString())).thenThrow(new NotFoundException("not found"));
configurator.configure(namespaceResolutionContext, TEST_NAMESPACE_NAME);

// then - don't create the configmap
var configMaps =
serverMock.getClient().configMaps().inNamespace(TEST_NAMESPACE_NAME).list().getItems();
Assert.assertEquals(configMaps.size(), 0);
}

@Test
public void doNothingWhenSecretAlreadyExists()
throws InfrastructureException, InterruptedException, ScmCommunicationException,
Expand Down Expand Up @@ -151,30 +133,4 @@ public void doNothingWhenSecretAlreadyExists()
Assert.assertEquals(configMaps.size(), 1);
Assert.assertEquals(configMaps.get(0).getMetadata().getAnnotations().get("already"), "created");
}

@Test
public void createUserdataConfigmapFromCheUserData()
throws InfrastructureException, ServerException, NotFoundException, InterruptedException {
// given
User user = mock(User.class);
when(user.getName()).thenReturn("test name");
when(user.getEmail()).thenReturn("test@email.com");
when(userManager.getById(anyString())).thenReturn(user);

// when
configurator.configure(namespaceResolutionContext, TEST_NAMESPACE_NAME);

// then create a secret
Assert.assertEquals(serverMock.getLastRequest().getMethod(), "POST");
ConfigMap configMap =
serverMock
.getClient()
.configMaps()
.inNamespace(TEST_NAMESPACE_NAME)
.withName(GIT_USERDATA_CONFIGMAP_NAME)
.get();
Assert.assertNotNull(configMap);
Assert.assertTrue(configMap.getData().get("gitconfig").contains("test name"));
Assert.assertTrue(configMap.getData().get("gitconfig").contains("test@email.com"));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
Expand All @@ -13,14 +13,10 @@

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;
Expand Down Expand Up @@ -84,25 +80,6 @@ public void cleanUp() {
kubernetesServer.after();
}

@Test
public void shouldCreatePreferencesSecret() throws InfrastructureException {
userPreferencesConfigurator.configure(context, USER_NAMESPACE);
List<Secret> 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, USER_NAMESPACE);
fail("InfrastructureException should have been thrown.");
}

@Test
public void shouldNormalizePreferenceName() {
assertEquals(
Expand Down
Loading