Skip to content

Commit

Permalink
Merge pull request #8376 from geoand/#6745
Browse files Browse the repository at this point in the history
Support Kubernetes ConfigMap and Secrets as configuration/value sources
  • Loading branch information
geoand authored Apr 6, 2020
2 parents 7c646af + feaddb8 commit 99b5ddc
Show file tree
Hide file tree
Showing 28 changed files with 1,140 additions and 4 deletions.
5 changes: 5 additions & 0 deletions bom/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@
<artifactId>quarkus-kubernetes-client-deployment-internal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-config-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-flyway-deployment</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions bom/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,11 @@
<artifactId>quarkus-kubernetes-client-internal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-optaplanner</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions extensions/kubernetes-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
<groupId>org.jboss.spec.javax.xml.bind</groupId>
<artifactId>jboss-jaxb-api_2.3_spec</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.config</groupId>
<artifactId>smallrye-config-source-yaml</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
43 changes: 43 additions & 0 deletions extensions/kubernetes-config/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-kubernetes-config-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-kubernetes-config-deployment</artifactId>
<name>Quarkus - Kubernetes Config - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client-deployment</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-config</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.kubernetes.config.deployment;

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.RunTimeConfigurationSourceValueBuildItem;
import io.quarkus.kubernetes.client.runtime.KubernetesClientBuildConfig;
import io.quarkus.kubernetes.client.runtime.KubernetesConfigRecorder;
import io.quarkus.kubernetes.client.runtime.KubernetesConfigSourceConfig;

public class KubernetesConfigProcessor {

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public RunTimeConfigurationSourceValueBuildItem configure(KubernetesConfigRecorder recorder,
KubernetesConfigSourceConfig config, KubernetesClientBuildConfig clientConfig) {
return new RunTimeConfigurationSourceValueBuildItem(
recorder.configSources(config, clientConfig));
}
}
20 changes: 20 additions & 0 deletions extensions/kubernetes-config/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-build-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../../build-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-kubernetes-config-parent</artifactId>
<name>Quarkus - Kubernetes Config</name>
<packaging>pom</packaging>
<modules>
<module>deployment</module>
<module>runtime</module>
</modules>
</project>
56 changes: 56 additions & 0 deletions extensions/kubernetes-config/runtime/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-config-parent</artifactId>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>quarkus-kubernetes-config</artifactId>
<name>Quarkus - Kubernetes Config - Runtime</name>
<description>Read runtime configuration from Kubernetes ConfigMaps and Secrets</description>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bootstrap-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>


</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package io.quarkus.kubernetes.client.runtime;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.microprofile.config.spi.ConfigSource;
import org.jboss.logging.Logger;

abstract class AbstractKubernetesConfigSourceUtil {

private static final Logger log = Logger.getLogger(AbstractKubernetesConfigSourceUtil.class);

private static final String APPLICATION_YML = "application.yml";
private static final String APPLICATION_YAML = "application.yaml";
private static final String APPLICATION_PROPERTIES = "application.properties";

private static final int ORDINAL = 270; // this is higher than the file system or jar ordinals, but lower than env vars

abstract String getType();

abstract ConfigSource createLiteralDataConfigSource(String kubernetesConfigSourceName, Map<String, String> propertyMap,
int ordinal);

abstract ConfigSource createPropertiesConfigSource(String kubernetesConfigSourceName, String fileName, String input,
int ordinal);

abstract ConfigSource createYamlConfigSource(String kubernetesConfigSourceName, String fileName, String input, int ordinal);

/**
* Returns a list of {@code ConfigSource} for the literal data that is contained in the ConfigMap
* and for the application.{properties|yaml|yml} files that might be contained in it as well
*
* All the {@code ConfigSource} objects use the same ordinal which is higher than the ordinal
* of normal configuration files, but lower than that of environment variables
*/
List<ConfigSource> toConfigSources(String kubernetesConfigSourceName, Map<String, String> kubernetesConfigSourceDataMap) {
if (log.isDebugEnabled()) {
log.debug("Attempting to convert data in " + getType() + " '" + kubernetesConfigSourceName
+ "' to a list of ConfigSource objects");
}

CategorizedConfigSourceData categorizedConfigSourceData = categorize(kubernetesConfigSourceDataMap);
List<ConfigSource> result = new ArrayList<>(categorizedConfigSourceData.fileData.size() + 1);

if (!categorizedConfigSourceData.literalData.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug(
"Adding a ConfigSource for the literal data of " + getType() + " '" + kubernetesConfigSourceName + "'");
}
result.add(createLiteralDataConfigSource(kubernetesConfigSourceName + "-literalData",
categorizedConfigSourceData.literalData,
ORDINAL));
}
for (Map.Entry<String, String> entry : categorizedConfigSourceData.fileData) {
String fileName = entry.getKey();
String rawFileData = entry.getValue();
if (APPLICATION_PROPERTIES.equals(fileName)) {
if (log.isDebugEnabled()) {
log.debug("Adding a Properties ConfigSource for file '" + fileName + "' of " + getType()
+ " '" + kubernetesConfigSourceName + "'");
}
result.add(createPropertiesConfigSource(kubernetesConfigSourceName, fileName, rawFileData, ORDINAL));
} else if (APPLICATION_YAML.equals(fileName) || APPLICATION_YML.equals(fileName)) {
if (log.isDebugEnabled()) {
log.debug("Adding a YAML ConfigSource for file '" + fileName + "' of " + getType()
+ " '" + kubernetesConfigSourceName + "'");
}
result.add(createYamlConfigSource(kubernetesConfigSourceName, fileName, rawFileData, ORDINAL));
}
}

if (log.isDebugEnabled()) {
log.debug(getType() + " '" + kubernetesConfigSourceName + "' converted into " + result.size()
+ "ConfigSource objects");
}
return result;
}

private static CategorizedConfigSourceData categorize(Map<String, String> data) {
if ((data == null) || data.isEmpty()) {
return new CategorizedConfigSourceData(Collections.emptyMap(), Collections.emptyList());
}

Map<String, String> literalData = new HashMap<>();
List<Map.Entry<String, String>> fileData = new ArrayList<>();
for (Map.Entry<String, String> entry : data.entrySet()) {
String key = entry.getKey();
if (key.endsWith(".yml") || key.endsWith(".yaml") || key.endsWith(".properties")) {
fileData.add(entry);
} else {
literalData.put(key, entry.getValue());
}
}

return new CategorizedConfigSourceData(literalData, fileData);
}

private static class CategorizedConfigSourceData {
final Map<String, String> literalData;
final List<Map.Entry<String, String>> fileData;

CategorizedConfigSourceData(Map<String, String> literalData, List<Map.Entry<String, String>> fileData) {
this.literalData = literalData;
this.fileData = fileData;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.quarkus.kubernetes.client.runtime;

import java.io.IOException;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.util.Map;
import java.util.Properties;

import org.eclipse.microprofile.config.spi.ConfigSource;

import io.smallrye.config.common.MapBackedConfigSource;
import io.smallrye.config.source.yaml.YamlConfigSource;

public class ConfigMapConfigSourceUtil extends AbstractKubernetesConfigSourceUtil {

@Override
String getType() {
return "ConfigMap";
}

@Override
ConfigSource createLiteralDataConfigSource(String kubernetesConfigSourceName, Map<String, String> propertyMap,
int ordinal) {
return new ConfigMapLiteralDataPropertiesConfigSource(kubernetesConfigSourceName, propertyMap, ordinal);
}

@Override
ConfigSource createPropertiesConfigSource(String kubernetesConfigSourceName, String fileName, String input, int ordinal) {
return new ConfigMapStringInputPropertiesConfigSource(kubernetesConfigSourceName, fileName, input, ordinal);
}

@Override
ConfigSource createYamlConfigSource(String kubernetesConfigSourceName, String fileName, String input, int ordinal) {
return new ConfigMapStringInputYamlConfigSource(kubernetesConfigSourceName, fileName, input, ordinal);
}

private static final class ConfigMapLiteralDataPropertiesConfigSource extends MapBackedConfigSource {

private static final String NAME_PREFIX = "ConfigMapLiteralDataPropertiesConfigSource[configMap=";

public ConfigMapLiteralDataPropertiesConfigSource(String configMapName, Map<String, String> propertyMap, int ordinal) {
super(NAME_PREFIX + configMapName + "]", propertyMap, ordinal);
}
}

private static class ConfigMapStringInputPropertiesConfigSource extends MapBackedConfigSource {

private static final String NAME_FORMAT = "ConfigMapStringInputPropertiesConfigSource[configMap=%s,file=%s]";

ConfigMapStringInputPropertiesConfigSource(String configMapName, String fileName, String input, int ordinal) {
super(String.format(NAME_FORMAT, configMapName, fileName), readProperties(input), ordinal);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private static Map<String, String> readProperties(String rawData) {
try (StringReader br = new StringReader(rawData)) {
final Properties properties = new Properties();
properties.load(br);
return (Map<String, String>) (Map) properties;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

private static class ConfigMapStringInputYamlConfigSource extends YamlConfigSource {

private static final String NAME_FORMAT = "ConfigMapStringInputYamlConfigSource[configMap=%s,file=%s]";

public ConfigMapStringInputYamlConfigSource(String configMapName, String fileName, String input, int ordinal) {
super(String.format(NAME_FORMAT, configMapName, fileName), input, ordinal);
}
}
}
Loading

0 comments on commit 99b5ddc

Please sign in to comment.