From df648f56f188afc6fe24838bf4903cb49eebc8c3 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 3 Nov 2020 20:11:20 +0100 Subject: [PATCH] Also copy the content of the truststore config map to the workspace namespace (#18264) * Allow copying also the content of the config map * Use the `CheServerKubernetesClientFactory` to have the permission to read the config map from the Che server namespace * Move constructor parameters as requested by @mshaposhnik * Additional change requested by @mshaposhnik Signed-off-by: David Festal --- .../Openshift4TrustedCAProvisioner.java | 36 ++++++- .../Openshift4TrustedCAProvisionerTest.java | 94 +++++++++++++++---- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java index 7cf713110e8..210508fc12c 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java @@ -14,6 +14,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; import com.google.common.base.Splitter; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; @@ -21,11 +22,14 @@ import io.fabric8.kubernetes.api.model.VolumeBuilder; import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import java.util.Map; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodRole; @@ -43,19 +47,28 @@ public class Openshift4TrustedCAProvisioner { private final String certificateMountPath; private final boolean trustedStoreInitialized; + private final String caBundleConfigMap; private final String configMapName; private final Map configMapLabelKeyValue; + private final CheServerKubernetesClientFactory cheServerClientFactory; + private final String installationLocationNamespace; @Inject public Openshift4TrustedCAProvisioner( @Nullable @Named("che.trusted_ca_bundles_configmap") String caBundleConfigMap, @Named("che.infra.openshift.trusted_ca_bundles_config_map") String configMapName, @Named("che.infra.openshift.trusted_ca_bundles_config_map_labels") String configMapLabel, - @Named("che.infra.openshift.trusted_ca_bundles_mount_path") String certificateMountPath) { + @Named("che.infra.openshift.trusted_ca_bundles_mount_path") String certificateMountPath, + CheInstallationLocation cheInstallationLocation, + CheServerKubernetesClientFactory cheServerClientFactory) + throws InfrastructureException { + this.cheServerClientFactory = cheServerClientFactory; this.trustedStoreInitialized = !isNullOrEmpty(caBundleConfigMap); this.configMapName = configMapName; + this.caBundleConfigMap = caBundleConfigMap; this.certificateMountPath = certificateMountPath; this.configMapLabelKeyValue = Splitter.on(",").withKeyValueSeparator("=").split(configMapLabel); + this.installationLocationNamespace = cheInstallationLocation.getInstallationLocationNamespace(); } public boolean isTrustedStoreInitialized() { @@ -67,9 +80,22 @@ public void provision(KubernetesEnvironment k8sEnv, OpenShiftProject project) if (!trustedStoreInitialized) { return; } + ConfigMap configMap = + cheServerClientFactory + .create() + .configMaps() + .inNamespace(installationLocationNamespace) + .withName(caBundleConfigMap) + .get(); + + if (configMap == null) { + return; + } + + Optional existing = project.configMaps().get(configMapName); - if (!project.configMaps().get(configMapName).isPresent()) { - // create new map + if (!existing.isPresent() || !existing.get().getData().equals(configMap.getData())) { + // create or renew map k8sEnv .getConfigMaps() .put( @@ -78,10 +104,14 @@ public void provision(KubernetesEnvironment k8sEnv, OpenShiftProject project) .withMetadata( new ObjectMetaBuilder() .withName(configMapName) + .withAnnotations(configMap.getMetadata().getAnnotations()) .withLabels(configMapLabelKeyValue) .build()) + .withApiVersion(configMap.getApiVersion()) + .withData(configMap.getData()) .build()); } + for (PodData pod : k8sEnv.getPodsData().values()) { if (pod.getRole() == PodRole.DEPLOYMENT) { if (pod.getSpec() diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java index 919eb9d3b4b..dbf81eb3bd6 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java @@ -12,26 +12,34 @@ package org.eclipse.che.workspace.infrastructure.openshift.provision; import static com.google.common.collect.ImmutableMap.of; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.verifyZeroInteractions; import static org.testng.Assert.assertEquals; 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.ConfigMapList; import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.DoneableConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.openshift.client.OpenShiftClient; import java.util.HashMap; import java.util.Map; +import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps; -import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory; import org.eclipse.che.workspace.infrastructure.openshift.project.OpenShiftProject; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -48,12 +56,41 @@ public class Openshift4TrustedCAProvisionerTest { private static final String CERTIFICATE_MOUNT_PATH = "/certs"; private static final String CONFIGMAP_KEY = "testConfigMapKey"; private static final String CONFIGMAP_VALUE = "testConfigMapValue"; + private static final String CHE_SERVER_NAMESPACE = "testCheServerNamespace"; + private static final String INJECTED_CA_BUNDLE_KEY = "ca-bundle.crt"; + private static final String INJECTED_CA_BUNDLE_VALUE = "ca-bundle.crt.content"; + private static final String MANUAL_CA_BUNDLE_KEY = "manual-ca.crt"; + private static final String MANUAL_CA_BUNDLE_VALUE = "maunal-ca.crt.content"; - @Mock OpenShiftClientFactory clientFactory; + @Mock CheServerKubernetesClientFactory clientFactory; @Mock private KubernetesEnvironment k8sEnv; @Mock private OpenShiftProject openShiftProject; @Mock private KubernetesConfigsMaps kubernetesConfigsMaps; + @Mock private CheInstallationLocation cheInstallationLocation; + + @Mock + private MixedOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + cheServerConfigMapGetter1; + + @Mock + private NonNamespaceOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + cheServerConfigMapGetter2; + + @Mock private Resource cheServerConfigMapResource; + @Mock private ConfigMap cheServerConfigMap; + @Mock private ObjectMeta cheServerConfigMapMetadata; + + private Map cheServerConfigMapData = + ImmutableMap.of( + INJECTED_CA_BUNDLE_KEY, INJECTED_CA_BUNDLE_VALUE, + MANUAL_CA_BUNDLE_KEY, MANUAL_CA_BUNDLE_VALUE); + + private Map cheServerConfigMapAnnotations = + ImmutableMap.of( + "testCheServerConfigMapAnnotationsKey", "testCheServerConfigMapAnnotationsValue"); @Mock private OpenShiftClient k8sClient; @@ -63,22 +100,49 @@ public class Openshift4TrustedCAProvisionerTest { @BeforeMethod public void setup() throws Exception { - lenient().when(clientFactory.createOC()).thenReturn(k8sClient); + lenient().when(clientFactory.create()).thenReturn(k8sClient); lenient().when(openShiftProject.configMaps()).thenReturn(kubernetesConfigsMaps); + lenient() + .when(cheInstallationLocation.getInstallationLocationNamespace()) + .thenReturn(CHE_SERVER_NAMESPACE); lenient().when(k8sEnv.getConfigMaps()).thenReturn(envConfigMaps); + lenient().when(k8sClient.configMaps()).thenReturn(cheServerConfigMapGetter1); + lenient() + .when(cheServerConfigMapGetter1.inNamespace(CHE_SERVER_NAMESPACE)) + .thenReturn(cheServerConfigMapGetter2); + lenient() + .when(cheServerConfigMapGetter2.withName(anyString())) + .thenReturn(cheServerConfigMapResource); + lenient().when(cheServerConfigMap.getData()).thenReturn(cheServerConfigMapData); + lenient().when(cheServerConfigMap.getMetadata()).thenReturn(cheServerConfigMapMetadata); + lenient() + .when(cheServerConfigMapMetadata.getAnnotations()) + .thenReturn(cheServerConfigMapAnnotations); + this.trustedCAProvisioner = new Openshift4TrustedCAProvisioner( - CONFIGMAP_NAME, CONFIGMAP_NAME, CONFIGMAP_LABELS, CERTIFICATE_MOUNT_PATH); + CONFIGMAP_NAME, + CONFIGMAP_NAME, + CONFIGMAP_LABELS, + CERTIFICATE_MOUNT_PATH, + cheInstallationLocation, + clientFactory); } @Test public void shouldDoNothingIfCAStoreIsNotInitialized() throws Exception { Openshift4TrustedCAProvisioner localProvisioner = new Openshift4TrustedCAProvisioner( - null, CONFIGMAP_NAME, CONFIGMAP_LABELS, CERTIFICATE_MOUNT_PATH); + null, + CONFIGMAP_NAME, + CONFIGMAP_LABELS, + CERTIFICATE_MOUNT_PATH, + cheInstallationLocation, + clientFactory); localProvisioner.provision(k8sEnv, openShiftProject); - verifyZeroInteractions(k8sEnv, openShiftProject, clientFactory, openShiftProject); + verifyZeroInteractions( + k8sEnv, openShiftProject, clientFactory, openShiftProject, clientFactory); } @Test @@ -86,12 +150,18 @@ public void shouldProvisionTrustStoreMapAndMountIt() throws Exception { Pod pod = newPod(); PodData podData = new PodData(pod.getSpec(), pod.getMetadata()); doReturn(of(POD_NAME, podData)).when(k8sEnv).getPodsData(); + lenient().when(cheServerConfigMapResource.get()).thenReturn(cheServerConfigMap); trustedCAProvisioner.provision(k8sEnv, openShiftProject); assertEquals(envConfigMaps.size(), 1); assertTrue(envConfigMaps.get(CONFIGMAP_NAME).getMetadata().getLabels().containsKey("foo")); assertEquals(envConfigMaps.get(CONFIGMAP_NAME).getMetadata().getLabels().get("foo"), "bar"); + assertEquals( + envConfigMaps.get(CONFIGMAP_NAME).getMetadata().getAnnotations(), + cheServerConfigMapAnnotations); + assertEquals(envConfigMaps.get(CONFIGMAP_NAME).getData(), cheServerConfigMapData); + PodSpec podSpec = pod.getSpec(); assertEquals(podSpec.getVolumes().size(), 1); assertEquals(podSpec.getVolumes().get(0).getConfigMap().getName(), CONFIGMAP_NAME); @@ -111,14 +181,4 @@ private static Pod newPod() { .endSpec() .build(); } - - private static ConfigMap newConfigMap() { - return new ConfigMapBuilder() - .withNewMetadata() - .withName(CONFIGMAP_NAME) - .withLabels(of("foo", "bar")) - .endMetadata() - .withData(of(CONFIGMAP_KEY, CONFIGMAP_VALUE)) - .build(); - } }