Use config map name for configtree property sources

When Kubernetes mounts config maps onto volumes in a pod, it creates
hidden files on the pod filesystem with symbolic links to the
hidden files. The symlinks are named for the user-provided config
map that was mounted, while the hidden files have system-generated
names.

Prior to this commit, the property sources created by the
configtree property source were added to the environment using the
system-generated hidden file name instead of the user-provided
symlink name. This commit corrects that behavior so the property
sources are named as a user would expect.

Fixes gh-23232
pull/23694/head
Scott Frederick 4 years ago
parent d0c6dbc2c7
commit de991616b0

@ -25,6 +25,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
@ -192,7 +193,7 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
static Map<String, PropertyFile> findAll(Path sourceDirectory, Set<Option> options) { static Map<String, PropertyFile> findAll(Path sourceDirectory, Set<Option> options) {
try { try {
Map<String, PropertyFile> propertyFiles = new TreeMap<>(); Map<String, PropertyFile> propertyFiles = new TreeMap<>();
Files.find(sourceDirectory, MAX_DEPTH, PropertyFile::isRegularFile).forEach((path) -> { Files.find(sourceDirectory, MAX_DEPTH, PropertyFile::isPropertyFile).forEach((path) -> {
String name = getName(sourceDirectory.relativize(path)); String name = getName(sourceDirectory.relativize(path));
if (StringUtils.hasText(name)) { if (StringUtils.hasText(name)) {
if (options.contains(Option.USE_LOWERCASE_NAMES)) { if (options.contains(Option.USE_LOWERCASE_NAMES)) {
@ -208,8 +209,18 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
} }
} }
private static boolean isRegularFile(Path path, BasicFileAttributes attributes) { private static boolean isPropertyFile(Path path, BasicFileAttributes attributes) {
return attributes.isRegularFile(); return !hasHiddenPathElement(path) && (attributes.isRegularFile() || attributes.isSymbolicLink());
}
private static boolean hasHiddenPathElement(Path path) {
Iterator<Path> iterator = path.iterator();
while (iterator.hasNext()) {
if (iterator.next().toString().startsWith(".")) {
return true;
}
}
return false;
} }
private static String getName(Path relativePath) { private static String getName(Path relativePath) {

@ -88,6 +88,18 @@ class ConfigTreePropertySourceTests {
assertThat(propertySource.getPropertyNames()).containsExactly("c", "fa.a", "fa.b", "fb.a", "fb.fa.a"); assertThat(propertySource.getPropertyNames()).containsExactly("c", "fa.a", "fa.b", "fb.a", "fb.fa.a");
} }
@Test
void getPropertyNamesFromFlatWithSymlinksIgnoresHiddenFiles() throws Exception {
ConfigTreePropertySource propertySource = getSymlinkedFlatPropertySource();
assertThat(propertySource.getPropertyNames()).containsExactly("a", "b", "c");
}
@Test
void getPropertyNamesFromNestedWithSymlinksIgnoresHiddenFiles() throws Exception {
ConfigTreePropertySource propertySource = getSymlinkedNestedPropertySource();
assertThat(propertySource.getPropertyNames()).containsExactly("aa", "ab", "baa", "c");
}
@Test @Test
void getPropertyNamesWhenLowercaseReturnsPropertyNames() throws Exception { void getPropertyNamesWhenLowercaseReturnsPropertyNames() throws Exception {
addProperty("SpRiNg", "boot"); addProperty("SpRiNg", "boot");
@ -194,6 +206,16 @@ class ConfigTreePropertySourceTests {
return new ConfigTreePropertySource("test", this.directory); return new ConfigTreePropertySource("test", this.directory);
} }
private ConfigTreePropertySource getSymlinkedFlatPropertySource() throws IOException {
addProperty("..hidden-a", "A");
addProperty("..hidden-b", "B");
addProperty("..hidden-c", "C");
createSymbolicLink("a", "..hidden-a");
createSymbolicLink("b", "..hidden-b");
createSymbolicLink("c", "..hidden-c");
return new ConfigTreePropertySource("test", this.directory);
}
private ConfigTreePropertySource getNestedPropertySource() throws IOException { private ConfigTreePropertySource getNestedPropertySource() throws IOException {
addNested(); addNested();
return new ConfigTreePropertySource("test", this.directory); return new ConfigTreePropertySource("test", this.directory);
@ -207,10 +229,26 @@ class ConfigTreePropertySourceTests {
addProperty("c", "C"); addProperty("c", "C");
} }
private ConfigTreePropertySource getSymlinkedNestedPropertySource() throws IOException {
addProperty("..hidden-a/a", "AA");
addProperty("..hidden-a/b", "AB");
addProperty("..hidden-b/fa/a", "BAA");
addProperty("c", "C");
createSymbolicLink("aa", "..hidden-a/a");
createSymbolicLink("ab", "..hidden-a/b");
createSymbolicLink("baa", "..hidden-b/fa/a");
return new ConfigTreePropertySource("test", this.directory);
}
private void addProperty(String path, String value) throws IOException { private void addProperty(String path, String value) throws IOException {
File file = this.directory.resolve(path).toFile(); File file = this.directory.resolve(path).toFile();
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
FileCopyUtils.copy(value.getBytes(StandardCharsets.UTF_8), file); FileCopyUtils.copy(value.getBytes(StandardCharsets.UTF_8), file);
} }
private void createSymbolicLink(String link, String target) throws IOException {
Files.createSymbolicLink(this.directory.resolve(link).toAbsolutePath(),
this.directory.resolve(target).toAbsolutePath());
}
} }

Loading…
Cancel
Save