From 07d9904a8dae00462a5b1ad410a633c615c6ee86 Mon Sep 17 00:00:00 2001 From: Lars Wander Date: Tue, 19 Sep 2017 16:48:17 -0400 Subject: [PATCH] feat(provider/kubernetes): Register k8s moniker for manifests --- clouddriver-core/clouddriver-core.gradle | 3 + .../clouddriver/names/NamerRegistry.java | 94 +++++++++++++++++++ .../clouddriver-kubernetes.gradle | 1 + .../KubernetesNamedAccountCredentials.java | 8 ++ .../KubernetesAugmentedManifest.java | 2 +- .../v2/names/KubernetesManifestNamer.java | 42 +++++++++ 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 clouddriver-core/src/main/groovy/com/netflix/spinnaker/clouddriver/names/NamerRegistry.java create mode 100644 clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/names/KubernetesManifestNamer.java diff --git a/clouddriver-core/clouddriver-core.gradle b/clouddriver-core/clouddriver-core.gradle index e2d2f9e5f85..debe55ab3f2 100644 --- a/clouddriver-core/clouddriver-core.gradle +++ b/clouddriver-core/clouddriver-core.gradle @@ -10,6 +10,7 @@ dependencies { compile spinnaker.dependency('eurekaClient') compile spinnaker.dependency("jedis") compile spinnaker.dependency("frigga") + compile spinnaker.dependency("lombok") compile project(':cats:cats-core') compile project(':cats:cats-redis') @@ -17,4 +18,6 @@ dependencies { compile project(':clouddriver-security') testCompile project(':cats:cats-test') testCompile spinnaker.dependency('korkJedisTest') + + compile 'com.netflix.spinnaker.moniker:moniker:0.2.0' } diff --git a/clouddriver-core/src/main/groovy/com/netflix/spinnaker/clouddriver/names/NamerRegistry.java b/clouddriver-core/src/main/groovy/com/netflix/spinnaker/clouddriver/names/NamerRegistry.java new file mode 100644 index 00000000000..10814de510b --- /dev/null +++ b/clouddriver-core/src/main/groovy/com/netflix/spinnaker/clouddriver/names/NamerRegistry.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.netflix.spinnaker.clouddriver.names; + +import com.netflix.spinnaker.moniker.Namer; +import com.netflix.spinnaker.moniker.frigga.FriggaReflectiveNamer; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * The idea is each provider can register (per-account) based on config naming + * strategy. This assigns a `moniker` to any named resource which is then pushed + * through the rest of Spinnaker and can be handled without prior knowledge of what + * naming strategy was used. This is the only place the mapping from (provider, account, resource) -> namer + * must happen within Spinnaker. + */ +public class NamerRegistry { + private static Namer defaultNamer = new FriggaReflectiveNamer(); + private static ProviderLookup providerLookup = new ProviderLookup(); + + public static Namer getDefaultNamer() { + return defaultNamer; + } + + public static ProviderLookup lookup() { + return providerLookup; + } + + @Slf4j + public static class ResourceLookup { + private ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public Namer withResource(Class resource) { + if (!map.containsKey(resource)) { + log.debug("Looking up a namer for a non-registered resource"); + return getDefaultNamer(); + } else { + return map.get(resource); + } + } + + public void setNamer(Class resource, Namer namer) { + map.put(resource, namer); + } + } + + @Slf4j + public static class AccountLookup { + private ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public ResourceLookup withAccount(String accountName) { + if (!map.containsKey(accountName)) { + log.debug("Looking up a namer for a non-registered account"); + ResourceLookup result = new ResourceLookup(); + map.put(accountName, result); + return result; + } else { + return map.get(accountName); + } + } + } + + @Slf4j + public static class ProviderLookup { + private ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public AccountLookup withProvider(String providerName) { + if (!map.containsKey(providerName)) { + log.debug("Looking up a namer for a non-registered provider"); + AccountLookup result = new AccountLookup(); + map.put(providerName, result); + return result; + } else { + return map.get(providerName); + } + } + } +} diff --git a/clouddriver-kubernetes/clouddriver-kubernetes.gradle b/clouddriver-kubernetes/clouddriver-kubernetes.gradle index c4231472e56..9cfc2abc151 100644 --- a/clouddriver-kubernetes/clouddriver-kubernetes.gradle +++ b/clouddriver-kubernetes/clouddriver-kubernetes.gradle @@ -11,4 +11,5 @@ dependencies { // TODO(lwander) move to spinnaker-dependencies when library stabilizes compile 'io.kubernetes:client-java-util:0.1' compile 'com.github.fge:json-patch:1.9' + compile 'com.netflix.spinnaker.moniker:moniker:0.2.0' } diff --git a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/security/KubernetesNamedAccountCredentials.java b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/security/KubernetesNamedAccountCredentials.java index cb60e343f02..2b4bdd95991 100644 --- a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/security/KubernetesNamedAccountCredentials.java +++ b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/security/KubernetesNamedAccountCredentials.java @@ -17,9 +17,13 @@ package com.netflix.spinnaker.clouddriver.kubernetes.security; import com.netflix.spectator.api.Registry; +import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesCloudProvider; import com.netflix.spinnaker.clouddriver.kubernetes.config.LinkedDockerRegistryConfiguration; import com.netflix.spinnaker.clouddriver.kubernetes.v1.security.KubernetesV1Credentials; +import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesManifest; +import com.netflix.spinnaker.clouddriver.kubernetes.v2.names.KubernetesManifestNamer; import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials; +import com.netflix.spinnaker.clouddriver.names.NamerRegistry; import com.netflix.spinnaker.clouddriver.security.AccountCredentials; import com.netflix.spinnaker.clouddriver.security.AccountCredentialsRepository; import com.netflix.spinnaker.clouddriver.security.ProviderVersion; @@ -283,6 +287,10 @@ private C buildCredentials() { accountCredentialsRepository ); case v2: + NamerRegistry.lookup() + .withProvider(KubernetesCloudProvider.getID()) + .withAccount(name) + .setNamer(KubernetesManifest.class, new KubernetesManifestNamer()); return (C) new KubernetesV2Credentials(name, spectatorRegistry); default: throw new IllegalArgumentException("Unknown provider type: " + version); diff --git a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/description/KubernetesAugmentedManifest.java b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/description/KubernetesAugmentedManifest.java index 1e67711e454..5662a6dcae3 100644 --- a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/description/KubernetesAugmentedManifest.java +++ b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/description/KubernetesAugmentedManifest.java @@ -26,7 +26,7 @@ public class KubernetesAugmentedManifest { Metadata metadata; @Data - public class Metadata { + public static class Metadata { KubernetesManifestSpinnakerRelationships relationships; Artifact artifact; } diff --git a/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/names/KubernetesManifestNamer.java b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/names/KubernetesManifestNamer.java new file mode 100644 index 00000000000..f1127dce61e --- /dev/null +++ b/clouddriver-kubernetes/src/main/groovy/com/netflix/spinnaker/clouddriver/kubernetes/v2/names/KubernetesManifestNamer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.netflix.spinnaker.clouddriver.kubernetes.v2.names; + +import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesManifest; +import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesManifestAnnotater; +import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesManifestSpinnakerRelationships; +import com.netflix.spinnaker.moniker.Moniker; +import com.netflix.spinnaker.moniker.Namer; +import org.apache.commons.lang3.NotImplementedException; + +public class KubernetesManifestNamer implements Namer { + @Override + public void applyMoniker(KubernetesManifest obj, Moniker moniker) { + throw new NotImplementedException("TODO(lwander)"); + } + + @Override + public Moniker deriveMoniker(KubernetesManifest obj) { + KubernetesManifestSpinnakerRelationships relationships = KubernetesManifestAnnotater.getManifestRelationships(obj); + + return Moniker.builder() + .app(relationships.getApplication()) + .cluster(relationships.getCluster()) + .build(); + } +}