FileSecretApplier extends KubernetesSecretApplier<KubernetesEnvironment> { @Override public void applySecret(KubernetesEnvironment env, RuntimeIdentity runtimeIdentity, Secret secret) throws InfrastructureException { final String secretMountPath = secret.getMetadata().getAnnotations().get(ANNOTATION_MOUNT_PATH); boolean secretAutomount = Boolean.parseBoolean(secret.getMetadata().getAnnotations().get(ANNOTATION_AUTOMOUNT)); if (secretMountPath == null) { throw new InfrastructureException( format( "Unable to mount secret '%s': It is configured to be mounted as a file but the mount path was not specified. Please define the '%s' annotation on the secret to specify it.", secret.getMetadata().getName(), ANNOTATION_MOUNT_PATH)); } Volume volumeFromSecret = new VolumeBuilder() .withName(secret.getMetadata().getName()) .withSecret( new SecretVolumeSourceBuilder() .withNewSecretName(secret.getMetadata().getName()) .build()) .build(); for (PodData podData : env.getPodsData().values()) { if (!podData.getRole().equals(PodRole.DEPLOYMENT)) { continue; } if (podData .getSpec() .getVolumes() .stream() .anyMatch(v -> v.getName().equals(volumeFromSecret.getName()))) { volumeFromSecret.setName(volumeFromSecret.getName() + "_" + NameGenerator.generate("", 6)); } podData.getSpec().getVolumes().add(volumeFromSecret); for (Container container : podData.getSpec().getContainers()) { Optional<ComponentImpl> component = getComponent(env, container.getName()); if (component.isPresent() && isComponentAutomountFalse(component.get())) { continue; } if (!secretAutomount && (!component.isPresent() || !isComponentAutomountTrue(component.get()))) { continue; } Optional<String> overridePathOptional = Optional.empty(); if (component.isPresent()) { overridePathOptional = getOverridenComponentPath(component.get(), secret.getMetadata().getName()); } final String componentMountPath = overridePathOptional.orElse(secretMountPath); if (k8sVersion.olderThan(1, 13)) { LOG.debug( "Unable to mount multiple VolumeMounts on same path on this k8s version. Removing conflicting volumes in favor of secret mounts."); container .getVolumeMounts() .removeIf(vm -> Paths.get(vm.getMountPath()).equals(Paths.get(componentMountPath))); } container .getVolumeMounts() .addAll( secret .getData() .keySet() .stream() .map( secretFile -> buildVolumeMount(volumeFromSecret, componentMountPath, secretFile)) .collect(Collectors.toList())); } } } @Inject  FileSecretApplier(K8sVersion k8sVersion); @Override void applySecret(KubernetesEnvironment env, RuntimeIdentity runtimeIdentity, Secret secret);  }
@Test public void shouldNotOverrideExistingVolumeMounts() throws InfrastructureException { Container container_match1 = new ContainerBuilder() .withName("maven") .withVolumeMounts( new VolumeMountBuilder() .withName("existing-volume") .withMountPath("/home/user/.m2") .build()) .build(); PodSpec localSpec = new PodSpecBuilder().withContainers(ImmutableList.of(container_match1)).build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 2); VolumeMount mount1 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(mount1.getName(), "existing-volume"); assertEquals(mount1.getMountPath(), "/home/user/.m2"); assertNull(mount1.getSubPath()); VolumeMount mount2 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(1); assertEquals(mount2.getName(), "test_secret"); assertEquals(mount2.getMountPath(), "/home/user/.m2/settings.xml"); assertEquals(mount2.getSubPath(), "settings.xml"); }
@Test public void shouldOverrideExistingVolumeMountsOnOlderK8s() throws InfrastructureException { lenient().when(kubernetesVersion.newerOrEqualThan(1, 13)).thenReturn(false); lenient().when(kubernetesVersion.olderThan(1, 13)).thenReturn(true); Container container_match1 = new ContainerBuilder() .withName("maven") .withVolumeMounts( new VolumeMountBuilder() .withName("existing-volume") .withMountPath("/home/user/.m2") .build()) .build(); PodSpec localSpec = new PodSpecBuilder().withContainers(ImmutableList.of(container_match1)).build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 1); VolumeMount secretMount = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(secretMount.getName(), "test_secret"); assertEquals(secretMount.getMountPath(), "/home/user/.m2"); assertNull(secretMount.getSubPath()); }
@Test public void shouldProvisionAsFiles() throws Exception { Container container_match1 = new ContainerBuilder().withName("maven").build(); Container container_match2 = new ContainerBuilder().withName("other").build(); PodSpec localSpec = new PodSpecBuilder() .withContainers(ImmutableList.of(container_match1, container_match2)) .build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random", "another.xml", "freedom")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 2); VolumeMount mount1 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(mount1.getName(), "test_secret"); assertEquals(mount1.getMountPath(), "/home/user/.m2/" + mount1.getSubPath()); assertFalse(mount1.getSubPath().isEmpty()); assertTrue(mount1.getReadOnly()); VolumeMount mount2 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(1); assertEquals(mount2.getName(), "test_secret"); assertEquals(mount2.getMountPath(), "/home/user/.m2/" + mount2.getSubPath()); assertFalse(mount2.getSubPath().isEmpty()); assertTrue(mount2.getReadOnly()); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(1) .getVolumeMounts() .size(), 2); if ("settings.xml".equals(mount1.getSubPath())) { assertEquals(mount1.getSubPath(), "settings.xml"); assertEquals(mount2.getSubPath(), "another.xml"); } else { assertEquals(mount1.getSubPath(), "another.xml"); assertEquals(mount2.getSubPath(), "settings.xml"); } }
@Test public void shouldProvisionAsFilesWithPathOverride() throws Exception { Container container = new ContainerBuilder().withName("maven").build(); DevfileImpl mock_defvile = mock(DevfileImpl.class); ComponentImpl component = new ComponentImpl(); component.setAlias("maven"); component.getVolumes().add(new VolumeImpl("test_secret", "/path/to/override")); InternalMachineConfig internalMachineConfig = new InternalMachineConfig(); internalMachineConfig.getAttributes().put(DEVFILE_COMPONENT_ALIAS_ATTRIBUTE, "maven"); when(environment.getMachines()).thenReturn(ImmutableMap.of("maven", internalMachineConfig)); when(environment.getDevfile()).thenReturn(mock_defvile); when(mock_defvile.getComponents()).thenReturn(singletonList(component)); PodSpec localSpec = new PodSpecBuilder().withContainers(ImmutableList.of(container)).build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random", "another.xml", "freedom")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 2); VolumeMount mount1 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(mount1.getName(), "test_secret"); assertEquals(mount1.getMountPath(), "/path/to/override/settings.xml"); assertTrue(mount1.getReadOnly()); }
@Test public void shouldProvisionContainersWithAutomountOverrideTrue() throws Exception { Container container_match1 = new ContainerBuilder().withName("maven").build(); Container container_match2 = new ContainerBuilder().withName("other").build(); DevfileImpl mock_defvile = mock(DevfileImpl.class); ComponentImpl component = new ComponentImpl(); component.setAlias("maven"); component.setAutomountWorkspaceSecrets(true); InternalMachineConfig internalMachineConfig = new InternalMachineConfig(); internalMachineConfig.getAttributes().put(DEVFILE_COMPONENT_ALIAS_ATTRIBUTE, "maven"); when(environment.getMachines()).thenReturn(ImmutableMap.of("maven", internalMachineConfig)); when(environment.getDevfile()).thenReturn(mock_defvile); when(mock_defvile.getComponents()).thenReturn(singletonList(component)); PodSpec localSpec = new PodSpecBuilder() .withContainers(ImmutableList.of(container_match1, container_match2)) .build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(singletonMap("foo", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "false")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 1); VolumeMount mount1 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(mount1.getName(), "test_secret"); assertEquals(mount1.getMountPath(), "/home/user/.m2/foo"); assertTrue(mount1.getReadOnly()); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(1) .getVolumeMounts() .size(), 0); }
@Test public void shouldNotProvisionContainersWithAutomountOverrideFalse() throws Exception { Container container_match1 = new ContainerBuilder().withName("maven").build(); Container container_match2 = new ContainerBuilder().withName("other").build(); DevfileImpl mock_defvile = mock(DevfileImpl.class); ComponentImpl component = new ComponentImpl(); component.setAlias("maven"); component.setAutomountWorkspaceSecrets(false); InternalMachineConfig internalMachineConfig = new InternalMachineConfig(); internalMachineConfig.getAttributes().put(DEVFILE_COMPONENT_ALIAS_ATTRIBUTE, "maven"); when(environment.getMachines()).thenReturn(ImmutableMap.of("maven", internalMachineConfig)); when(environment.getDevfile()).thenReturn(mock_defvile); when(mock_defvile.getComponents()).thenReturn(singletonList(component)); PodSpec localSpec = new PodSpecBuilder() .withContainers(ImmutableList.of(container_match1, container_match2)) .build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(singletonMap("foo", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 0); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(1) .getVolumeMounts() .size(), 1); VolumeMount mount2 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(1) .getVolumeMounts() .get(0); assertEquals(mount2.getName(), "test_secret"); assertEquals(mount2.getMountPath(), "/home/user/.m2/foo"); assertTrue(mount2.getReadOnly()); }
@Test public void shouldNotProvisionAllContainersifAutomountDisabled() throws Exception { Container container_match1 = spy(new ContainerBuilder().withName("maven").build()); Container container_match2 = spy(new ContainerBuilder().withName("other").build()); when(podSpec.getContainers()).thenReturn(ImmutableList.of(container_match1, container_match2)); Secret secret = new SecretBuilder() .withData(singletonMap("foo", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "false")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); verify(container_match1).getName(); verify(container_match2).getName(); verifyNoMoreInteractions(container_match1, container_match2); }
@Test( expectedExceptions = InfrastructureException.class, expectedExceptionsMessageRegExp = "Unable to mount secret 'test_secret': It is configured to be mounted as a file but the mount path was not specified. Please define the 'che.eclipse.org/mount-path' annotation on the secret to specify it.") public void shouldThrowExceptionWhenNoMountPathSpecifiedForFiles() throws Exception { Container container_match = new ContainerBuilder().withName("maven").build(); PodSpec localSpec = new PodSpecBuilder().withContainers(ImmutableList.of(container_match)).build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random", "another.xml", "freedom")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations(singletonMap(ANNOTATION_MOUNT_AS, "file")) .withLabels(emptyMap()) .build()) .build(); when(secrets.get(any(LabelSelector.class))).thenReturn(singletonList(secret)); secretApplier.applySecret(environment, runtimeIdentity, secret); }
@Test public void shouldNotUseSubpathForOlderK8s() throws InfrastructureException { lenient().when(kubernetesVersion.newerOrEqualThan(1, 13)).thenReturn(false); lenient().when(kubernetesVersion.olderThan(1, 13)).thenReturn(true); Container container_match1 = new ContainerBuilder().withName("maven").build(); PodSpec localSpec = new PodSpecBuilder().withContainers(ImmutableList.of(container_match1)).build(); when(podData.getSpec()).thenReturn(localSpec); Secret secret = new SecretBuilder() .withData(ImmutableMap.of("settings.xml", "random")) .withMetadata( new ObjectMetaBuilder() .withName("test_secret") .withAnnotations( ImmutableMap.of( ANNOTATION_MOUNT_AS, "file", ANNOTATION_MOUNT_PATH, "/home/user/.m2", ANNOTATION_AUTOMOUNT, "true")) .withLabels(emptyMap()) .build()) .build(); secretApplier.applySecret(environment, runtimeIdentity, secret); assertEquals(environment.getPodsData().get("pod1").getSpec().getVolumes().size(), 1); Volume volume = environment.getPodsData().get("pod1").getSpec().getVolumes().get(0); assertEquals(volume.getName(), "test_secret"); assertEquals(volume.getSecret().getSecretName(), "test_secret"); assertEquals( environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .size(), 1); VolumeMount mount1 = environment .getPodsData() .get("pod1") .getSpec() .getContainers() .get(0) .getVolumeMounts() .get(0); assertEquals(mount1.getName(), "test_secret"); assertEquals(mount1.getMountPath(), "/home/user/.m2"); assertNull(mount1.getSubPath()); }