Skip to content

Commit

Permalink
Merge branch 'main' into cleanup-fabric8-loadbalancer-mapper-part-5
Browse files Browse the repository at this point in the history
  • Loading branch information
wind57 committed Mar 28, 2024
2 parents 4766a63 + 5526b50 commit 6b58a62
Show file tree
Hide file tree
Showing 23 changed files with 436 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@
* @author wind57
*/
public record KubernetesClientConfigContext(CoreV1Api client, NormalizedSource normalizedSource, String namespace,
Environment environment) {
Environment environment, boolean includeDefaultProfileData) {

public KubernetesClientConfigContext(CoreV1Api client, NormalizedSource normalizedSource, String namespace,
Environment environment) {
this(client, normalizedSource, namespace, environment, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
*
* @author wind57
*/
final class KubernetesClientConfigMapsCache implements ConfigMapCache {
public final class KubernetesClientConfigMapsCache implements ConfigMapCache {

private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesClientConfigMapsCache.class));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,23 @@ static MultipleSourcesContainer configMapsDataByLabels(CoreV1Api coreV1Api, Stri
* </pre>
*/
static MultipleSourcesContainer secretsDataByName(CoreV1Api coreV1Api, String namespace,
LinkedHashSet<String> sourceNames, Environment environment) {
LinkedHashSet<String> sourceNames, Environment environment, boolean includeDefaultProfileData) {
List<StrippedSourceContainer> strippedSecrets = strippedSecrets(coreV1Api, namespace);
if (strippedSecrets.isEmpty()) {
return MultipleSourcesContainer.empty();
}
return ConfigUtils.processNamedData(strippedSecrets, environment, sourceNames, namespace, DECODE);
return ConfigUtils.processNamedData(strippedSecrets, environment, sourceNames, namespace, DECODE,
includeDefaultProfileData);
}

static MultipleSourcesContainer secretsDataByName(CoreV1Api coreV1Api, String namespace,
LinkedHashSet<String> sourceNames, Environment environment) {
return secretsDataByName(coreV1Api, namespace, sourceNames, environment, true);
}

static MultipleSourcesContainer configMapsDataByName(CoreV1Api coreV1Api, String namespace,
LinkedHashSet<String> sourceNames, Environment environment) {
return configMapsDataByName(coreV1Api, namespace, sourceNames, environment, true);
}

/**
Expand All @@ -125,12 +136,13 @@ static MultipleSourcesContainer secretsDataByName(CoreV1Api coreV1Api, String na
* </pre>
*/
static MultipleSourcesContainer configMapsDataByName(CoreV1Api coreV1Api, String namespace,
LinkedHashSet<String> sourceNames, Environment environment) {
LinkedHashSet<String> sourceNames, Environment environment, boolean includeDefaultProfileData) {
List<StrippedSourceContainer> strippedConfigMaps = strippedConfigMaps(coreV1Api, namespace);
if (strippedConfigMaps.isEmpty()) {
return MultipleSourcesContainer.empty();
}
return ConfigUtils.processNamedData(strippedConfigMaps, environment, sourceNames, namespace, DECODE);
return ConfigUtils.processNamedData(strippedConfigMaps, environment, sourceNames, namespace, DECODE,
includeDefaultProfileData);
}

private static List<StrippedSourceContainer> strippedConfigMaps(CoreV1Api coreV1Api, String namespace) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.LinkedHashSet;
import java.util.function.Supplier;

import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NamedSourceData;
Expand All @@ -42,10 +43,19 @@ public KubernetesClientContextToSourceData get() {
NamedConfigMapNormalizedSource source = (NamedConfigMapNormalizedSource) context.normalizedSource();

return new NamedSourceData() {
@Override
protected String generateSourceName(String target, String sourceName, String namespace,
String[] activeProfiles) {
if (source.appendProfileToName()) {
return ConfigUtils.sourceName(target, sourceName, namespace, activeProfiles);
}
return super.generateSourceName(target, sourceName, namespace, activeProfiles);
}

@Override
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
return KubernetesClientConfigUtils.configMapsDataByName(context.client(), context.namespace(),
sourceNames, context.environment());
sourceNames, context.environment(), context.includeDefaultProfileData());
}
}.compute(source.name().orElseThrow(), source.prefix(), source.target(), source.profileSpecificSources(),
source.failFast(), context.namespace(), context.environment().getActiveProfiles());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.LinkedHashSet;
import java.util.function.Supplier;

import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NamedSourceData;
Expand All @@ -41,10 +42,19 @@ public KubernetesClientContextToSourceData get() {
NamedSecretNormalizedSource source = (NamedSecretNormalizedSource) context.normalizedSource();

return new NamedSourceData() {
@Override
protected String generateSourceName(String target, String sourceName, String namespace,
String[] activeProfiles) {
if (source.appendProfileToName()) {
return ConfigUtils.sourceName(target, sourceName, namespace, activeProfiles);
}
return super.generateSourceName(target, sourceName, namespace, activeProfiles);
}

@Override
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
return KubernetesClientConfigUtils.secretsDataByName(context.client(), context.namespace(),
sourceNames, context.environment());
sourceNames, context.environment(), context.includeDefaultProfileData());
}
}.compute(source.name().orElseThrow(), source.prefix(), source.target(), source.profileSpecificSources(),
source.failFast(), context.namespace(), context.environment().getActiveProfiles());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,17 @@ void matchIncludeSingleProfile() {
stubCall(configMapList);
CoreV1Api api = new CoreV1Api();

NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, true);
NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true,
ConfigUtils.Prefix.DEFAULT, true, true);
MockEnvironment environment = new MockEnvironment();
environment.setActiveProfiles("with-profile");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment);
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment, false);

KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);

Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default");
Assertions.assertEquals(sourceData.sourceData().size(), 2);
Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red");
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default.with-profile");
Assertions.assertEquals(sourceData.sourceData().size(), 1);
Assertions.assertEquals(sourceData.sourceData().get("taste"), "mango");

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,17 +217,17 @@ void matchIncludeSingleProfile() {
stubCall(secretList);
CoreV1Api api = new CoreV1Api();

NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, true);
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, ConfigUtils.Prefix.DEFAULT,
true, true);
MockEnvironment environment = new MockEnvironment();
environment.addActiveProfile("with-profile");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment);
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment, false);

KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);

Assertions.assertEquals(sourceData.sourceName(), "secret.red.red-with-profile.default");
Assertions.assertEquals(sourceData.sourceData().size(), 2);
Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.red-with-profile.default.with-profile");
Assertions.assertEquals(sourceData.sourceData().size(), 1);
Assertions.assertEquals(sourceData.sourceData().get("taste"), "mango");

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.cloud.kubernetes.commons.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -161,13 +162,27 @@ public static String sourceName(String target, String applicationName, String na
return target + PROPERTY_SOURCE_NAME_SEPARATOR + applicationName + PROPERTY_SOURCE_NAME_SEPARATOR + namespace;
}

public static String sourceName(String target, String applicationName, String namespace, String[] profiles) {
String name = sourceName(target, applicationName, namespace);
if (profiles != null && profiles.length > 0) {
name = name + PROPERTY_SOURCE_NAME_SEPARATOR + StringUtils.arrayToDelimitedString(profiles, "-");
}
return name;
}

public static MultipleSourcesContainer processNamedData(List<StrippedSourceContainer> strippedSources,
Environment environment, LinkedHashSet<String> sourceNames, String namespace, boolean decode) {
return processNamedData(strippedSources, environment, sourceNames, namespace, decode, true);
}

/**
* transforms raw data from one or multiple sources into an entry of source names and
* flattened data that they all hold (potentially overriding entries without any
* defined order).
*/
public static MultipleSourcesContainer processNamedData(List<StrippedSourceContainer> strippedSources,
Environment environment, LinkedHashSet<String> sourceNames, String namespace, boolean decode) {
Environment environment, LinkedHashSet<String> sourceNames, String namespace, boolean decode,
boolean includeDefaultProfileData) {

Map<String, StrippedSourceContainer> hashByName = strippedSources.stream()
.collect(Collectors.toMap(StrippedSourceContainer::name, Function.identity()));
Expand All @@ -189,14 +204,35 @@ public static MultipleSourcesContainer processNamedData(List<StrippedSourceConta
if (decode) {
rawData = decodeData(rawData);
}
data.putAll(SourceDataEntriesProcessor.processAllEntries(rawData == null ? Map.of() : rawData,
environment));

// In some cases we want to include properties from the default profile along with any active profiles
// In these cases includeDefaultProfileData will be true
// If includeDefaultProfileData is false then we want to make sure that we only return properties from any active profiles

//Check the source to see if it contains any active profiles
boolean containsActiveProfile = environment.getActiveProfiles().length == 0
|| Arrays.stream(environment.getActiveProfiles())
.anyMatch(p -> source.contains("-" + p) || "default".equals(p));
if (includeDefaultProfileData || containsActiveProfile
|| containsDataWithProfile(rawData, environment.getActiveProfiles())) {
data.putAll(SourceDataEntriesProcessor.processAllEntries(rawData == null ? Map.of() : rawData,
environment, includeDefaultProfileData));
}
}
});

return new MultipleSourcesContainer(foundSourceNames, data);
}

/*
* In the case there the data contains yaml or properties files we need to check their names to see if they
* contain any active profiles.
*/
private static boolean containsDataWithProfile(Map<String, String> rawData, String[] activeProfiles) {
return rawData.keySet().stream().anyMatch(
key -> Arrays.stream(activeProfiles).anyMatch(p -> key.contains("-" + p) || "default".equals(p)));
}

/**
* transforms raw data from one or multiple sources into an entry of source names and
* flattened data that they all hold (potentially overriding entries without any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,25 @@ public final class NamedConfigMapNormalizedSource extends NormalizedSource {

private final boolean includeProfileSpecificSources;

private final boolean appendProfileToName;

public NamedConfigMapNormalizedSource(String name, String namespace, boolean failFast, ConfigUtils.Prefix prefix,
boolean includeProfileSpecificSources) {
super(name, namespace, failFast);
this.prefix = Objects.requireNonNull(prefix);
this.includeProfileSpecificSources = includeProfileSpecificSources;
this(name, namespace, failFast, prefix, includeProfileSpecificSources, false);
}

public NamedConfigMapNormalizedSource(String name, String namespace, boolean failFast,
boolean includeProfileSpecificSources) {
this(name, namespace, failFast, ConfigUtils.Prefix.DEFAULT, includeProfileSpecificSources);
}

public NamedConfigMapNormalizedSource(String name, String namespace, boolean failFast, ConfigUtils.Prefix prefix,
boolean includeProfileSpecificSources, boolean appendProfileToName) {
super(name, namespace, failFast);
this.prefix = ConfigUtils.Prefix.DEFAULT;
this.prefix = Objects.requireNonNull(prefix);
this.includeProfileSpecificSources = includeProfileSpecificSources;
this.appendProfileToName = appendProfileToName;

}

public ConfigUtils.Prefix prefix() {
Expand All @@ -51,6 +58,14 @@ public boolean profileSpecificSources() {
return includeProfileSpecificSources;
}

/**
* append or not the active profiles to the name of the generated source.
* At the moment this is true only for config server generated sources.
*/
public boolean appendProfileToName() {
return appendProfileToName;
}

@Override
public NormalizedSourceType type() {
return NormalizedSourceType.NAMED_CONFIG_MAP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,38 @@ public final class NamedSecretNormalizedSource extends NormalizedSource {

private final boolean includeProfileSpecificSources;

private final boolean appendProfileToName;

public NamedSecretNormalizedSource(String name, String namespace, boolean failFast, ConfigUtils.Prefix prefix,
boolean includeProfileSpecificSources) {
boolean includeProfileSpecificSources, boolean appendProfileToName) {
super(name, namespace, failFast);
this.prefix = Objects.requireNonNull(prefix);
this.includeProfileSpecificSources = includeProfileSpecificSources;
this.appendProfileToName = appendProfileToName;
}

public NamedSecretNormalizedSource(String name, String namespace, boolean failFast,
boolean includeProfileSpecificSources) {
super(name, namespace, failFast);
this.prefix = ConfigUtils.Prefix.DEFAULT;
this.includeProfileSpecificSources = includeProfileSpecificSources;
this(name, namespace, failFast, ConfigUtils.Prefix.DEFAULT, includeProfileSpecificSources, false);
}

public NamedSecretNormalizedSource(String name, String namespace, boolean failFast, ConfigUtils.Prefix prefix,
boolean includeProfileSpecificSources) {
this(name, namespace, failFast, prefix, includeProfileSpecificSources, false);
}

public boolean profileSpecificSources() {
return includeProfileSpecificSources;
}

/**
* append or not the active profiles to the name of the generated source.
* At the moment this is true only for config server generated sources.
*/
public boolean appendProfileToName() {
return appendProfileToName;
}

public ConfigUtils.Prefix prefix() {
return prefix;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ public final SourceData compute(String sourceName, ConfigUtils.Prefix prefix, St
}

String names = data.names().stream().sorted().collect(Collectors.joining(PROPERTY_SOURCE_NAME_SEPARATOR));
return new SourceData(ConfigUtils.sourceName(target, names, namespace), data.data());
return new SourceData(generateSourceName(target, names, namespace, activeProfiles), data.data());
}

protected String generateSourceName(String target, String sourceName, String namespace, String[] activeProfiles) {
return ConfigUtils.sourceName(target, sourceName, namespace);
}

/**
Expand Down
Loading

0 comments on commit 6b58a62

Please sign in to comment.