forked from eclipse-che/che
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adjust gitconfig in case if git credentials file are going to be moun…
…ted into the workspace (eclipse-che#17445) * Adjust gitconfig in case if git credentials file are going to be mounted into the workspace (eclipse-che#17445) Signed-off-by: Sergii Kabashniuk <skabashniuk@redhat.com>
- Loading branch information
1 parent
1c31004
commit 262c076
Showing
5 changed files
with
391 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
...ace/infrastructure/kubernetes/provision/secret/GitCredentialStorageFileSecretApplier.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copyright (c) 2012-2018 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.secret; | ||
|
||
import static java.lang.String.format; | ||
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.SecretAsContainerResourceProvisioner.ANNOTATION_PREFIX; | ||
|
||
import com.google.common.annotations.Beta; | ||
import io.fabric8.kubernetes.api.model.ConfigMap; | ||
import io.fabric8.kubernetes.api.model.Secret; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import javax.inject.Inject; | ||
import javax.inject.Singleton; | ||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; | ||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.K8sVersion; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner; | ||
|
||
/** | ||
* An instance of {@link FileSecretApplier} that is trying to adjust the content of git-config that | ||
* was added by {@link GitConfigProvisioner}. The adjustment is adding configuration of git | ||
* credentials store, which is pointing to the file that is going to be mount to the container from | ||
* the secret. | ||
*/ | ||
@Beta | ||
@Singleton | ||
public class GitCredentialStorageFileSecretApplier extends FileSecretApplier { | ||
|
||
public static final String ANNOTATION_GIT_CREDENTIALS = | ||
ANNOTATION_PREFIX + "/" + "git-credential"; | ||
|
||
private static final String GIT_CREDENTIALS_FILE_STORE_PATTERN = | ||
"\n[credential]\n\thelper = store --file %s\n"; | ||
|
||
@Inject | ||
public GitCredentialStorageFileSecretApplier(K8sVersion k8sVersion) { | ||
super(k8sVersion); | ||
} | ||
|
||
@Override | ||
public void applySecret(KubernetesEnvironment env, RuntimeIdentity runtimeIdentity, Secret secret) | ||
throws InfrastructureException { | ||
super.applySecret(env, runtimeIdentity, secret); | ||
final String secretMountPath = secret.getMetadata().getAnnotations().get(ANNOTATION_MOUNT_PATH); | ||
Set<String> keys = secret.getData().keySet(); | ||
if (keys.size() != 1) { | ||
throw new InfrastructureException( | ||
format( | ||
"Invalid git credential secret data. It should contain only 1 data item but it have %d", | ||
keys.size())); | ||
} | ||
Path gitSecretFilePath = Paths.get(secretMountPath, keys.iterator().next()); | ||
ConfigMap gitConfigMap = | ||
env.getConfigMaps() | ||
.get( | ||
runtimeIdentity.getWorkspaceId() + GitConfigProvisioner.GIT_CONFIG_MAP_NAME_SUFFIX); | ||
if (gitConfigMap != null) { | ||
Map<String, String> gitConfigMapData = gitConfigMap.getData(); | ||
String gitConfig = gitConfigMapData.get(GitConfigProvisioner.GIT_CONFIG); | ||
if (gitConfig != null) { | ||
if (gitConfig.contains("helper = store --file") && gitConfig.contains("[credential]")) { | ||
throw new InfrastructureException( | ||
"Multiple git credentials secrets found. Please remove duplication."); | ||
} | ||
|
||
HashMap<String, String> newGitConfigMapData = new HashMap<>(gitConfigMapData); | ||
newGitConfigMapData.put( | ||
GitConfigProvisioner.GIT_CONFIG, | ||
String.format(GIT_CREDENTIALS_FILE_STORE_PATTERN, gitSecretFilePath.toString())); | ||
gitConfigMap.setData(newGitConfigMapData); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
...infrastructure/kubernetes/provision/secret/GitCredentialStorageFileSecretApplierTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* | ||
* Copyright (c) 2012-2018 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.secret; | ||
|
||
import static java.util.Collections.emptyMap; | ||
import static java.util.Collections.singletonMap; | ||
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.FileSecretApplier.ANNOTATION_MOUNT_PATH; | ||
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.KubernetesSecretApplier.ANNOTATION_AUTOMOUNT; | ||
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.SecretAsContainerResourceProvisioner.ANNOTATION_MOUNT_AS; | ||
import static org.mockito.Mockito.lenient; | ||
import static org.mockito.Mockito.when; | ||
import static org.testng.Assert.assertTrue; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
import io.fabric8.kubernetes.api.model.ConfigMap; | ||
import io.fabric8.kubernetes.api.model.ConfigMapBuilder; | ||
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; | ||
import io.fabric8.kubernetes.api.model.PodSpec; | ||
import io.fabric8.kubernetes.api.model.Secret; | ||
import io.fabric8.kubernetes.api.model.SecretBuilder; | ||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; | ||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.K8sVersion; | ||
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner; | ||
import org.mockito.Mock; | ||
import org.mockito.testng.MockitoTestNGListener; | ||
import org.testng.annotations.BeforeMethod; | ||
import org.testng.annotations.Listeners; | ||
import org.testng.annotations.Test; | ||
|
||
@Listeners(MockitoTestNGListener.class) | ||
public class GitCredentialStorageFileSecretApplierTest { | ||
|
||
@Mock private KubernetesEnvironment environment; | ||
|
||
@Mock private KubernetesEnvironment.PodData podData; | ||
|
||
@Mock private PodSpec podSpec; | ||
|
||
@Mock private RuntimeIdentity runtimeIdentity; | ||
|
||
@Mock private K8sVersion kubernetesVersion; | ||
|
||
GitCredentialStorageFileSecretApplier secretApplier; | ||
|
||
public static final String GIT_CONFIG_CONTENT = | ||
"[user]\n\tname = Michelangelo Merisi da Caravaggio\n\tmail = mcaravag@email.not.exists.com"; | ||
|
||
@BeforeMethod | ||
public void setUp() throws Exception { | ||
lenient().when(kubernetesVersion.newerOrEqualThan(1, 13)).thenReturn(true); | ||
lenient().when(kubernetesVersion.olderThan(1, 13)).thenReturn(false); | ||
secretApplier = new GitCredentialStorageFileSecretApplier(kubernetesVersion); | ||
when(environment.getPodsData()).thenReturn(singletonMap("pod1", podData)); | ||
when(podData.getRole()).thenReturn(KubernetesEnvironment.PodRole.DEPLOYMENT); | ||
when(podData.getSpec()).thenReturn(podSpec); | ||
when(runtimeIdentity.getWorkspaceId()).thenReturn("ws-1234598"); | ||
} | ||
|
||
@Test( | ||
expectedExceptions = InfrastructureException.class, | ||
expectedExceptionsMessageRegExp = | ||
"Invalid git credential secret data. It should contain only 1 data item but it have 2") | ||
public void shouldThrowInfrastructureExceptionIfSecretsHasMoreOrLessWhen1Data() | ||
throws InfrastructureException { | ||
// given | ||
Secret secret = | ||
new SecretBuilder() | ||
.withData(ImmutableMap.of("credentials", "random", "credentials2", "random")) | ||
.withMetadata( | ||
new ObjectMetaBuilder() | ||
.withName("test_secret") | ||
.withAnnotations( | ||
ImmutableMap.of( | ||
ANNOTATION_MOUNT_AS, | ||
"file", | ||
ANNOTATION_MOUNT_PATH, | ||
"/home/user/.git", | ||
GitCredentialStorageFileSecretApplier.ANNOTATION_GIT_CREDENTIALS, | ||
"true", | ||
ANNOTATION_AUTOMOUNT, | ||
"true")) | ||
.withLabels(emptyMap()) | ||
.build()) | ||
.build(); | ||
// when | ||
secretApplier.applySecret(environment, runtimeIdentity, secret); | ||
} | ||
|
||
@Test | ||
public void shouldBeAbleToAdjustGiConfigConfigMap() throws InfrastructureException { | ||
// given | ||
Secret secret = | ||
new SecretBuilder() | ||
.withData(ImmutableMap.of("credentials", "random")) | ||
.withMetadata( | ||
new ObjectMetaBuilder() | ||
.withName("test_secret") | ||
.withAnnotations( | ||
ImmutableMap.of( | ||
ANNOTATION_MOUNT_AS, | ||
"file", | ||
ANNOTATION_MOUNT_PATH, | ||
"/home/user/.git", | ||
GitCredentialStorageFileSecretApplier.ANNOTATION_GIT_CREDENTIALS, | ||
"true", | ||
ANNOTATION_AUTOMOUNT, | ||
"true")) | ||
.withLabels(emptyMap()) | ||
.build()) | ||
.build(); | ||
|
||
ConfigMap configMap = | ||
new ConfigMapBuilder() | ||
.withData(ImmutableMap.of(GitConfigProvisioner.GIT_CONFIG, GIT_CONFIG_CONTENT)) | ||
.build(); | ||
when(environment.getConfigMaps()) | ||
.thenReturn( | ||
ImmutableMap.of( | ||
"ws-1234598" + GitConfigProvisioner.GIT_CONFIG_MAP_NAME_SUFFIX, configMap)); | ||
// when | ||
secretApplier.applySecret(environment, runtimeIdentity, secret); | ||
// then | ||
String data = configMap.getData().get(GitConfigProvisioner.GIT_CONFIG); | ||
assertTrue( | ||
data.endsWith("[credential]\n\thelper = store --file /home/user/.git/credentials\n")); | ||
} | ||
|
||
@Test( | ||
expectedExceptions = InfrastructureException.class, | ||
expectedExceptionsMessageRegExp = | ||
"Multiple git credentials secrets found. Please remove duplication.") | ||
public void shouldThrowInfrastructureExceptionIfGitConfigAlreadyContainsSecretConfig() | ||
throws InfrastructureException { | ||
// given | ||
Secret secret = | ||
new SecretBuilder() | ||
.withData(ImmutableMap.of("credentials", "random")) | ||
.withMetadata( | ||
new ObjectMetaBuilder() | ||
.withName("test_secret") | ||
.withAnnotations( | ||
ImmutableMap.of( | ||
ANNOTATION_MOUNT_AS, | ||
"file", | ||
ANNOTATION_MOUNT_PATH, | ||
"/home/user/.git", | ||
GitCredentialStorageFileSecretApplier.ANNOTATION_GIT_CREDENTIALS, | ||
"true", | ||
ANNOTATION_AUTOMOUNT, | ||
"true")) | ||
.withLabels(emptyMap()) | ||
.build()) | ||
.build(); | ||
|
||
ConfigMap configMap = | ||
new ConfigMapBuilder() | ||
.withData( | ||
ImmutableMap.of( | ||
GitConfigProvisioner.GIT_CONFIG, | ||
GIT_CONFIG_CONTENT | ||
+ "[credential]\n\thelper = store --file /home/user/.git/credentials\n")) | ||
.build(); | ||
when(environment.getConfigMaps()) | ||
.thenReturn( | ||
ImmutableMap.of( | ||
"ws-1234598" + GitConfigProvisioner.GIT_CONFIG_MAP_NAME_SUFFIX, configMap)); | ||
// when | ||
secretApplier.applySecret(environment, runtimeIdentity, secret); | ||
} | ||
} |
Oops, something went wrong.