diff --git a/clouddriver-kubernetes/clouddriver-kubernetes.gradle b/clouddriver-kubernetes/clouddriver-kubernetes.gradle index 1faeb14a867..4b18b1690dc 100644 --- a/clouddriver-kubernetes/clouddriver-kubernetes.gradle +++ b/clouddriver-kubernetes/clouddriver-kubernetes.gradle @@ -22,6 +22,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-actuator" implementation "org.springframework.boot:spring-boot-starter-web" implementation 'com.jayway.jsonpath:json-path:2.3.0' + implementation "com.github.ben-manes.caffeine:guava" testImplementation "cglib:cglib-nodep" testImplementation "org.objenesis:objenesis" diff --git a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/security/KubernetesV2Credentials.java b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/security/KubernetesV2Credentials.java index 0168a7ae127..c306da251fb 100644 --- a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/security/KubernetesV2Credentials.java +++ b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/security/KubernetesV2Credentials.java @@ -18,7 +18,8 @@ package com.netflix.spinnaker.clouddriver.kubernetes.v2.security; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.google.common.base.Suppliers; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.netflix.spectator.api.Clock; import com.netflix.spectator.api.Registry; import com.netflix.spinnaker.clouddriver.kubernetes.config.CustomKubernetesResource; @@ -90,8 +91,8 @@ public class KubernetesV2Credentials implements KubernetesCredentials { @Getter private final boolean debug; private String cachedDefaultNamespace; - private final com.google.common.base.Supplier> liveNamespaceSupplier; - private final com.google.common.base.Supplier> liveCrdSupplier; + private final Supplier> liveNamespaceSupplier; + private final Supplier> liveCrdSupplier; public KubernetesV2Credentials( Registry registry, @@ -131,9 +132,10 @@ public KubernetesV2Credentials( this.debug = managedAccount.getDebug(); this.liveNamespaceSupplier = - Suppliers.memoizeWithExpiration( - () -> - jobExecutor + Memoizer.memoizeWithExpiration( + () -> { + try { + return jobExecutor .list( this, Collections.singletonList(KubernetesKind.NAMESPACE), @@ -141,12 +143,18 @@ public KubernetesV2Credentials( new KubernetesSelectorList()) .stream() .map(KubernetesManifest::getName) - .collect(Collectors.toList()), + .collect(Collectors.toList()); + } catch (KubectlException e) { + log.error( + "Could not list namespaces for account {}: {}", accountName, e.getMessage()); + return new ArrayList<>(); + } + }, NAMESPACE_EXPIRY_SECONDS, TimeUnit.SECONDS); this.liveCrdSupplier = - Suppliers.memoizeWithExpiration( + Memoizer.memoizeWithExpiration( () -> { try { return this.list(KubernetesKind.CUSTOM_RESOURCE_DEFINITION, "").stream() @@ -177,6 +185,30 @@ public KubernetesV2Credentials( TimeUnit.SECONDS); } + /** + * Thin wrapper around a Caffeine cache that handles memoizing a supplier function with expiration + */ + private static class Memoizer implements Supplier { + private static String CACHE_KEY = "key"; + LoadingCache cache; + + private Memoizer(Supplier supplier, long expirySeconds, TimeUnit timeUnit) { + this.cache = + Caffeine.newBuilder() + .expireAfterWrite(expirySeconds, timeUnit) + .build(key -> supplier.get()); + } + + public T get() { + return cache.get(CACHE_KEY); + } + + public static Memoizer memoizeWithExpiration( + Supplier supplier, long expirySeconds, TimeUnit timeUnit) { + return new Memoizer<>(supplier, expirySeconds, timeUnit); + } + } + public enum InvalidKindReason { KIND_NONE("Kind [%s] is invalid"), EXPLICITLY_OMITTED_BY_CONFIGURATION( @@ -273,13 +305,7 @@ public List getDeclaredNamespaces() { if (!namespaces.isEmpty()) { result = namespaces; } else { - try { - result = liveNamespaceSupplier.get(); - - } catch (KubectlException e) { - log.warn("Could not list namespaces for account {}: {}", accountName, e.getMessage()); - return new ArrayList<>(); - } + result = liveNamespaceSupplier.get(); } if (!omitNamespaces.isEmpty()) {