Skip to content

Commit

Permalink
Use propertyresolver revert function (#1565)
Browse files Browse the repository at this point in the history
* Bumping versions

* Remove function and use PropertyResolved
Co-authored-by: Ryan Baxter <[email protected]>
  • Loading branch information
Ryan Baxter authored Jan 23, 2024
1 parent a4e2115 commit 13d7d6e
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,19 +29,16 @@
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;
Expand All @@ -54,65 +50,45 @@
*/
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,
Expand All @@ -133,40 +109,32 @@ private KubernetesConfigServerInstanceProvider getInstanceProvider(
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));
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
*/
public class KubernetesNamespaceProvider {

private static final DeferredLog LOG = new DeferredLog();

/**
* Property name for namespace.
*/
Expand All @@ -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;
Expand All @@ -65,7 +67,36 @@ public KubernetesNamespaceProvider(Binder binder, BindHandler bindHandler) {
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);
Expand Down Expand Up @@ -96,24 +127,4 @@ private String getServiceAccountNamespace() {
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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -41,14 +44,40 @@ public static KubernetesDiscoveryProperties createKubernetesDiscoveryProperties(
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)));
}

}
Loading

0 comments on commit 13d7d6e

Please sign in to comment.