Use propertyresolver revert function (#1565)

* Bumping versions

* Remove function and use PropertyResolved
Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
This commit is contained in:
Ryan Baxter
2024-01-23 10:00:19 -05:00
committed by GitHub
parent a4e211535a
commit 13d7d6e3f9
5 changed files with 140 additions and 154 deletions

View File

@@ -17,7 +17,6 @@
package org.springframework.cloud.kubernetes.client.discovery;
import java.util.Collections;
import java.util.List;
import io.kubernetes.client.informer.SharedIndexInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
@@ -30,19 +29,16 @@ import io.kubernetes.client.openapi.models.V1ServiceList;
import io.kubernetes.client.util.Namespaces;
import io.kubernetes.client.util.generic.GenericKubernetesApi;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver;
import org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver.PropertyResolver;
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerBootstrapper;
import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerInstanceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.Environment;
@@ -54,65 +50,45 @@ import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.
*/
class KubernetesClientConfigServerBootstrapper extends KubernetesConfigServerBootstrapper {
private static final Log LOG = LogFactory.getLog(KubernetesClientConfigServerBootstrapper.class);
@Override
public void initialize(BootstrapRegistry registry) {
if (hasConfigServerInstanceProvider()) {
return;
}
// We need to pass a lambda here rather than create a new instance of
// ConfigServerInstanceProvider.Function
// or else we will get ClassNotFoundExceptions if Spring Cloud Config is not on
// the classpath
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, KubernetesFunction::create);
}
final static class KubernetesFunction implements ConfigServerInstanceProvider.Function {
private final BootstrapContext context;
private KubernetesFunction(BootstrapContext context) {
this.context = context;
}
static KubernetesFunction create(BootstrapContext context) {
return new KubernetesFunction(context);
}
@Override
public List<ServiceInstance> apply(String serviceId, Binder binder, BindHandler bindHandler, Log log) {
if (binder == null || bindHandler == null || !getDiscoveryEnabled(binder, bindHandler)) {
// If we don't have the Binder or BinderHandler from the
// ConfigDataLocationResolverContext
// we won't be able to create the necessary configuration
// properties to configure the
// Kubernetes DiscoveryClient
return Collections.emptyList();
registry.registerIfAbsent(KubernetesDiscoveryProperties.class, context -> {
if (!getDiscoveryEnabled(context)) {
return null;
}
KubernetesDiscoveryProperties discoveryProperties = createKubernetesDiscoveryProperties(binder,
bindHandler);
KubernetesClientProperties clientProperties = createKubernetesClientProperties(binder, bindHandler);
return getInstanceProvider(discoveryProperties, clientProperties, context, binder, bindHandler, log)
.getInstances(serviceId);
}
return createKubernetesDiscoveryProperties(context);
});
private KubernetesConfigServerInstanceProvider getInstanceProvider(
KubernetesDiscoveryProperties discoveryProperties, KubernetesClientProperties clientProperties,
BootstrapContext context, Binder binder, BindHandler bindHandler, Log log) {
registry.registerIfAbsent(KubernetesClientProperties.class, context -> {
if (!getDiscoveryEnabled(context)) {
return null;
}
return createKubernetesClientProperties(context);
});
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, context -> {
if (!getDiscoveryEnabled(context)) {
return (id) -> Collections.emptyList();
}
if (context.isRegistered(KubernetesInformerDiscoveryClient.class)) {
KubernetesInformerDiscoveryClient client = context.get(KubernetesInformerDiscoveryClient.class);
return client::getInstances;
}
else {
PropertyResolver propertyResolver = getPropertyResolver(context);
ApiClient defaultApiClient = kubernetesApiClient();
defaultApiClient.setUserAgent(binder.bind("spring.cloud.kubernetes.client.user-agent", String.class)
.orElse(KubernetesClientProperties.DEFAULT_USER_AGENT));
defaultApiClient.setUserAgent(propertyResolver.get("spring.cloud.kubernetes.client.user-agent",
String.class, KubernetesClientProperties.DEFAULT_USER_AGENT));
KubernetesClientAutoConfiguration clientAutoConfiguration = new KubernetesClientAutoConfiguration();
ApiClient apiClient = context.getOrElseSupply(ApiClient.class, () -> defaultApiClient);
KubernetesNamespaceProvider kubernetesNamespaceProvider = clientAutoConfiguration
.kubernetesNamespaceProvider(getNamespaceEnvironment(binder, bindHandler));
.kubernetesNamespaceProvider(getNamespaceEnvironment(propertyResolver));
KubernetesDiscoveryProperties discoveryProperties = context.get(KubernetesDiscoveryProperties.class);
String namespace = getInformerNamespace(kubernetesNamespaceProvider, discoveryProperties);
SharedInformerFactory sharedInformerFactory = new SharedInformerFactory(apiClient);
GenericKubernetesApi<V1Service, V1ServiceList> servicesApi = new GenericKubernetesApi<>(V1Service.class,
@@ -133,40 +109,32 @@ class KubernetesClientConfigServerBootstrapper extends KubernetesConfigServerBoo
return discoveryClient::getInstances;
}
catch (Exception e) {
if (log != null) {
log.warn("Error initiating informer discovery client", e);
}
LOG.warn("Error initiating informer discovery client", e);
return (serviceId) -> Collections.emptyList();
}
finally {
sharedInformerFactory.stopAllRegisteredInformers();
}
}
}
private String getInformerNamespace(KubernetesNamespaceProvider kubernetesNamespaceProvider,
KubernetesDiscoveryProperties discoveryProperties) {
return discoveryProperties.allNamespaces() ? Namespaces.NAMESPACE_ALL
: kubernetesNamespaceProvider.getNamespace() == null ? Namespaces.NAMESPACE_DEFAULT
: kubernetesNamespaceProvider.getNamespace();
}
private Environment getNamespaceEnvironment(Binder binder, BindHandler bindHandler) {
return new AbstractEnvironment() {
@Override
public String getProperty(String key) {
return binder.bind(key, Bindable.of(String.class), bindHandler).orElse(super.getProperty(key));
}
};
}
// This method should never be called, but is there for backward
// compatibility purposes
@Override
public List<ServiceInstance> apply(String serviceId) {
return apply(serviceId, null, null, null);
}
});
}
private String getInformerNamespace(KubernetesNamespaceProvider kubernetesNamespaceProvider,
KubernetesDiscoveryProperties discoveryProperties) {
return discoveryProperties.allNamespaces() ? Namespaces.NAMESPACE_ALL
: kubernetesNamespaceProvider.getNamespace() == null ? Namespaces.NAMESPACE_DEFAULT
: kubernetesNamespaceProvider.getNamespace();
}
private Environment getNamespaceEnvironment(
ConfigServerConfigDataLocationResolver.PropertyResolver propertyResolver) {
return new AbstractEnvironment() {
@Override
public String getProperty(String key) {
return propertyResolver.get(key, String.class, super.getProperty(key));
}
};
}
}

View File

@@ -35,8 +35,6 @@ import static org.springframework.cloud.kubernetes.commons.KubernetesClientPrope
*/
public class KubernetesNamespaceProvider {
private static final DeferredLog LOG = new DeferredLog();
/**
* Property name for namespace.
*/
@@ -47,6 +45,10 @@ public class KubernetesNamespaceProvider {
*/
public static final String NAMESPACE_PATH_PROPERTY = "spring.cloud.kubernetes.client.serviceAccountNamespacePath";
private static final DeferredLog LOG = new DeferredLog();
private String namespacePropertyValue;
private BindHandler bindHandler;
private String serviceAccountNamespace;
@@ -65,7 +67,36 @@ public class KubernetesNamespaceProvider {
this.bindHandler = bindHandler;
}
public KubernetesNamespaceProvider(String namespacePropertyValue) {
this.namespacePropertyValue = namespacePropertyValue;
}
public static String getNamespaceFromServiceAccountFile(String path) {
String namespace = null;
LOG.debug("Looking for service account namespace at: [" + path + "].");
Path serviceAccountNamespacePath = Paths.get(path);
boolean serviceAccountNamespaceExists = Files.isRegularFile(serviceAccountNamespacePath);
if (serviceAccountNamespaceExists) {
LOG.debug("Found service account namespace at: [" + serviceAccountNamespacePath + "].");
try {
namespace = new String(Files.readAllBytes((serviceAccountNamespacePath)));
LOG.debug("Service account namespace value: " + serviceAccountNamespacePath);
}
catch (IOException ioe) {
LOG.error("Error reading service account namespace from: [" + serviceAccountNamespacePath + "].", ioe);
}
}
return namespace;
}
public String getNamespace() {
// If they provided the namespace in the constructor just return that
if (!ObjectUtils.isEmpty(namespacePropertyValue)) {
return namespacePropertyValue;
}
// No namespace provided so try to get it from another source
String namespace = null;
if (environment != null) {
namespace = environment.getProperty(NAMESPACE_PROPERTY);
@@ -96,24 +127,4 @@ public class KubernetesNamespaceProvider {
return serviceAccountNamespace;
}
public static String getNamespaceFromServiceAccountFile(String path) {
String namespace = null;
LOG.debug("Looking for service account namespace at: [" + path + "].");
Path serviceAccountNamespacePath = Paths.get(path);
boolean serviceAccountNamespaceExists = Files.isRegularFile(serviceAccountNamespacePath);
if (serviceAccountNamespaceExists) {
LOG.debug("Found service account namespace at: [" + serviceAccountNamespacePath + "].");
try {
namespace = new String(Files.readAllBytes((serviceAccountNamespacePath)));
LOG.debug("Service account namespace value: " + serviceAccountNamespacePath);
}
catch (IOException ioe) {
LOG.error("Error reading service account namespace from: [" + serviceAccountNamespacePath + "].", ioe);
}
}
return namespace;
}
}

View File

@@ -16,11 +16,14 @@
package org.springframework.cloud.kubernetes.commons.config;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistryInitializer;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.config.client.ConfigClientProperties;
import org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver;
import org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver.PropertyResolver;
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
@@ -41,14 +44,40 @@ public abstract class KubernetesConfigServerBootstrapper implements BootstrapReg
bindHandler).orElseGet(() -> KubernetesDiscoveryProperties.DEFAULT);
}
public static KubernetesDiscoveryProperties createKubernetesDiscoveryProperties(BootstrapContext bootstrapContext) {
PropertyResolver propertyResolver = getPropertyResolver(bootstrapContext);
return propertyResolver.resolveConfigurationProperties(KubernetesDiscoveryProperties.PREFIX,
KubernetesDiscoveryProperties.class, () -> KubernetesDiscoveryProperties.DEFAULT);
}
public static KubernetesClientProperties createKubernetesClientProperties(Binder binder, BindHandler bindHandler) {
return binder.bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class))
.withNamespace(new KubernetesNamespaceProvider(binder, bindHandler).getNamespace());
}
public static KubernetesClientProperties createKubernetesClientProperties(BootstrapContext bootstrapContext) {
PropertyResolver propertyResolver = getPropertyResolver(bootstrapContext);
return getPropertyResolver(bootstrapContext)
.resolveOrCreateConfigurationProperties(KubernetesClientProperties.PREFIX,
KubernetesClientProperties.class)
.withNamespace(
propertyResolver.get(KubernetesNamespaceProvider.NAMESPACE_PROPERTY, String.class, null));
}
public static Boolean getDiscoveryEnabled(Binder binder, BindHandler bindHandler) {
return binder.bind(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Bindable.of(Boolean.class), bindHandler)
.orElse(false);
}
public static Boolean getDiscoveryEnabled(BootstrapContext bootstrapContext) {
return getPropertyResolver(bootstrapContext).get(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Boolean.class,
false);
}
protected static PropertyResolver getPropertyResolver(BootstrapContext context) {
return context.getOrElseSupply(ConfigServerConfigDataLocationResolver.PropertyResolver.class,
() -> new ConfigServerConfigDataLocationResolver.PropertyResolver(context.get(Binder.class),
context.getOrElse(BindHandler.class, null)));
}
}

View File

@@ -17,21 +17,16 @@
package org.springframework.cloud.kubernetes.fabric8.discovery;
import java.util.Collections;
import java.util.List;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.config.client.ConfigServerConfigDataLocationResolver.PropertyResolver;
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerBootstrapper;
import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerInstanceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortSecureResolver;
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
@@ -46,68 +41,46 @@ class Fabric8ConfigServerBootstrapper extends KubernetesConfigServerBootstrapper
if (hasConfigServerInstanceProvider()) {
return;
}
// We need to pass a lambda here rather than create a new instance of
// ConfigServerInstanceProvider.Function
// or else we will get ClassNotFoundExceptions if Spring Cloud Config is not on
// the classpath
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, KubernetesFunction::create);
}
final static class KubernetesFunction implements ConfigServerInstanceProvider.Function {
private final BootstrapContext context;
private KubernetesFunction(BootstrapContext context) {
this.context = context;
}
static KubernetesFunction create(BootstrapContext context) {
return new KubernetesFunction(context);
}
@Override
public List<ServiceInstance> apply(String serviceId, Binder binder, BindHandler bindHandler, Log log) {
if (binder == null || bindHandler == null || !getDiscoveryEnabled(binder, bindHandler)) {
// If we don't have the Binder or BinderHandler from the
// ConfigDataLocationResolverContext
// we won't be able to create the necessary configuration
// properties to configure the
// Kubernetes DiscoveryClient
return Collections.emptyList();
registry.registerIfAbsent(KubernetesDiscoveryProperties.class, context -> {
if (!getDiscoveryEnabled(context)) {
return null;
}
KubernetesDiscoveryProperties discoveryProperties = createKubernetesDiscoveryProperties(binder,
bindHandler);
KubernetesClientProperties clientProperties = createKubernetesClientProperties(binder, bindHandler);
return getInstanceProvider(discoveryProperties, clientProperties, context, binder, bindHandler)
.getInstances(serviceId);
}
return createKubernetesDiscoveryProperties(context);
});
private KubernetesConfigServerInstanceProvider getInstanceProvider(
KubernetesDiscoveryProperties discoveryProperties, KubernetesClientProperties clientProperties,
BootstrapContext context, Binder binder, BindHandler bindHandler) {
registry.registerIfAbsent(KubernetesClientProperties.class, context -> {
if (!getDiscoveryEnabled(context)) {
return null;
}
return createKubernetesClientProperties(context);
});
// create instance provider
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, context -> {
if (!getDiscoveryEnabled(context)) {
return (id) -> Collections.emptyList();
}
if (context.isRegistered(KubernetesDiscoveryClient.class)) {
KubernetesDiscoveryClient client = context.get(KubernetesDiscoveryClient.class);
return client::getInstances;
}
else {
PropertyResolver propertyResolver = getPropertyResolver(context);
Fabric8AutoConfiguration fabric8AutoConfiguration = new Fabric8AutoConfiguration();
Config config = fabric8AutoConfiguration.kubernetesClientConfig(clientProperties);
Config config = fabric8AutoConfiguration
.kubernetesClientConfig(context.get(KubernetesClientProperties.class));
KubernetesClient kubernetesClient = fabric8AutoConfiguration.kubernetesClient(config);
KubernetesDiscoveryProperties discoveryProperties = context.get(KubernetesDiscoveryProperties.class);
KubernetesDiscoveryClient discoveryClient = new KubernetesDiscoveryClient(kubernetesClient,
discoveryProperties, KubernetesClientServicesFunctionProvider
.servicesFunction(discoveryProperties, binder, bindHandler),
discoveryProperties,
KubernetesClientServicesFunctionProvider.servicesFunction(discoveryProperties,
new KubernetesNamespaceProvider(propertyResolver
.get(KubernetesNamespaceProvider.NAMESPACE_PROPERTY, String.class, null))),
null, new ServicePortSecureResolver(discoveryProperties));
return discoveryClient::getInstances;
}
}
// This method should never be called, but is there for backward
// compatibility purposes
@Override
public List<ServiceInstance> apply(String serviceId) {
return apply(serviceId, null, null, null);
}
});
}
}

View File

@@ -48,6 +48,11 @@ public final class KubernetesClientServicesFunctionProvider {
public static KubernetesClientServicesFunction servicesFunction(KubernetesDiscoveryProperties properties,
Binder binder, BindHandler bindHandler) {
return servicesFunction(properties, new KubernetesNamespaceProvider(binder, bindHandler));
}
public static KubernetesClientServicesFunction servicesFunction(KubernetesDiscoveryProperties properties,
KubernetesNamespaceProvider namespaceProvider) {
if (properties.allNamespaces()) {
return (client) -> client.services().inAnyNamespace().withLabels(properties.serviceLabels());
@@ -55,7 +60,7 @@ public final class KubernetesClientServicesFunctionProvider {
return client -> {
String namespace = Fabric8Utils.getApplicationNamespace(client, null, "discovery-service",
new KubernetesNamespaceProvider(binder, bindHandler));
namespaceProvider);
return client.services().inNamespace(namespace).withLabels(properties.serviceLabels());
};