From 89dd8146cac02bc1dfcbffd5dfd9152b0b71bf47 Mon Sep 17 00:00:00 2001 From: bohmber Date: Thu, 24 Jan 2019 23:21:40 +0100 Subject: [PATCH 1/3] allow to add secrets via annotation Signed-off-by: bohmber --- doc/src/main/asciidoc/inc/_enricher.adoc | 23 +++- .../standard/FileDataSecretEnricher.java | 87 +++++++++++++++ .../META-INF/fabric8/enricher-default | 3 + .../standard/FileDataSecretEnricherTest.java | 100 ++++++++++++++++++ .../META-INF/fabric8/profiles-default.yml | 1 + 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 enricher/standard/src/main/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricher.java create mode 100644 enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java diff --git a/doc/src/main/asciidoc/inc/_enricher.adoc b/doc/src/main/asciidoc/inc/_enricher.adoc index 91a7ef18ee..22117e2c86 100644 --- a/doc/src/main/asciidoc/inc/_enricher.adoc +++ b/doc/src/main/asciidoc/inc/_enricher.adoc @@ -87,6 +87,9 @@ fabric8-maven-plugin comes with a set of enrichers which are enabled by default. | <> | Add ConfigMap elements defined as XML or as annotation. + +| <> +| Add Secret elements defined as annotation. |=== [[enrichers-standard]] @@ -1141,11 +1144,29 @@ If you are defining a custom `ConfigMap` file, you can use an annotation to defi ---- metadata: name: ${project.artifactId} - maven.fabric8.io/cm/application.properties: src/test/resources/test-application.properties + annotations: + maven.fabric8.io/cm/application.properties: src/test/resources/test-application.properties ---- This creates a `ConfigMap` data with key `application.properties` (part defined after `cm`) and value the content of `src/test/resources/test-application.properties` file. +[[fmp-secret-file]] +==== fmp-secret-file + +This enricher adds Secret defined as file content from an annotation. + +If you are defining a custom `Secret` file, you can use an annotation to define a file name as key and its content as the value: + +[source, yaml] +---- +metadata: + name: ${project.artifactId} + annotations: + maven.fabric8.io/secret/application.properties: src/test/resources/test-application.properties +---- + +This creates a `Secret` data with the key `application.properties` (part defined after `secret`) and value content of `src/test/resources/test-application.properties` file (base64 encoded). + == Enricher API _howto write your own enricher and install them_ diff --git a/enricher/standard/src/main/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricher.java b/enricher/standard/src/main/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricher.java new file mode 100644 index 0000000000..d594b64979 --- /dev/null +++ b/enricher/standard/src/main/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricher.java @@ -0,0 +1,87 @@ +/** + * Copyright 2016 Red Hat, Inc. + * + * Red Hat licenses this file to you 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 io.fabric8.maven.enricher.standard; + +import io.fabric8.kubernetes.api.builder.TypedVisitor; +import io.fabric8.kubernetes.api.model.KubernetesListBuilder; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.maven.core.util.Base64Util; +import io.fabric8.maven.enricher.api.BaseEnricher; +import io.fabric8.maven.enricher.api.MavenEnricherContext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class FileDataSecretEnricher extends BaseEnricher { + + protected static final String PREFIX_ANNOTATION = "maven.fabric8.io/secret/"; + + public FileDataSecretEnricher(MavenEnricherContext buildContext) { + super(buildContext, "fmp-secret-file"); + } + + @Override + public void addMissingResources(KubernetesListBuilder builder) { + addAnnotations(builder); + } + + private void addAnnotations(KubernetesListBuilder builder) { + builder.accept(new TypedVisitor() { + + @Override + public void visit(SecretBuilder element) { + final Map annotations = element.buildMetadata().getAnnotations(); + try { + final Map secretAnnotations = createSecretFromAnnotations(annotations); + element.addToData(secretAnnotations); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + }); + } + + private Map createSecretFromAnnotations(final Map annotations) throws IOException { + final Set> entries = annotations.entrySet(); + final Map secretFileLocations = new HashMap<>(); + + for(Iterator> it = entries.iterator(); it.hasNext(); ) { + Map.Entry entry = it.next(); + final String key = entry.getKey(); + + if(key.startsWith(PREFIX_ANNOTATION)) { + byte[] bytes = readContent(entry.getValue()); + secretFileLocations.put(getOutput(key), Base64Util.encodeToString(bytes)); + it.remove(); + } + } + + return secretFileLocations; + } + + private byte[] readContent(String location) throws IOException { + return Files.readAllBytes(Paths.get(location)); + } + + private String getOutput(String key) { + return key.substring(PREFIX_ANNOTATION.length()); + } +} diff --git a/enricher/standard/src/main/resources/META-INF/fabric8/enricher-default b/enricher/standard/src/main/resources/META-INF/fabric8/enricher-default index 6f8251a12d..cfeebd48a5 100644 --- a/enricher/standard/src/main/resources/META-INF/fabric8/enricher-default +++ b/enricher/standard/src/main/resources/META-INF/fabric8/enricher-default @@ -76,3 +76,6 @@ io.fabric8.maven.enricher.standard.openshift.ExposeEnricher # Enhance a given controller with the configuration information presented in the plugin configuration. io.fabric8.maven.enricher.standard.ControllerViaPluginConfigurationEnricher + +# Add Secret enricher +io.fabric8.maven.enricher.standard.FileDataSecretEnricher diff --git a/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java b/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java new file mode 100644 index 0000000000..e44a9dc282 --- /dev/null +++ b/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java @@ -0,0 +1,100 @@ +/** + * Copyright 2016 Red Hat, Inc. + * + * Red Hat licenses this file to you 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 io.fabric8.maven.enricher.standard; + +import io.fabric8.kubernetes.api.model.KubernetesListBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.maven.core.config.ResourceConfig; +import io.fabric8.maven.core.model.Configuration; +import io.fabric8.maven.core.util.Base64Util; +import io.fabric8.maven.enricher.api.MavenEnricherContext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import mockit.Expectations; +import mockit.Mocked; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FileDataSecretEnricherTest { + + private static final String TEST_APPLICATION_PROPERTIES_PATH = "src/test/resources/test-application.properties"; + private static final String TEST_APPLICATION_PROPERTIES = "test-application.properties"; + @Mocked + private MavenEnricherContext context; + + @Test + public void should_materialize_file_content_from_annotation() throws IOException { + + // Given + + new Expectations() { + {{ + context.getConfiguration(); + result = new Configuration.Builder() + .resource(new ResourceConfig()) + .build(); + }} + + }; + + final FileDataSecretEnricher fileDataSecretEnricher = + new FileDataSecretEnricher(context); + final KubernetesListBuilder builder = new KubernetesListBuilder(); + builder.addToSecretItems(createBaseSecret()); + + // When + fileDataSecretEnricher.addMissingResources(builder); + + // Then + final Secret secret = (Secret) builder.buildFirstItem(); + + final Map data = secret.getData(); + assertThat(data) + .containsKey(TEST_APPLICATION_PROPERTIES); + + assertThat(data.get(TEST_APPLICATION_PROPERTIES)) + .isEqualTo(Base64Util + .encodeToString(Files.readAllBytes(Paths.get(TEST_APPLICATION_PROPERTIES_PATH)))); + + final Map annotations = secret.getMetadata().getAnnotations(); + assertThat(annotations) + .isEmpty(); + } + + private Secret createBaseSecret() { + ObjectMetaBuilder metaBuilder = new ObjectMetaBuilder() + .withNamespace("default"); + + Map annotations = new HashMap<>(); + annotations.put(FileDataSecretEnricher.PREFIX_ANNOTATION + TEST_APPLICATION_PROPERTIES, + TEST_APPLICATION_PROPERTIES_PATH); + metaBuilder = metaBuilder.withAnnotations(annotations); + + Map data = new HashMap<>(); + return new SecretBuilder() + .withData(data) + .withMetadata(metaBuilder.build()) + .build(); + } +} + diff --git a/plugin/src/main/resources/META-INF/fabric8/profiles-default.yml b/plugin/src/main/resources/META-INF/fabric8/profiles-default.yml index e0c355208f..92cad75b12 100644 --- a/plugin/src/main/resources/META-INF/fabric8/profiles-default.yml +++ b/plugin/src/main/resources/META-INF/fabric8/profiles-default.yml @@ -39,6 +39,7 @@ - fmp-remove-build-annotations - fmp-volume-permission - fmp-configmap-file + - fmp-secret-file # Route exposure - fmp-openshift-service-expose From cd3bc90cad7210a2040315a02265ed620780ff29 Mon Sep 17 00:00:00 2001 From: bohmber Date: Fri, 25 Jan 2019 04:44:29 +0100 Subject: [PATCH 2/3] allow to add secrets via annotation Signed-off-by: bohmber --- .../maven/enricher/standard/FileDataSecretEnricherTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java b/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java index e44a9dc282..99d3c8031c 100644 --- a/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java +++ b/enricher/standard/src/test/java/io/fabric8/maven/enricher/standard/FileDataSecretEnricherTest.java @@ -43,7 +43,7 @@ public class FileDataSecretEnricherTest { private MavenEnricherContext context; @Test - public void should_materialize_file_content_from_annotation() throws IOException { + public void shouldMaterializeFileContentFromAnnotation() throws IOException { // Given From 467436685c322bf8f52e814b7c98f3904352ed1e Mon Sep 17 00:00:00 2001 From: bohmber Date: Fri, 25 Jan 2019 16:53:11 +0100 Subject: [PATCH 3/3] allow to add secrets via annotation Signed-off-by: bohmber --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b4b28dbd..b0efa515a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ After this we will switch probably to real [Semantic Versioning 2.0.0](http://se * Fix 925: Unable to configure replicas count via property * Feature 804: Allow set fragments as external references (URL) * Fix 788: Added Git URL to GitEnricher. -* Feature 718: Detect port number from configuration file for health check in Thorntail +* Feature 718: Detect port number from configuration file for health check in Thorntail +* Feature 1498: Allow users to define secrets from annotations ### 4.0.0-M2 (2018-12-14) * Fix 10: Make VolumeConfiguration more flexible