Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Allows user to define Secret from annotation #1498

Merged
merged 3 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 22 additions & 1 deletion doc/src/main/asciidoc/inc/_enricher.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ fabric8-maven-plugin comes with a set of enrichers which are enabled by default.

| <<fmp-configmap-file>>
| Add ConfigMap elements defined as XML or as annotation.

| <<fmp-secret-file>>
| Add Secret elements defined as annotation.
|===

[[enrichers-standard]]
Expand Down Expand Up @@ -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_
Original file line number Diff line number Diff line change
@@ -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<SecretBuilder>() {

@Override
public void visit(SecretBuilder element) {
final Map<String, String> annotations = element.buildMetadata().getAnnotations();
try {
final Map<String, String> secretAnnotations = createSecretFromAnnotations(annotations);
element.addToData(secretAnnotations);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}

private Map<String, String> createSecretFromAnnotations(final Map<String, String> annotations) throws IOException {
final Set<Map.Entry<String, String>> entries = annotations.entrySet();
final Map<String, String> secretFileLocations = new HashMap<>();

for(Iterator<Map.Entry<String, String>> it = entries.iterator(); it.hasNext(); ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @bohmber why not just use

for (Map.Entry<String, String> entry : annotations.entrySet( ) )

?
The FMP code base uses this way of iteration everywhere, so it would look uniform with the codebase if you change it to this style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a modified copy of the ConfigMapEnricher and i think the iterator is needed for the remove a few lines later

it.remove();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i see

Map.Entry<String, String> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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 shouldMaterializeFileContentFromAnnotation() 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<String, String> 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<String, String> annotations = secret.getMetadata().getAnnotations();
assertThat(annotations)
.isEmpty();
}

private Secret createBaseSecret() {
ObjectMetaBuilder metaBuilder = new ObjectMetaBuilder()
.withNamespace("default");

Map<String, String> annotations = new HashMap<>();
annotations.put(FileDataSecretEnricher.PREFIX_ANNOTATION + TEST_APPLICATION_PROPERTIES,
TEST_APPLICATION_PROPERTIES_PATH);
metaBuilder = metaBuilder.withAnnotations(annotations);

Map<String, String> data = new HashMap<>();
return new SecretBuilder()
.withData(data)
.withMetadata(metaBuilder.build())
.build();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- fmp-remove-build-annotations
- fmp-volume-permission
- fmp-configmap-file
- fmp-secret-file

# Route exposure
- fmp-openshift-service-expose
Expand Down