Updates formatting and license header

This commit is contained in:
Spencer Gibb
2018-08-03 13:45:46 -04:00
parent b65f7fc30f
commit b281bd2d28
98 changed files with 2545 additions and 1901 deletions

27
pom.xml
View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,36 +17,35 @@
package org.springframework.cloud.kubernetes.config;
public abstract class AbstractConfigProperties {
protected boolean enabled = true;
protected String name;
protected String namespace;
protected boolean enabled = true;
protected String name;
protected String namespace;
public abstract String getConfigurationTarget();
public abstract String getConfigurationTarget();
public boolean isEnabled() {
return enabled;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getNamespace() {
return namespace;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -20,11 +20,12 @@ package org.springframework.cloud.kubernetes.config;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.cloud.kubernetes.KubernetesAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.KubernetesAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -34,22 +35,25 @@ import org.springframework.context.annotation.Import;
@ConditionalOnClass({ ConfigMap.class, Secret.class })
public class BootstrapConfiguration {
@Configuration
@Import(KubernetesAutoConfiguration.class)
@EnableConfigurationProperties({ ConfigMapConfigProperties.class, SecretsConfigProperties.class })
@ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true)
protected static class KubernetesPropertySourceConfiguration {
@Autowired
private KubernetesClient client;
@Configuration
@Import(KubernetesAutoConfiguration.class)
@EnableConfigurationProperties({ ConfigMapConfigProperties.class,
SecretsConfigProperties.class })
@ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true)
protected static class KubernetesPropertySourceConfiguration {
@Autowired
private KubernetesClient client;
@Bean
public ConfigMapPropertySourceLocator configMapPropertySourceLocator(ConfigMapConfigProperties properties) {
return new ConfigMapPropertySourceLocator(client, properties);
}
@Bean
public ConfigMapPropertySourceLocator configMapPropertySourceLocator(
ConfigMapConfigProperties properties) {
return new ConfigMapPropertySourceLocator(client, properties);
}
@Bean
public SecretsPropertySourceLocator secretsPropertySourceLocator(SecretsConfigProperties properties) {
return new SecretsPropertySourceLocator(client, properties);
}
}
@Bean
public SecretsPropertySourceLocator secretsPropertySourceLocator(
SecretsConfigProperties properties) {
return new SecretsPropertySourceLocator(client, properties);
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -21,13 +21,14 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
@ConfigurationProperties("spring.cloud.kubernetes.config")
public class ConfigMapConfigProperties extends AbstractConfigProperties {
private static final String TARGET = "Config Map";
private static final String TARGET = "Config Map";
private boolean enableApi = true;
private List<String> paths = new LinkedList<>();
@@ -58,28 +59,32 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
}
/**
* @return A list of Source to use
* If the user has not specified any Source properties, then a single Source
* is constructed based on the supplied name and namespace
* @return A list of Source to use If the user has not specified any Source
* properties, then a single Source is constructed based on the supplied name and
* namespace
*
* These are the actual name/namespace pairs that are used to create a ConfigMapPropertySource
* These are the actual name/namespace pairs that are used to create a
* ConfigMapPropertySource
*/
public List<NormalizedSource> determineSources() {
if (sources.isEmpty()) {
return new ArrayList<NormalizedSource>() {{
add(new NormalizedSource(name, namespace));
}};
return new ArrayList<NormalizedSource>() {
{
add(new NormalizedSource(name, namespace));
}
};
}
return sources.stream().map(s -> s.normalize(name, namespace)).collect(Collectors.toList());
return sources.stream().map(s -> s.normalize(name, namespace))
.collect(Collectors.toList());
}
@Override
public String getConfigurationTarget() {
return TARGET;
}
public String getConfigurationTarget() {
return TARGET;
}
public static class Source {
public static class Source {
/**
* The name of the ConfigMap
@@ -120,10 +125,10 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
}
public NormalizedSource normalize(String defaultName, String defaultNamespace) {
final String normalizedName =
StringUtils.isEmpty(this.name) ? defaultName : this.name;
final String normalizedNamespace =
StringUtils.isEmpty(this.namespace) ? defaultNamespace : this.namespace;
final String normalizedName = StringUtils.isEmpty(this.name) ? defaultName
: this.name;
final String normalizedNamespace = StringUtils.isEmpty(this.namespace)
? defaultNamespace : this.namespace;
return new NormalizedSource(normalizedName, normalizedNamespace);
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,13 +17,6 @@
package org.springframework.cloud.kubernetes.config;
import static java.util.Arrays.asList;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.ABSTAIN;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.FOUND;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.NOT_FOUND;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
@@ -33,58 +26,72 @@ import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.StringUtils;
import static java.util.Arrays.asList;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.ABSTAIN;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.FOUND;
import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus.NOT_FOUND;
public class ConfigMapPropertySource extends KubernetesPropertySource {
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySource.class);
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySource.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 String APPLICATION_YML = "application.yml";
private static final String APPLICATION_YAML = "application.yaml";
private static final String APPLICATION_PROPERTIES = "application.properties";
private static final String PREFIX = "configmap";
private static final String PREFIX = "configmap";
public ConfigMapPropertySource(KubernetesClient client, String name, ConfigMapConfigProperties config) {
public ConfigMapPropertySource(KubernetesClient client, String name,
ConfigMapConfigProperties config) {
this(client, name, null, config);
}
public ConfigMapPropertySource(KubernetesClient client, String name, String[] profiles, ConfigMapConfigProperties config) {
this(client, name, null, profiles, config);
}
public ConfigMapPropertySource(KubernetesClient client, String name,
String[] profiles, ConfigMapConfigProperties config) {
this(client, name, null, profiles, config);
}
public ConfigMapPropertySource(KubernetesClient client, String name, String namespace, String[] profiles, ConfigMapConfigProperties config) {
super(getName(client, name, namespace), asObjectMap(getData(client, name, namespace, profiles, config)));
}
public ConfigMapPropertySource(KubernetesClient client, String name, String namespace,
String[] profiles, ConfigMapConfigProperties config) {
super(getName(client, name, namespace),
asObjectMap(getData(client, name, namespace, profiles, config)));
}
private static String getName(KubernetesClient client, String name, String namespace) {
return new StringBuilder()
.append(PREFIX)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(name)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(namespace == null || namespace.isEmpty() ? client.getNamespace() : namespace)
.toString();
}
private static String getName(KubernetesClient client, String name,
String namespace) {
return new StringBuilder().append(PREFIX)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(namespace == null || namespace.isEmpty() ? client.getNamespace()
: namespace)
.toString();
}
private static Map<String, String> getData(KubernetesClient client, String name, String namespace,
String[] profiles, ConfigMapConfigProperties config) {
Map<String, String> result = new HashMap<>();
private static Map<String, String> getData(KubernetesClient client, String name,
String namespace, String[] profiles, ConfigMapConfigProperties config) {
Map<String, String> result = new HashMap<>();
if (config.isEnableApi()) {
try {
ConfigMap map = StringUtils.isEmpty(namespace)
? client.configMaps().withName(name).get()
: client.configMaps().inNamespace(namespace).withName(name).get();
? client.configMaps().withName(name).get()
: client.configMaps().inNamespace(namespace).withName(name).get();
if (map != null) {
result.putAll(processAllEntries(map.getData(), profiles));
}
} catch (Exception e) {
LOG.warn("Can't read configMap with name: [" + name + "] in namespace:[" + namespace + "]. Ignoring", e);
}
catch (Exception e) {
LOG.warn("Can't read configMap with name: [" + name + "] in namespace:["
+ namespace + "]. Ignoring", e);
}
}
@@ -92,29 +99,35 @@ public class ConfigMapPropertySource extends KubernetesPropertySource {
putPathConfig(configsFromPaths, config.getPaths());
result.putAll(processAllEntries(configsFromPaths, profiles));
return result;
}
}
private static Map<String, String> processAllEntries(Map<String, String> input,
String[] profiles) {
String[] profiles) {
Set<Entry<String, String>> entrySet = input.entrySet();
if(entrySet.size() == 1) {
if (entrySet.size() == 1) {
Entry<String, String> singleEntry = entrySet.iterator().next();
String propertyName = singleEntry.getKey();
String propertyValue = singleEntry.getValue();
if (propertyName.endsWith(".yml") || propertyName.endsWith(".yaml")) {
if (LOG.isDebugEnabled()) {
LOG.debug("The single property with name: [" + propertyName + "] will be treated as a yaml file");
LOG.debug("The single property with name: [" + propertyName
+ "] will be treated as a yaml file");
}
return yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP).apply(propertyValue);
} else if (propertyName.endsWith(".properties")) {
return yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP)
.apply(propertyValue);
}
else if (propertyName.endsWith(".properties")) {
if (LOG.isDebugEnabled()) {
LOG.debug("The single property with name: [" + propertyName + "] will be treated as a properties file");
LOG.debug("The single property with name: [" + propertyName
+ "] will be treated as a properties file");
}
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(propertyValue);
} else {
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP)
.apply(propertyValue);
}
else {
return defaultProcessAllEntries(input, profiles);
}
}
@@ -123,42 +136,48 @@ public class ConfigMapPropertySource extends KubernetesPropertySource {
}
private static Map<String, String> defaultProcessAllEntries(Map<String, String> input,
String[] profiles) {
String[] profiles) {
return input.entrySet().stream()
.map(e -> extractProperties(e.getKey(), e.getValue(), profiles))
.filter(m -> !m.isEmpty())
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
.map(e -> extractProperties(e.getKey(), e.getValue(), profiles))
.filter(m -> !m.isEmpty()).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
}
private static Map<String, String> extractProperties(String resourceName, String content, String[] profiles) {
private static Map<String, String> extractProperties(String resourceName,
String content, String[] profiles) {
Map<String, String> result = new HashMap<>();
if (resourceName.equals(APPLICATION_YAML) || resourceName.equals(APPLICATION_YML)) {
result.putAll(yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP).apply(content));
} else if (resourceName.equals(APPLICATION_PROPERTIES)) {
result.putAll(KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content));
} else {
if (resourceName.equals(APPLICATION_YAML)
|| resourceName.equals(APPLICATION_YML)) {
result.putAll(yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP)
.apply(content));
}
else if (resourceName.equals(APPLICATION_PROPERTIES)) {
result.putAll(
KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content));
}
else {
result.put(resourceName, content);
}
return result;
}
return result;
}
private static Map<String, Object> asObjectMap(Map<String, String> source) {
return source.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private static Map<String, Object> asObjectMap(Map<String, String> source) {
return source.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private static Function<String, Properties> yamlParserGenerator(final String[] profiles) {
private static Function<String, Properties> yamlParserGenerator(
final String[] profiles) {
return s -> {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
yamlFactory.setDocumentMatchers(properties -> {
String profileProperty = properties.getProperty("spring.profiles");
if (profileProperty != null && profileProperty.length() > 0) {
return asList(profiles).contains(profileProperty) ? FOUND : NOT_FOUND;
} else {
}
else {
return ABSTAIN;
}
});
@@ -167,20 +186,19 @@ public class ConfigMapPropertySource extends KubernetesPropertySource {
};
}
private static final Function<String, Properties> KEY_VALUE_TO_PROPERTIES = s -> {
Properties properties = new Properties();
try {
properties.load(new ByteArrayInputStream(s.getBytes()));
return properties;
} catch (IOException e) {
throw new IllegalArgumentException();
}
};
private static final Function<Properties, Map<String,String>> PROPERTIES_TO_MAP = p -> p.entrySet().stream()
.collect(Collectors.toMap(
e -> String.valueOf(e.getKey()),
e -> String.valueOf(e.getValue())));
private static final Function<String, Properties> KEY_VALUE_TO_PROPERTIES = s -> {
Properties properties = new Properties();
try {
properties.load(new ByteArrayInputStream(s.getBytes()));
return properties;
}
catch (IOException e) {
throw new IllegalArgumentException();
}
};
private static final Function<Properties, Map<String, String>> PROPERTIES_TO_MAP = p -> p
.entrySet().stream().collect(Collectors.toMap(e -> String.valueOf(e.getKey()),
e -> String.valueOf(e.getValue())));
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,11 +17,10 @@
package org.springframework.cloud.kubernetes.config;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
import java.util.List;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.util.List;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.cloud.kubernetes.config.ConfigMapConfigProperties.NormalizedSource;
import org.springframework.core.annotation.Order;
@@ -31,47 +30,50 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
@Order(0)
public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
private final KubernetesClient client;
private final ConfigMapConfigProperties properties;
private final KubernetesClient client;
private final ConfigMapConfigProperties properties;
public ConfigMapPropertySourceLocator(KubernetesClient client, ConfigMapConfigProperties properties) {
this.client = client;
this.properties = properties;
}
public ConfigMapPropertySourceLocator(KubernetesClient client,
ConfigMapConfigProperties properties) {
this.client = client;
this.properties = properties;
}
@Override
public PropertySource locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
@Override
public PropertySource locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
List<ConfigMapConfigProperties.NormalizedSource> sources =
properties.determineSources();
List<ConfigMapConfigProperties.NormalizedSource> sources = properties
.determineSources();
if (sources.size() == 1) {
return getMapPropertySourceForSingleConfigMap(env, sources.get(0));
}
CompositePropertySource composite = new CompositePropertySource("composite-configmap");
sources.forEach(s ->
composite.addFirstPropertySource(getMapPropertySourceForSingleConfigMap(env, s))
);
CompositePropertySource composite = new CompositePropertySource(
"composite-configmap");
sources.forEach(s -> composite.addFirstPropertySource(
getMapPropertySourceForSingleConfigMap(env, s)));
return composite;
}
return null;
}
return null;
}
private MapPropertySource getMapPropertySourceForSingleConfigMap(
ConfigurableEnvironment environment, NormalizedSource normalizedSource) {
ConfigurableEnvironment environment, NormalizedSource normalizedSource) {
String configurationTarget = properties.getConfigurationTarget();
return new ConfigMapPropertySource(
client,
getApplicationName(environment, normalizedSource.getName(), configurationTarget),
getApplicationNamespace(client, normalizedSource.getNamespace(), configurationTarget),
environment.getActiveProfiles(),
properties
);
String configurationTarget = properties.getConfigurationTarget();
return new ConfigMapPropertySource(client,
getApplicationName(environment, normalizedSource.getName(),
configurationTarget),
getApplicationNamespace(client, normalizedSource.getNamespace(),
configurationTarget),
environment.getActiveProfiles(), properties);
}
}

View File

@@ -1,12 +1,29 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import io.fabric8.kubernetes.client.KubernetesClient;
import static org.springframework.cloud.kubernetes.config.Constants.FALLBACK_APPLICATION_NAME;
import static org.springframework.cloud.kubernetes.config.Constants.SPRING_APPLICATION_NAME;
@@ -14,36 +31,38 @@ public class ConfigUtils {
private static final Log LOG = LogFactory.getLog(ConfigUtils.class);
public static <C extends AbstractConfigProperties> String getApplicationName(Environment env,
String configName, String configurationTarget) {
String name = configName;
if (StringUtils.isEmpty(name)) {
//TODO: use relaxed binding
if (LOG.isDebugEnabled()) {
LOG.debug(configurationTarget +
" name has not been set, taking it from property/env " +
SPRING_APPLICATION_NAME + " (default=" + FALLBACK_APPLICATION_NAME + ")");
}
public static <C extends AbstractConfigProperties> String getApplicationName(
Environment env, String configName, String configurationTarget) {
String name = configName;
if (StringUtils.isEmpty(name)) {
// TODO: use relaxed binding
if (LOG.isDebugEnabled()) {
LOG.debug(configurationTarget
+ " name has not been set, taking it from property/env "
+ SPRING_APPLICATION_NAME + " (default="
+ FALLBACK_APPLICATION_NAME + ")");
}
name = env.getProperty(SPRING_APPLICATION_NAME, FALLBACK_APPLICATION_NAME);
}
name = env.getProperty(SPRING_APPLICATION_NAME, FALLBACK_APPLICATION_NAME);
}
return name;
}
return name;
}
public static <C extends AbstractConfigProperties> String getApplicationNamespace(
KubernetesClient client, String configNamespace, String configurationTarget) {
String namespace = configNamespace;
if (StringUtils.isEmpty(namespace)) {
if (LOG.isDebugEnabled()) {
LOG.debug(
configurationTarget + " namespace has not been set, taking it from client (ns="+client.getNamespace()+")");
}
public static <C extends AbstractConfigProperties> String getApplicationNamespace(
KubernetesClient client, String configNamespace, String configurationTarget) {
String namespace = configNamespace;
if (StringUtils.isEmpty(namespace)) {
if (LOG.isDebugEnabled()) {
LOG.debug(configurationTarget
+ " namespace has not been set, taking it from client (ns="
+ client.getNamespace() + ")");
}
namespace = client.getNamespace();
}
namespace = client.getNamespace();
}
return namespace;
}
return namespace;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,10 +17,10 @@
package org.springframework.cloud.kubernetes.config;
final class Constants {
static final String SPRING_APPLICATION_NAME = "spring.application.name";
static final String FALLBACK_APPLICATION_NAME = "application";
static final String PROPERTY_SOURCE_NAME_SEPARATOR = ".";
static final String SPRING_APPLICATION_NAME = "spring.application.name";
static final String FALLBACK_APPLICATION_NAME = "application";
static final String PROPERTY_SOURCE_NAME_SEPARATOR = ".";
private Constants() {
}
private Constants() {
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2017 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -26,39 +26,38 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.cloud.kubernetes.secrets")
public class SecretsConfigProperties extends AbstractConfigProperties {
private static final String TARGET = "Secret";
private static final String TARGET = "Secret";
private boolean enableApi = false;
private Map<String, String> labels = new HashMap<>();
private List<String> paths = new LinkedList<>();
private boolean enableApi = false;
private Map<String, String> labels = new HashMap<>();
private List<String> paths = new LinkedList<>();
public boolean isEnableApi() {
return enableApi;
}
public boolean isEnableApi() {
return enableApi;
}
public void setEnableApi(boolean enableApi) {
this.enableApi = enableApi;
}
public void setEnableApi(boolean enableApi) {
this.enableApi = enableApi;
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
public Map<String, String> getLabels() {
return labels;
}
public Map<String, String> getLabels() {
return labels;
}
public void setPaths(List<String> paths) {
this.paths = paths;
}
public void setPaths(List<String> paths) {
this.paths = paths;
}
public List<String> getPaths() {
return paths;
}
public List<String> getPaths() {
return paths;
}
@Override
public String getConfigurationTarget() {
return TARGET;
}
@Override
public String getConfigurationTarget() {
return TARGET;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -22,99 +22,90 @@ import java.util.Map;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.*;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
public class SecretsPropertySource extends KubernetesPropertySource {
private static final Log LOG = LogFactory.getLog(SecretsPropertySource.class);
private static final Log LOG = LogFactory.getLog(SecretsPropertySource.class);
private static final String PREFIX = "secrets";
private static final String PREFIX = "secrets";
public SecretsPropertySource(KubernetesClient client, Environment env, SecretsConfigProperties config) {
super(
getSourceName(client, env, config),
getSourceData(client, env, config)
);
}
public SecretsPropertySource(KubernetesClient client, Environment env,
SecretsConfigProperties config) {
super(getSourceName(client, env, config), getSourceData(client, env, config));
}
private static String getSourceName(KubernetesClient client, Environment env, SecretsConfigProperties config) {
return new StringBuilder()
.append(PREFIX)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(getApplicationName(env, config.getName(), config.getConfigurationTarget()))
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(getApplicationNamespace(client, config.getNamespace(),
config.getConfigurationTarget()))
.toString();
}
private static String getSourceName(KubernetesClient client, Environment env,
SecretsConfigProperties config) {
return new StringBuilder().append(PREFIX)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(getApplicationName(env, config.getName(),
config.getConfigurationTarget()))
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
.append(getApplicationNamespace(client, config.getNamespace(),
config.getConfigurationTarget()))
.toString();
}
private static Map<String, Object> getSourceData(KubernetesClient client, Environment env, SecretsConfigProperties config) {
String name = getApplicationName(env, config.getName(), config.getConfigurationTarget());
String namespace = getApplicationNamespace(client, config.getNamespace(),
config.getConfigurationTarget());
Map<String, Object> result = new HashMap<>();
private static Map<String, Object> getSourceData(KubernetesClient client,
Environment env, SecretsConfigProperties config) {
String name = getApplicationName(env, config.getName(),
config.getConfigurationTarget());
String namespace = getApplicationNamespace(client, config.getNamespace(),
config.getConfigurationTarget());
Map<String, Object> result = new HashMap<>();
if (config.isEnableApi()) {
try {
// Read for secrets api (named)
if (config.isEnableApi()) {
try {
// Read for secrets api (named)
Secret secret;
if (StringUtils.isEmpty(namespace)) {
secret = client.secrets()
.withName(name)
.get();
} else {
secret = client.secrets()
.inNamespace(namespace)
.withName(name)
.get();
}
putAll(secret, result);
if (StringUtils.isEmpty(namespace)) {
secret = client.secrets().withName(name).get();
}
else {
secret = client.secrets().inNamespace(namespace).withName(name).get();
}
putAll(secret, result);
// Read for secrets api (label)
if (!config.getLabels().isEmpty()) {
if (StringUtils.isEmpty(namespace)) {
client.secrets()
.withLabels(config.getLabels())
.list()
.getItems()
.forEach(s -> putAll(s, result));
} else {
client.secrets()
.inNamespace(namespace)
.withLabels(config.getLabels())
.list()
.getItems()
.forEach(s -> putAll(s, result));
}
}
} catch (Exception e) {
LOG.warn("Can't read secret with name: [" + name +
"] or labels [" + config.getLabels() +
"] in namespace:[" + namespace +
"] (cause: " + e.getMessage() + "). Ignoring");
}
}
// Read for secrets api (label)
if (!config.getLabels().isEmpty()) {
if (StringUtils.isEmpty(namespace)) {
client.secrets().withLabels(config.getLabels()).list().getItems()
.forEach(s -> putAll(s, result));
}
else {
client.secrets().inNamespace(namespace)
.withLabels(config.getLabels()).list().getItems()
.forEach(s -> putAll(s, result));
}
}
}
catch (Exception e) {
LOG.warn("Can't read secret with name: [" + name + "] or labels ["
+ config.getLabels() + "] in namespace:[" + namespace
+ "] (cause: " + e.getMessage() + "). Ignoring");
}
}
// read for secrets mount
// read for secrets mount
putPathConfig(result, config.getPaths());
return result;
}
}
// *****************************
// Helpers
// *****************************
private static void putAll(Secret secret, Map<String, Object> result) {
if (secret != null && secret.getData() != null) {
secret.getData().forEach((k, v) -> result.put(
k,
new String(Base64.getDecoder().decode(v)).trim())
);
}
}
// Helpers
// *****************************
private static void putAll(Secret secret, Map<String, Object> result) {
if (secret != null && secret.getData() != null) {
secret.getData().forEach((k, v) -> result.put(k,
new String(Base64.getDecoder().decode(v)).trim()));
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -18,27 +18,27 @@
package org.springframework.cloud.kubernetes.config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@Order(1)
public class SecretsPropertySourceLocator implements PropertySourceLocator {
private final KubernetesClient client;
private final SecretsConfigProperties properties;
private final KubernetesClient client;
private final SecretsConfigProperties properties;
public SecretsPropertySourceLocator(KubernetesClient client, SecretsConfigProperties properties) {
this.client = client;
this.properties = properties;
}
public SecretsPropertySourceLocator(KubernetesClient client,
SecretsConfigProperties properties) {
this.client = client;
this.properties = properties;
}
@Override
public MapPropertySource locate(Environment environment) {
return environment instanceof ConfigurableEnvironment
? new SecretsPropertySource(client, environment, properties)
: null;
}
@Override
public MapPropertySource locate(Environment environment) {
return environment instanceof ConfigurableEnvironment
? new SecretsPropertySource(client, environment, properties) : null;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,21 +17,20 @@
package org.springframework.cloud.kubernetes.config.reload;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.restart.RestartEndpoint;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -44,64 +43,77 @@ import org.springframework.scheduling.annotation.EnableScheduling;
*/
@Configuration
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
@AutoConfigureAfter({InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class, RefreshAutoConfiguration.class})
@AutoConfigureAfter({ InfoEndpointAutoConfiguration.class,
RefreshEndpointAutoConfiguration.class, RefreshAutoConfiguration.class })
@EnableConfigurationProperties(ConfigReloadProperties.class)
public class ConfigReloadAutoConfiguration {
/**
* Configuration reload must be enabled explicitly.
*/
@ConditionalOnProperty(value = "spring.cloud.kubernetes.reload.enabled")
@ConditionalOnClass({RestartEndpoint.class, ContextRefresher.class})
@EnableScheduling
@EnableAsync
protected static class ConfigReloadAutoConfigurationBeans {
/**
* Configuration reload must be enabled explicitly.
*/
@ConditionalOnProperty(value = "spring.cloud.kubernetes.reload.enabled")
@ConditionalOnClass({ RestartEndpoint.class, ContextRefresher.class })
@EnableScheduling
@EnableAsync
protected static class ConfigReloadAutoConfigurationBeans {
@Autowired
private AbstractEnvironment environment;
@Autowired
private AbstractEnvironment environment;
@Autowired
private KubernetesClient kubernetesClient;
@Autowired
private KubernetesClient kubernetesClient;
@Autowired
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
@Autowired
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
@Autowired
private SecretsPropertySourceLocator secretsPropertySourceLocator;
@Autowired
private SecretsPropertySourceLocator secretsPropertySourceLocator;
/**
* Provides a bean that listen to configuration changes and fire a reload.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationChangeDetector propertyChangeWatcher(ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy) {
switch (properties.getMode()) {
case POLLING:
return new PollingConfigurationChangeDetector(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator, secretsPropertySourceLocator);
case EVENT:
return new EventBasedConfigurationChangeDetector(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator, secretsPropertySourceLocator);
}
throw new IllegalStateException("Unsupported configuration reload mode: " + properties.getMode());
}
/**
* Provides a bean that listen to configuration changes and fire a reload.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationChangeDetector propertyChangeWatcher(
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy) {
switch (properties.getMode()) {
case POLLING:
return new PollingConfigurationChangeDetector(environment, properties,
kubernetesClient, strategy, configMapPropertySourceLocator,
secretsPropertySourceLocator);
case EVENT:
return new EventBasedConfigurationChangeDetector(environment, properties,
kubernetesClient, strategy, configMapPropertySourceLocator,
secretsPropertySourceLocator);
}
throw new IllegalStateException(
"Unsupported configuration reload mode: " + properties.getMode());
}
/**
* Provides the action to execute when the configuration changes.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationUpdateStrategy configurationUpdateStrategy(ConfigReloadProperties properties, ConfigurableApplicationContext ctx, RestartEndpoint restarter, ContextRefresher refresher) {
switch (properties.getStrategy()) {
case RESTART_CONTEXT:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), restarter::restart);
case REFRESH:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), refresher::refresh);
case SHUTDOWN:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), ctx::close);
}
throw new IllegalStateException("Unsupported configuration update strategy: " + properties.getStrategy());
}
/**
* Provides the action to execute when the configuration changes.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationUpdateStrategy configurationUpdateStrategy(
ConfigReloadProperties properties, ConfigurableApplicationContext ctx,
RestartEndpoint restarter, ContextRefresher refresher) {
switch (properties.getStrategy()) {
case RESTART_CONTEXT:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(),
restarter::restart);
case REFRESH:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(),
refresher::refresh);
case SHUTDOWN:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(),
ctx::close);
}
throw new IllegalStateException("Unsupported configuration update strategy: "
+ properties.getStrategy());
}
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -24,117 +24,120 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.cloud.kubernetes.reload")
public class ConfigReloadProperties {
/**
* Enables the Kubernetes configuration reload on change.
*/
private boolean enabled = false;
/**
* Enables the Kubernetes configuration reload on change.
*/
private boolean enabled = false;
/**
* Enables monitoring on config maps to detect changes.
*/
private boolean monitoringConfigMaps = true;
/**
* Enables monitoring on config maps to detect changes.
*/
private boolean monitoringConfigMaps = true;
/**
* Enables monitoring on secrets to detect changes.
*/
private boolean monitoringSecrets = false;
/**
* Enables monitoring on secrets to detect changes.
*/
private boolean monitoringSecrets = false;
/**
* Sets the reload strategy for Kubernetes configuration reload on change.
*/
private ReloadStrategy strategy = ReloadStrategy.REFRESH;
/**
* Sets the reload strategy for Kubernetes configuration reload on change.
*/
private ReloadStrategy strategy = ReloadStrategy.REFRESH;
/**
* Sets the detection mode for Kubernetes configuration reload.
*/
private ReloadDetectionMode mode = ReloadDetectionMode.EVENT;
/**
* Sets the detection mode for Kubernetes configuration reload.
*/
private ReloadDetectionMode mode = ReloadDetectionMode.EVENT;
/**
* Sets the polling period in milliseconds to use when the detection mode is POLLING.
*/
private Long period = 15000L;
/**
* Sets the polling period in milliseconds to use when the detection mode is POLLING.
*/
private Long period = 15000L;
public ConfigReloadProperties() {
}
public ConfigReloadProperties() {
}
public boolean isEnabled() {
return enabled;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isMonitoringConfigMaps() {
return monitoringConfigMaps;
}
public boolean isMonitoringConfigMaps() {
return monitoringConfigMaps;
}
public void setMonitoringConfigMaps(boolean monitoringConfigMaps) {
this.monitoringConfigMaps = monitoringConfigMaps;
}
public void setMonitoringConfigMaps(boolean monitoringConfigMaps) {
this.monitoringConfigMaps = monitoringConfigMaps;
}
public boolean isMonitoringSecrets() {
return monitoringSecrets;
}
public boolean isMonitoringSecrets() {
return monitoringSecrets;
}
public void setMonitoringSecrets(boolean monitoringSecrets) {
this.monitoringSecrets = monitoringSecrets;
}
public void setMonitoringSecrets(boolean monitoringSecrets) {
this.monitoringSecrets = monitoringSecrets;
}
public ReloadStrategy getStrategy() {
return strategy;
}
public ReloadStrategy getStrategy() {
return strategy;
}
public void setStrategy(ReloadStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(ReloadStrategy strategy) {
this.strategy = strategy;
}
public ReloadDetectionMode getMode() {
return mode;
}
public ReloadDetectionMode getMode() {
return mode;
}
public Long getPeriod() {
return period;
}
public Long getPeriod() {
return period;
}
public void setPeriod(Long period) {
this.period = period;
}
public void setPeriod(Long period) {
this.period = period;
}
public void setMode(ReloadDetectionMode mode) {
this.mode = mode;
}
public void setMode(ReloadDetectionMode mode) {
this.mode = mode;
}
public enum ReloadStrategy {
/**
* Fire a refresh of beans annotated with @ConfigurationProperties or @RefreshScope.
*/
REFRESH,
public enum ReloadStrategy {
/**
* Fire a refresh of beans annotated with @ConfigurationProperties
* or @RefreshScope.
*/
REFRESH,
/**
* Restarts the Spring ApplicationContext to apply the new configuration.
*/
RESTART_CONTEXT,
/**
* Restarts the Spring ApplicationContext to apply the new configuration.
*/
RESTART_CONTEXT,
/**
* Shuts down the Spring ApplicationContext to activate a restart of the container.
* Make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext and that
* a replication controller or replica set is configured to restart the pod.
*/
SHUTDOWN
}
/**
* Shuts down the Spring ApplicationContext to activate a restart of the
* container. Make sure that the lifecycle of all non-daemon threads is bound to
* the ApplicationContext and that a replication controller or replica set is
* configured to restart the pod.
*/
SHUTDOWN
}
public enum ReloadDetectionMode {
/**
* Enables a polling task that retrieves periodically all external properties and
* fire a reload when they change.
*/
POLLING,
public enum ReloadDetectionMode {
/**
* Enables a polling task that retrieves periodically all external properties and
* fire a reload when they change.
*/
POLLING,
/**
* Listens to Kubernetes events and checks if a reload is needed when configmaps or secrets change.
*/
EVENT
}
/**
* Listens to Kubernetes events and checks if a reload is needed when configmaps
* or secrets change.
*/
EVENT
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -16,15 +16,18 @@
*/
package org.springframework.cloud.kubernetes.config.reload;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PreDestroy;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -33,61 +36,67 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
/**
* This is the superclass of all beans that can listen to changes in the configuration and fire a reload.
* This is the superclass of all beans that can listen to changes in the configuration and
* fire a reload.
*/
public abstract class ConfigurationChangeDetector {
protected Log log = LogFactory.getLog(getClass());
protected Log log = LogFactory.getLog(getClass());
protected ConfigurableEnvironment environment;
protected ConfigurableEnvironment environment;
protected ConfigReloadProperties properties;
protected ConfigReloadProperties properties;
protected KubernetesClient kubernetesClient;
protected KubernetesClient kubernetesClient;
protected ConfigurationUpdateStrategy strategy;
protected ConfigurationUpdateStrategy strategy;
public ConfigurationChangeDetector(ConfigurableEnvironment environment, ConfigReloadProperties properties, KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy) {
this.environment = environment;
this.properties = properties;
this.kubernetesClient = kubernetesClient;
this.strategy = strategy;
}
public ConfigurationChangeDetector(ConfigurableEnvironment environment,
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy) {
this.environment = environment;
this.properties = properties;
this.kubernetesClient = kubernetesClient;
this.strategy = strategy;
}
@PreDestroy
public void shutdown() {
// Ensure the kubernetes client is cleaned up from spare threads when shutting down
kubernetesClient.close();
}
@PreDestroy
public void shutdown() {
// Ensure the kubernetes client is cleaned up from spare threads when shutting
// down
kubernetesClient.close();
}
public void reloadProperties() {
log.info("Reloading using strategy: " + strategy.getName());
strategy.reload();
}
public void reloadProperties() {
log.info("Reloading using strategy: " + strategy.getName());
strategy.reload();
}
/**
* Determines if two property sources are different.
*/
protected boolean changed(MapPropertySource mp1, MapPropertySource mp2) {
if (mp1 == mp2) return false;
if (mp1 == null && mp2 != null || mp1 != null && mp2 == null) return true;
/**
* Determines if two property sources are different.
*/
protected boolean changed(MapPropertySource mp1, MapPropertySource mp2) {
if (mp1 == mp2)
return false;
if (mp1 == null && mp2 != null || mp1 != null && mp2 == null)
return true;
Map<String, Object> s1 = mp1.getSource();
Map<String, Object> s2 = mp2.getSource();
Map<String, Object> s1 = mp1.getSource();
Map<String, Object> s2 = mp2.getSource();
return s1 == null ? s2 != null : !s1.equals(s2);
}
return s1 == null ? s2 != null : !s1.equals(s2);
}
protected boolean changed(List<? extends MapPropertySource> l1,
List<? extends MapPropertySource> l2) {
protected boolean changed(List<? extends MapPropertySource> l1,
List<? extends MapPropertySource> l2) {
if(l1.size() != l2.size()) {
if (l1.size() != l2.size()) {
log.debug("The current number of Confimap PropertySources does not match "
+ "the ones loaded from the Kubernetes - No reload will take place");
+ "the ones loaded from the Kubernetes - No reload will take place");
return false;
}
for(int i=0; i<l1.size(); i++) {
for (int i = 0; i < l1.size(); i++) {
if (changed(l1.get(i), l2.get(i))) {
return true;
}
@@ -95,70 +104,72 @@ public abstract class ConfigurationChangeDetector {
return false;
}
/**
* Finds one registered property source of the given type, logging a warning if
* multiple property sources of that type are available.
*/
protected <S extends PropertySource<?>> S findPropertySource(Class<S> sourceClass) {
List<S> sources = findPropertySources(sourceClass);
if (sources.size() == 0) {
return null;
}
if (sources.size() > 1) {
log.warn("Found more than one property source of type " + sourceClass);
}
return sources.get(0);
}
/**
* Finds all registered property sources of the given type.
*/
protected <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass) {
List<S> managedSources = new LinkedList<>();
LinkedList<PropertySource<?>> sources = toLinkedList(environment.getPropertySources());
while (!sources.isEmpty()) {
PropertySource<?> source = sources.pop();
if (source instanceof CompositePropertySource) {
CompositePropertySource comp = (CompositePropertySource) source;
sources.addAll(comp.getPropertySources());
} else if (sourceClass.isInstance(source)) {
managedSources.add(sourceClass.cast(source));
}
}
return managedSources;
}
private <E> LinkedList<E> toLinkedList(Iterable<E> it) {
LinkedList<E> list = new LinkedList<E>();
for (E e : it) {
list.add(e);
}
return list;
}
/**
* Finds one registered property source of the given type, logging a warning if
* multiple property sources of that type are available.
*/
protected <S extends PropertySource<?>> S findPropertySource(Class<S> sourceClass) {
List<S> sources = findPropertySources(sourceClass);
if (sources.size() == 0) {
return null;
}
if (sources.size() > 1) {
log.warn("Found more than one property source of type " + sourceClass);
}
return sources.get(0);
}
/**
* Returns a list of MapPropertySource that correspond to the current state of the system
* This only handles the PropertySource objects that are returned
* Finds all registered property sources of the given type.
*/
protected <S extends PropertySource<?>> List<S> findPropertySources(
Class<S> sourceClass) {
List<S> managedSources = new LinkedList<>();
LinkedList<PropertySource<?>> sources = toLinkedList(
environment.getPropertySources());
while (!sources.isEmpty()) {
PropertySource<?> source = sources.pop();
if (source instanceof CompositePropertySource) {
CompositePropertySource comp = (CompositePropertySource) source;
sources.addAll(comp.getPropertySources());
}
else if (sourceClass.isInstance(source)) {
managedSources.add(sourceClass.cast(source));
}
}
return managedSources;
}
private <E> LinkedList<E> toLinkedList(Iterable<E> it) {
LinkedList<E> list = new LinkedList<E>();
for (E e : it) {
list.add(e);
}
return list;
}
/**
* Returns a list of MapPropertySource that correspond to the current state of the
* system This only handles the PropertySource objects that are returned
*/
protected List<MapPropertySource> locateMapPropertySources(
PropertySourceLocator propertySourceLocator, Environment environment) {
PropertySourceLocator propertySourceLocator, Environment environment) {
List<MapPropertySource> result = new ArrayList<>();
PropertySource propertySource= propertySourceLocator.locate(environment);
if(propertySource instanceof MapPropertySource) {
PropertySource propertySource = propertySourceLocator.locate(environment);
if (propertySource instanceof MapPropertySource) {
result.add((MapPropertySource) propertySource);
} else if(propertySource instanceof CompositePropertySource) {
result.addAll(((CompositePropertySource) propertySource)
.getPropertySources()
.stream()
.filter(p -> p instanceof MapPropertySource)
.map(p -> (MapPropertySource) p)
.collect(Collectors.toList()));
} else {
}
else if (propertySource instanceof CompositePropertySource) {
result.addAll(((CompositePropertySource) propertySource).getPropertySources()
.stream().filter(p -> p instanceof MapPropertySource)
.map(p -> (MapPropertySource) p).collect(Collectors.toList()));
}
else {
log.debug("Found property source that cannot be handled: "
+ propertySource.getClass());
+ propertySource.getClass());
}
return result;

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -19,34 +19,35 @@ package org.springframework.cloud.kubernetes.config.reload;
import java.util.Objects;
/**
* This is the superclass of all named strategies that can be fired when the configuration changes.
* This is the superclass of all named strategies that can be fired when the configuration
* changes.
*/
public class ConfigurationUpdateStrategy {
private String name;
private String name;
private Runnable reloadProcedure;
private Runnable reloadProcedure;
public ConfigurationUpdateStrategy(String name, Runnable reloadProcedure) {
Objects.requireNonNull(name, "name cannot be null");
Objects.requireNonNull(reloadProcedure, "reloadProcedure cannot be null");
this.name = name;
this.reloadProcedure = reloadProcedure;
}
public ConfigurationUpdateStrategy(String name, Runnable reloadProcedure) {
Objects.requireNonNull(name, "name cannot be null");
Objects.requireNonNull(reloadProcedure, "reloadProcedure cannot be null");
this.name = name;
this.reloadProcedure = reloadProcedure;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void reload() {
this.reloadProcedure.run();
}
public void reload() {
this.reloadProcedure.run();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ConfigurationUpdateStrategy{");
sb.append("name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ConfigurationUpdateStrategy{");
sb.append("name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -16,16 +16,19 @@
*/
package org.springframework.cloud.kubernetes.config.reload;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySource;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.config.SecretsPropertySource;
@@ -34,117 +37,124 @@ import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.MapPropertySource;
/**
* A change detector that subscribes to changes in secrets and configmaps and fire a reload when something changes.
* A change detector that subscribes to changes in secrets and configmaps and fire a
* reload when something changes.
*/
public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDetector {
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
private Map<String, Watch> watches;
private Map<String, Watch> watches;
public EventBasedConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties,
KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
public EventBasedConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
this.watches = new HashMap<>();
}
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
this.watches = new HashMap<>();
}
@PostConstruct
public void watch() {
boolean activated = false;
@PostConstruct
public void watch() {
boolean activated = false;
if (properties.isMonitoringConfigMaps()) {
try {
String name = "config-maps-watch";
watches.put(name, kubernetesClient.configMaps()
.watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action, ConfigMap configMap) {
onEvent(configMap);
}
if (properties.isMonitoringConfigMaps()) {
try {
String name = "config-maps-watch";
watches.put(name,
kubernetesClient.configMaps().watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action,
ConfigMap configMap) {
onEvent(configMap);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
log.info("Added new Kubernetes watch: "+name);
} catch (Exception e) {
log.error("Error while establishing a connection to watch config maps: configuration may remain stale", e);
}
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
log.info("Added new Kubernetes watch: " + name);
}
catch (Exception e) {
log.error(
"Error while establishing a connection to watch config maps: configuration may remain stale",
e);
}
}
if (properties.isMonitoringSecrets()) {
try {
activated = false;
String name = "secrets-watch";
watches.put(name, kubernetesClient.secrets()
.watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
if (properties.isMonitoringSecrets()) {
try {
activated = false;
String name = "secrets-watch";
watches.put(name, kubernetesClient.secrets().watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
log.info("Added new Kubernetes watch: " + name);
} catch (Exception e) {
log.error("Error while establishing a connection to watch secrets: configuration may remain stale", e);
}
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
log.info("Added new Kubernetes watch: " + name);
}
catch (Exception e) {
log.error(
"Error while establishing a connection to watch secrets: configuration may remain stale",
e);
}
}
if (activated) {
log.info("Kubernetes event-based configuration change detector activated");
}
}
if (activated) {
log.info("Kubernetes event-based configuration change detector activated");
}
}
@PreDestroy
public void unwatch() {
if (this.watches != null) {
for (Map.Entry<String, Watch> entry : this.watches.entrySet()) {
try {
log.debug("Closing the watch "+ entry.getKey());
entry.getValue().close();
@PreDestroy
public void unwatch() {
if (this.watches != null) {
for (Map.Entry<String, Watch> entry : this.watches.entrySet()) {
try {
log.debug("Closing the watch " + entry.getKey());
entry.getValue().close();
} catch (Exception e) {
log.error("Error while closing the watch connection", e);
}
}
}
}
}
catch (Exception e) {
log.error("Error while closing the watch connection", e);
}
}
}
}
private void onEvent(ConfigMap configMap) {
private void onEvent(ConfigMap configMap) {
boolean changed = changed(
locateMapPropertySources(configMapPropertySourceLocator, environment),
findPropertySources(ConfigMapPropertySource.class)
);
if(changed) {
locateMapPropertySources(configMapPropertySourceLocator, environment),
findPropertySources(ConfigMapPropertySource.class));
if (changed) {
log.info("Detected change in config maps");
reloadProperties();
}
}
private void onEvent(Secret secret) {
MapPropertySource currentSecretSource = findPropertySource(SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator.locate(environment);
if (changed(currentSecretSource, newSecretSource)) {
log.info("Detected change in secrets");
reloadProperties();
}
}
}
}
private void onEvent(Secret secret) {
MapPropertySource currentSecretSource = findPropertySource(
SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator
.locate(environment);
if (changed(currentSecretSource, newSecretSource)) {
log.info("Detected change in secrets");
reloadProperties();
}
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -16,11 +16,14 @@
*/
package org.springframework.cloud.kubernetes.config.reload;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.util.List;
import javax.annotation.PostConstruct;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySource;
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.config.SecretsPropertySource;
@@ -30,61 +33,63 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.scheduling.annotation.Scheduled;
/**
* A change detector that periodically retrieves secrets and configmaps and fire a reload when something changes.
* A change detector that periodically retrieves secrets and configmaps and fire a reload
* when something changes.
*/
public class PollingConfigurationChangeDetector extends ConfigurationChangeDetector {
protected Log log = LogFactory.getLog(getClass());
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
public PollingConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties,
KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
public PollingConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
}
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
}
@PostConstruct
public void init() {
log.info("Kubernetes polling configuration change detector activated");
}
@PostConstruct
public void init() {
log.info("Kubernetes polling configuration change detector activated");
}
@Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}", fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}")
public void executeCycle() {
@Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}", fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}")
public void executeCycle() {
boolean changedConfigMap = false;
if (properties.isMonitoringConfigMaps()) {
List<? extends MapPropertySource> currentConfigMapSources
= findPropertySources(ConfigMapPropertySource.class);
boolean changedConfigMap = false;
if (properties.isMonitoringConfigMaps()) {
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(
ConfigMapPropertySource.class);
if (!currentConfigMapSources.isEmpty()) {
if (!currentConfigMapSources.isEmpty()) {
changedConfigMap = changed(
locateMapPropertySources(configMapPropertySourceLocator, environment),
currentConfigMapSources
);
}
}
locateMapPropertySources(configMapPropertySourceLocator,
environment),
currentConfigMapSources);
}
}
boolean changedSecrets = false;
if (properties.isMonitoringSecrets()) {
MapPropertySource currentSecretSource = findPropertySource(SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator.locate(environment);
changedSecrets = changed(currentSecretSource, newSecretSource);
}
}
boolean changedSecrets = false;
if (properties.isMonitoringSecrets()) {
MapPropertySource currentSecretSource = findPropertySource(
SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator
.locate(environment);
changedSecrets = changed(currentSecretSource, newSecretSource);
}
}
if (changedConfigMap || changedSecrets) {
reloadProperties();
}
}
if (changedConfigMap || changedSecrets) {
reloadProperties();
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.config;
import io.fabric8.kubernetes.client.utils.IOHelpers;

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -30,6 +30,7 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
@@ -44,11 +45,9 @@ import static org.junit.Assert.assertEquals;
* @author Charles Moulliard
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = App.class,
properties = { "spring.application.name=configmap-example",
"spring.cloud.kubernetes.reload.enabled=false"}
)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
"spring.application.name=configmap-example",
"spring.cloud.kubernetes.reload.enabled=false" })
public class ConfigMapsSpringBootTest {
@ClassRule
@@ -68,23 +67,23 @@ public class ConfigMapsSpringBootTest {
public static void setUpBeforeClass() {
mockClient = server.getClient();
//Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY,
"false");
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
HashMap<String,String> data = new HashMap<>();
data.put("bean.greeting","Hello ConfigMap, %s!");
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME).andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(APPLICATION_NAME).endMetadata()
.addToData(data)
.build())
.always();
HashMap<String, String> data = new HashMap<>();
data.put("bean.greeting", "Hello ConfigMap, %s!");
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
.withName(APPLICATION_NAME).endMetadata().addToData(data).build())
.always();
}
@Before
public void setUp() {
RestAssured.baseURI = String.format("http://localhost:%d/api/greeting", port);
@@ -92,23 +91,22 @@ public class ConfigMapsSpringBootTest {
@Test
public void testConfig() {
assertEquals(config.getMasterUrl(),mockClient.getConfiguration().getMasterUrl());
assertEquals(config.getNamespace(),mockClient.getNamespace());
assertEquals(config.getMasterUrl(), mockClient.getConfiguration().getMasterUrl());
assertEquals(config.getNamespace(), mockClient.getNamespace());
}
@Test
public void testGreetingEndpoint() {
when().get()
.then()
.statusCode(200)
.body("content", is("Hello ConfigMap, World!"));
when().get().then().statusCode(200).body("content",
is("Hello ConfigMap, World!"));
}
@Test
public void testConfigMap() {
ConfigMap configmap = mockClient.configMaps().inNamespace("test").withName(APPLICATION_NAME).get();
HashMap<String,String> keys = (HashMap<String, String>) configmap.getData();
assertEquals(keys.get("bean.greeting"),"Hello ConfigMap, %s!");
ConfigMap configmap = mockClient.configMaps().inNamespace("test")
.withName(APPLICATION_NAME).get();
HashMap<String, String> keys = (HashMap<String, String>) configmap.getData();
assertEquals(keys.get("bean.greeting"), "Hello ConfigMap, %s!");
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,17 +17,6 @@
package org.springframework.cloud.kubernetes.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ConfigMapList;
import io.fabric8.kubernetes.api.model.ConfigMapListBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.fabric8.kubernetes.client.utils.IOHelpers;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -35,14 +24,22 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ConfigMapList;
import io.fabric8.kubernetes.api.model.ConfigMapListBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.util.FileSystemUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.*;
import static org.junit.Assert.assertNull;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
/**
* @author Charles Moulliard
@@ -54,7 +51,8 @@ public class ConfigMapsTest {
@Test
public void testConfigMapList() {
server.expect().withPath("/api/v1/namespaces/ns1/configmaps").andReturn(200, new ConfigMapListBuilder().build()).once();
server.expect().withPath("/api/v1/namespaces/ns1/configmaps")
.andReturn(200, new ConfigMapListBuilder().build()).once();
KubernetesClient client = server.getClient();
@@ -65,19 +63,21 @@ public class ConfigMapsTest {
@Test
public void testConfigMapGet() {
server.expect().withPath("/api/v1/namespaces/ns2/configmaps").andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName("reload-example").endMetadata()
.addToData("KEY","123")
.build())
.once();
server.expect().withPath("/api/v1/namespaces/ns2/configmaps")
.andReturn(200,
new ConfigMapBuilder().withNewMetadata()
.withName("reload-example").endMetadata()
.addToData("KEY", "123").build())
.once();
KubernetesClient client = server.getClient();
ConfigMapList configMapList = client.configMaps().inNamespace("ns2").list();
assertNotNull(configMapList);
assertEquals(1, configMapList.getAdditionalProperties().size());
@SuppressWarnings("unchecked")
Map<String,String> data = (Map<String, String>) configMapList.getAdditionalProperties().get("data");
assertEquals("123",data.get("KEY"));
Map<String, String> data = (Map<String, String>) configMapList
.getAdditionalProperties().get("data");
assertEquals("123", data.get("KEY"));
}
@Test
@@ -85,20 +85,18 @@ public class ConfigMapsTest {
String configMapName = "app-properties-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("application.properties",readResourceFile("application.properties"))
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
.withName(configMapName).endMetadata()
.addToData("application.properties",
readResourceFile("application.properties"))
.build())
.once();
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties());
assertEquals("a", cmps.getProperty("dummy.property.string1"));
assertEquals("1", cmps.getProperty("dummy.property.int1"));
@@ -110,20 +108,19 @@ public class ConfigMapsTest {
String configMapName = "app-yaml-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("application.yaml",readResourceFile("application.yaml"))
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200,
new ConfigMapBuilder().withNewMetadata().withName(configMapName)
.endMetadata()
.addToData("application.yaml",
readResourceFile("application.yaml"))
.build())
.once();
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties());
assertEquals("a", cmps.getProperty("dummy.property.string2"));
assertEquals("1", cmps.getProperty("dummy.property.int2"));
@@ -135,20 +132,16 @@ public class ConfigMapsTest {
String configMapName = "single-non-standard-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("adhoc.yml",readResourceFile("adhoc.yml"))
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
.withName(configMapName).endMetadata()
.addToData("adhoc.yml", readResourceFile("adhoc.yml")).build())
.once();
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties());
assertEquals("a", cmps.getProperty("dummy.property.string3"));
assertEquals("1", cmps.getProperty("dummy.property.int3"));
@@ -160,22 +153,18 @@ public class ConfigMapsTest {
String configMapName = "single-unparseable-properties-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("application.properties","somevalue")
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200,
new ConfigMapBuilder().withNewMetadata().withName(configMapName)
.endMetadata()
.addToData("application.properties", "somevalue").build())
.once();
new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
new ConfigMapPropertySource(server.getClient().inNamespace(namespace),
configMapName, new ConfigMapConfigProperties());
//no exception is thrown for unparseable content
// no exception is thrown for unparseable content
}
@Test
@@ -183,22 +172,18 @@ public class ConfigMapsTest {
String configMapName = "single-unparseable-yaml-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("application.yaml","somevalue")
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200,
new ConfigMapBuilder().withNewMetadata().withName(configMapName)
.endMetadata().addToData("application.yaml", "somevalue")
.build())
.once();
new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
new ConfigMapPropertySource(server.getClient().inNamespace(namespace),
configMapName, new ConfigMapConfigProperties());
//no exception is thrown for unparseable content
// no exception is thrown for unparseable content
}
@Test
@@ -206,28 +191,28 @@ public class ConfigMapsTest {
String configMapName = "app-multiple-properties-test";
String namespace = "app-props";
server.expect()
.withPath(
String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName)
)
.andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(configMapName).endMetadata()
.addToData("application.properties",readResourceFile("application.properties"))
.addToData("adhoc.properties",readResourceFile("adhoc.properties"))
.build()
)
.once();
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
configMapName))
.andReturn(200,
new ConfigMapBuilder().withNewMetadata().withName(configMapName)
.endMetadata()
.addToData("application.properties",
readResourceFile("application.properties"))
.addToData("adhoc.properties",
readResourceFile("adhoc.properties"))
.build())
.once();
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties()
);
server.getClient().inNamespace(namespace), configMapName,
new ConfigMapConfigProperties());
//application.properties should be read correctly
// application.properties should be read correctly
assertEquals("a", cmps.getProperty("dummy.property.string1"));
assertEquals("1", cmps.getProperty("dummy.property.int1"));
assertEquals("true", cmps.getProperty("dummy.property.bool1"));
//the adhoc.properties file should not be parsed
// the adhoc.properties file should not be parsed
assertNull(cmps.getProperty("dummy.property.bool2"));
assertNull(cmps.getProperty("dummy.property.bool2"));
assertNull(cmps.getProperty("dummy.property.bool2"));
@@ -250,12 +235,16 @@ public class ConfigMapsTest {
final Path filesPath = tmp.resolve("cm/files");
createConfigMapFile(filesPath, "application.yaml", readResourceFile("application.yaml"));
createConfigMapFile(filesPath, "application.properties", readResourceFile("application.properties"));
createConfigMapFile(filesPath, "application.yaml",
readResourceFile("application.yaml"));
createConfigMapFile(filesPath, "application.properties",
readResourceFile("application.properties"));
// parse ConfigMaps
cmConfProperties.setPaths(Arrays.asList(dbPath.toString(), apiPath.toString(), filesPath.toString()));
ConfigMapPropertySource cmps = new ConfigMapPropertySource(client, "testapp", cmConfProperties);
cmConfProperties.setPaths(Arrays.asList(dbPath.toString(), apiPath.toString(),
filesPath.toString()));
ConfigMapPropertySource cmps = new ConfigMapPropertySource(client, "testapp",
cmConfProperties);
// assert as expected
assertEquals("42", cmps.getProperty("foo.bar"));
@@ -271,11 +260,12 @@ public class ConfigMapsTest {
assertEquals("1", cmps.getProperty("dummy.property.int2"));
assertEquals("true", cmps.getProperty("dummy.property.bool2"));
FileSystemUtils.deleteRecursively(tmp.toFile());
FileSystemUtils.deleteRecursively(tmp.toFile());
}
@Test
public void testConfigMapGetSingleApplicationPropertiesFromVolume() throws IOException {
public void testConfigMapGetSingleApplicationPropertiesFromVolume()
throws IOException {
KubernetesClient client = server.getClient();
ConfigMapConfigProperties cmConfProperties = new ConfigMapConfigProperties();
cmConfProperties.setEnableApi(false);
@@ -286,11 +276,13 @@ public class ConfigMapsTest {
final Path filesPath = tmp.resolve("cm/files");
createConfigMapFile(filesPath, "adhoc.properties", readResourceFile("adhoc.properties"));
createConfigMapFile(filesPath, "adhoc.properties",
readResourceFile("adhoc.properties"));
// parse ConfigMaps
cmConfProperties.setPaths(Collections.singletonList(filesPath.toString()));
ConfigMapPropertySource cmps = new ConfigMapPropertySource(client, "testapp", cmConfProperties);
ConfigMapPropertySource cmps = new ConfigMapPropertySource(client, "testapp",
cmConfProperties);
// assert as expected
assertEquals("a", cmps.getProperty("dummy.property.string4"));
@@ -300,7 +292,8 @@ public class ConfigMapsTest {
FileSystemUtils.deleteRecursively(tmp.toFile());
}
private void createConfigMapFile(Path basePath, String key, String value) throws IOException {
private void createConfigMapFile(Path basePath, String key, String value)
throws IOException {
Files.createDirectories(basePath);
final Path apiUrlFile = Files.createFile(basePath.resolve(key));
Files.write(apiUrlFile, value.getBytes(StandardCharsets.UTF_8));

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,35 +17,35 @@
package org.springframework.cloud.kubernetes.config;
import static io.restassured.RestAssured.when;
import static org.hamcrest.core.Is.is;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
import java.util.HashMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.restassured.RestAssured;
import java.util.HashMap;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.config.example.App;
import org.springframework.test.context.junit4.SpringRunner;
import static io.restassured.RestAssured.when;
import static org.hamcrest.core.Is.is;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
/**
* @author Charles Moulliard
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = App.class,
properties = { "spring.application.name=configmap-with-profile-no-active-profiles-example",
"spring.cloud.kubernetes.reload.enabled=false"}
)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
"spring.application.name=configmap-with-profile-no-active-profiles-example",
"spring.cloud.kubernetes.reload.enabled=false" })
public class ConfigMapsWithProfilesNoActiveProfileSpringBootTest {
@ClassRule
@@ -65,38 +65,35 @@ public class ConfigMapsWithProfilesNoActiveProfileSpringBootTest {
public static void setUpBeforeClass() {
mockClient = server.getClient();
//Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY,
"false");
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
HashMap<String,String> data = new HashMap<>();
HashMap<String, String> data = new HashMap<>();
data.put("application.yml", readResourceFile("application-with-profiles.yaml"));
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME).andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(APPLICATION_NAME).endMetadata()
.addToData(data)
.build())
.always();
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
.withName(APPLICATION_NAME).endMetadata().addToData(data).build())
.always();
}
@Test
public void testGreetingEndpoint() {
RestAssured.baseURI = String.format("http://localhost:%d/api/greeting", port);
when().get()
.then()
.statusCode(200)
.body("content", is("Hello ConfigMap default, World!"));
when().get().then().statusCode(200).body("content",
is("Hello ConfigMap default, World!"));
}
@Test
public void testFarewellEndpoint() {
RestAssured.baseURI = String.format("http://localhost:%d/api/farewell", port);
when().get()
.then()
.statusCode(200)
.body("content", is("Goodbye ConfigMap default, World!"));
when().get().then().statusCode(200).body("content",
is("Goodbye ConfigMap default, World!"));
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,20 +17,18 @@
package org.springframework.cloud.kubernetes.config;
import static io.restassured.RestAssured.when;
import static org.hamcrest.core.Is.is;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.*;
import java.util.HashMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.restassured.RestAssured;
import java.util.HashMap;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
@@ -38,15 +36,17 @@ import org.springframework.cloud.kubernetes.config.example.App;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static io.restassured.RestAssured.when;
import static org.hamcrest.core.Is.is;
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
/**
* @author Charles Moulliard
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = App.class,
properties = { "spring.application.name=configmap-with-profile-example",
"spring.cloud.kubernetes.reload.enabled=false"}
)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
"spring.application.name=configmap-with-profile-example",
"spring.cloud.kubernetes.reload.enabled=false" })
@ActiveProfiles("development")
public class ConfigMapsWithProfilesSpringBootTest {
@@ -67,37 +67,34 @@ public class ConfigMapsWithProfilesSpringBootTest {
public static void setUpBeforeClass() {
mockClient = server.getClient();
//Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY,
"false");
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
HashMap<String,String> data = new HashMap<>();
HashMap<String, String> data = new HashMap<>();
data.put("application.yml", readResourceFile("application-with-profiles.yaml"));
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME).andReturn(200, new ConfigMapBuilder()
.withNewMetadata().withName(APPLICATION_NAME).endMetadata()
.addToData(data)
.build())
.always();
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
.withName(APPLICATION_NAME).endMetadata().addToData(data).build())
.always();
}
@Test
public void testGreetingEndpoint() {
RestAssured.baseURI = String.format("http://localhost:%d/api/greeting", port);
when().get()
.then()
.statusCode(200)
.body("content", is("Hello ConfigMap dev, World!"));
when().get().then().statusCode(200).body("content",
is("Hello ConfigMap dev, World!"));
}
@Test
public void testFarewellEndpoint() {
RestAssured.baseURI = String.format("http://localhost:%d/api/farewell", port);
when().get()
.then()
.statusCode(200)
.body("content", is("Goodbye ConfigMap default, World!"));
when().get().then().statusCode(200).body("content",
is("Goodbye ConfigMap default, World!"));
}
}

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.config;
import static io.restassured.RestAssured.when;

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -19,14 +19,13 @@ package org.springframework.cloud.kubernetes.config.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
*
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.config.example2;
import org.springframework.boot.SpringApplication;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.config.example2;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,23 +1,29 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -26,81 +32,98 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
@Configuration
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
@EnableConfigurationProperties(KubernetesClientProperties.class)
public class KubernetesAutoConfiguration {
private static final Log LOG = LogFactory.getLog(KubernetesAutoConfiguration.class);
private static final Log LOG = LogFactory.getLog(KubernetesAutoConfiguration.class);
@Bean
@ConditionalOnMissingBean(Config.class)
public Config kubernetesClientConfig(KubernetesClientProperties kubernetesClientProperties) {
Config base = Config.autoConfigure(null);
Config properties = new ConfigBuilder(base)
//Only set values that have been explicitly specified
.withMasterUrl(or(kubernetesClientProperties.getMasterUrl(), base.getMasterUrl()))
.withApiVersion(or(kubernetesClientProperties.getApiVersion(), base.getApiVersion()))
.withNamespace(or(kubernetesClientProperties.getNamespace(), base.getNamespace()))
.withUsername(or(kubernetesClientProperties.getUsername(), base.getUsername()))
.withPassword(or(kubernetesClientProperties.getPassword(), base.getPassword()))
@Bean
@ConditionalOnMissingBean(Config.class)
public Config kubernetesClientConfig(
KubernetesClientProperties kubernetesClientProperties) {
Config base = Config.autoConfigure(null);
Config properties = new ConfigBuilder(base)
// Only set values that have been explicitly specified
.withMasterUrl(or(kubernetesClientProperties.getMasterUrl(),
base.getMasterUrl()))
.withApiVersion(or(kubernetesClientProperties.getApiVersion(),
base.getApiVersion()))
.withNamespace(or(kubernetesClientProperties.getNamespace(),
base.getNamespace()))
.withUsername(
or(kubernetesClientProperties.getUsername(), base.getUsername()))
.withPassword(
or(kubernetesClientProperties.getPassword(), base.getPassword()))
.withCaCertFile(or(kubernetesClientProperties.getCaCertFile(), base.getCaCertFile()))
.withCaCertData(or(kubernetesClientProperties.getCaCertData(), base.getCaCertData()))
.withCaCertFile(or(kubernetesClientProperties.getCaCertFile(),
base.getCaCertFile()))
.withCaCertData(or(kubernetesClientProperties.getCaCertData(),
base.getCaCertData()))
.withClientKeyFile(or(kubernetesClientProperties.getClientKeyFile(), base.getClientKeyFile()))
.withClientKeyData(or(kubernetesClientProperties.getClientKeyData(), base.getClientKeyData()))
.withClientKeyFile(or(kubernetesClientProperties.getClientKeyFile(),
base.getClientKeyFile()))
.withClientKeyData(or(kubernetesClientProperties.getClientKeyData(),
base.getClientKeyData()))
.withClientCertFile(or(kubernetesClientProperties.getClientCertFile(), base.getClientCertFile()))
.withClientCertData(or(kubernetesClientProperties.getClientCertData(), base.getClientCertData()))
.withClientCertFile(or(kubernetesClientProperties.getClientCertFile(),
base.getClientCertFile()))
.withClientCertData(or(kubernetesClientProperties.getClientCertData(),
base.getClientCertData()))
//No magic is done for the properties below so we leave them as is.
.withClientKeyAlgo(or(kubernetesClientProperties.getClientKeyAlgo(), base.getClientKeyAlgo()))
.withClientKeyPassphrase(or(kubernetesClientProperties.getClientKeyPassphrase(), base.getClientKeyPassphrase()))
.withConnectionTimeout(or(kubernetesClientProperties.getConnectionTimeout(), base.getConnectionTimeout()))
.withRequestTimeout(or(kubernetesClientProperties.getRequestTimeout(), base.getRequestTimeout()))
.withRollingTimeout(or(kubernetesClientProperties.getRollingTimeout(), base.getRollingTimeout()))
.withTrustCerts(or(kubernetesClientProperties.isTrustCerts(), base.isTrustCerts()))
.build();
// No magic is done for the properties below so we leave them as is.
.withClientKeyAlgo(or(kubernetesClientProperties.getClientKeyAlgo(),
base.getClientKeyAlgo()))
.withClientKeyPassphrase(
or(kubernetesClientProperties.getClientKeyPassphrase(),
base.getClientKeyPassphrase()))
.withConnectionTimeout(
or(kubernetesClientProperties.getConnectionTimeout(),
base.getConnectionTimeout()))
.withRequestTimeout(or(kubernetesClientProperties.getRequestTimeout(),
base.getRequestTimeout()))
.withRollingTimeout(or(kubernetesClientProperties.getRollingTimeout(),
base.getRollingTimeout()))
.withTrustCerts(or(kubernetesClientProperties.isTrustCerts(),
base.isTrustCerts()))
.build();
if (properties.getNamespace() == null || properties.getNamespace().isEmpty()) {
LOG.warn("No namespace has been detected. Please specify KUBERNETES_NAMESPACE env var, or use a later kubernetes version (1.3 or later)");
}
return properties;
}
if (properties.getNamespace() == null || properties.getNamespace().isEmpty()) {
LOG.warn(
"No namespace has been detected. Please specify KUBERNETES_NAMESPACE env var, or use a later kubernetes version (1.3 or later)");
}
return properties;
}
@Bean
@ConditionalOnMissingBean
public KubernetesClient kubernetesClient(Config config) {
return new DefaultKubernetesClient(config);
}
@Bean
@ConditionalOnMissingBean
public KubernetesClient kubernetesClient(Config config) {
return new DefaultKubernetesClient(config);
}
@Bean
@ConditionalOnMissingBean
public StandardPodUtils kubernetesPodUtils(KubernetesClient client) {
return new StandardPodUtils(client);
}
@Bean
@ConditionalOnMissingBean
public StandardPodUtils kubernetesPodUtils(KubernetesClient client) {
return new StandardPodUtils(client);
}
@Configuration
@ConditionalOnClass(HealthIndicator.class)
protected static class KubernetesActuatorConfiguration {
@Bean
@ConditionalOnMissingBean
public KubernetesHealthIndicator kubernetesHealthIndicator(PodUtils podUtils) {
return new KubernetesHealthIndicator(podUtils);
}
}
@Configuration
@ConditionalOnClass(HealthIndicator.class)
protected static class KubernetesActuatorConfiguration {
@Bean
@ConditionalOnMissingBean
public KubernetesHealthIndicator kubernetesHealthIndicator(PodUtils podUtils) {
return new KubernetesHealthIndicator(podUtils);
}
}
private static <D> D or(D dis, D dat) {
if (dis != null) {
return dis;
} else {
return dat;
}
}
private static <D> D or(D dis, D dat) {
if (dis != null) {
return dis;
}
else {
return dat;
}
}
}

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
@@ -21,184 +22,184 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.cloud.kubernetes.client")
public class KubernetesClientProperties {
private Boolean trustCerts;
private String masterUrl;
private String apiVersion;
private String namespace;
private String caCertFile;
private String caCertData;
private String clientCertFile;
private String clientCertData;
private String clientKeyFile;
private String clientKeyData;
private String clientKeyAlgo;
private String clientKeyPassphrase;
private String username;
private String password;
private Integer watchReconnectInterval;
private Integer watchReconnectLimit;
private Integer connectionTimeout;
private Integer requestTimeout;
private Long rollingTimeout;
private Integer loggingInterval;
private Boolean trustCerts;
private String masterUrl;
private String apiVersion;
private String namespace;
private String caCertFile;
private String caCertData;
private String clientCertFile;
private String clientCertData;
private String clientKeyFile;
private String clientKeyData;
private String clientKeyAlgo;
private String clientKeyPassphrase;
private String username;
private String password;
private Integer watchReconnectInterval;
private Integer watchReconnectLimit;
private Integer connectionTimeout;
private Integer requestTimeout;
private Long rollingTimeout;
private Integer loggingInterval;
public String getClientCertData() {
return clientCertData;
}
public String getClientCertData() {
return clientCertData;
}
public void setClientCertData(String clientCertData) {
this.clientCertData = clientCertData;
}
public void setClientCertData(String clientCertData) {
this.clientCertData = clientCertData;
}
public Boolean isTrustCerts() {
return trustCerts;
}
public Boolean isTrustCerts() {
return trustCerts;
}
public void setTrustCerts(Boolean trustCerts) {
this.trustCerts = trustCerts;
}
public void setTrustCerts(Boolean trustCerts) {
this.trustCerts = trustCerts;
}
public String getMasterUrl() {
return masterUrl;
}
public String getMasterUrl() {
return masterUrl;
}
public void setMasterUrl(String masterUrl) {
this.masterUrl = masterUrl;
}
public void setMasterUrl(String masterUrl) {
this.masterUrl = masterUrl;
}
public String getApiVersion() {
return apiVersion;
}
public String getApiVersion() {
return apiVersion;
}
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
public String getNamespace() {
return namespace;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getCaCertFile() {
return caCertFile;
}
public String getCaCertFile() {
return caCertFile;
}
public void setCaCertFile(String caCertFile) {
this.caCertFile = caCertFile;
}
public void setCaCertFile(String caCertFile) {
this.caCertFile = caCertFile;
}
public String getCaCertData() {
return caCertData;
}
public String getCaCertData() {
return caCertData;
}
public void setCaCertData(String caCertData) {
this.caCertData = caCertData;
}
public void setCaCertData(String caCertData) {
this.caCertData = caCertData;
}
public String getClientCertFile() {
return clientCertFile;
}
public String getClientCertFile() {
return clientCertFile;
}
public void setClientCertFile(String clientCertFile) {
this.clientCertFile = clientCertFile;
}
public void setClientCertFile(String clientCertFile) {
this.clientCertFile = clientCertFile;
}
public String getClientKeyFile() {
return clientKeyFile;
}
public String getClientKeyFile() {
return clientKeyFile;
}
public void setClientKeyFile(String clientKeyFile) {
this.clientKeyFile = clientKeyFile;
}
public void setClientKeyFile(String clientKeyFile) {
this.clientKeyFile = clientKeyFile;
}
public String getClientKeyData() {
return clientKeyData;
}
public String getClientKeyData() {
return clientKeyData;
}
public void setClientKeyData(String clientKeyData) {
this.clientKeyData = clientKeyData;
}
public void setClientKeyData(String clientKeyData) {
this.clientKeyData = clientKeyData;
}
public String getClientKeyAlgo() {
return clientKeyAlgo;
}
public String getClientKeyAlgo() {
return clientKeyAlgo;
}
public void setClientKeyAlgo(String clientKeyAlgo) {
this.clientKeyAlgo = clientKeyAlgo;
}
public void setClientKeyAlgo(String clientKeyAlgo) {
this.clientKeyAlgo = clientKeyAlgo;
}
public String getClientKeyPassphrase() {
return clientKeyPassphrase;
}
public String getClientKeyPassphrase() {
return clientKeyPassphrase;
}
public void setClientKeyPassphrase(String clientKeyPassphrase) {
this.clientKeyPassphrase = clientKeyPassphrase;
}
public void setClientKeyPassphrase(String clientKeyPassphrase) {
this.clientKeyPassphrase = clientKeyPassphrase;
}
public String getUsername() {
return username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getWatchReconnectInterval() {
return watchReconnectInterval;
}
public Integer getWatchReconnectInterval() {
return watchReconnectInterval;
}
public void setWatchReconnectInterval(Integer watchReconnectInterval) {
this.watchReconnectInterval = watchReconnectInterval;
}
public void setWatchReconnectInterval(Integer watchReconnectInterval) {
this.watchReconnectInterval = watchReconnectInterval;
}
public Integer getWatchReconnectLimit() {
return watchReconnectLimit;
}
public Integer getWatchReconnectLimit() {
return watchReconnectLimit;
}
public void setWatchReconnectLimit(Integer watchReconnectLimit) {
this.watchReconnectLimit = watchReconnectLimit;
}
public void setWatchReconnectLimit(Integer watchReconnectLimit) {
this.watchReconnectLimit = watchReconnectLimit;
}
public Integer getConnectionTimeout() {
return connectionTimeout;
}
public Integer getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public Integer getRequestTimeout() {
return requestTimeout;
}
public Integer getRequestTimeout() {
return requestTimeout;
}
public void setRequestTimeout(Integer requestTimeout) {
this.requestTimeout = requestTimeout;
}
public void setRequestTimeout(Integer requestTimeout) {
this.requestTimeout = requestTimeout;
}
public Long getRollingTimeout() {
return rollingTimeout;
}
public Long getRollingTimeout() {
return rollingTimeout;
}
public void setRollingTimeout(Long rollingTimeout) {
this.rollingTimeout = rollingTimeout;
}
public void setRollingTimeout(Long rollingTimeout) {
this.rollingTimeout = rollingTimeout;
}
public Integer getLoggingInterval() {
return loggingInterval;
}
public Integer getLoggingInterval() {
return loggingInterval;
}
public void setLoggingInterval(Integer loggingInterval) {
this.loggingInterval = loggingInterval;
}
public void setLoggingInterval(Integer loggingInterval) {
this.loggingInterval = loggingInterval;
}
}

View File

@@ -1,53 +1,55 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
import io.fabric8.kubernetes.api.model.Pod;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import io.fabric8.kubernetes.api.model.Pod;
public class KubernetesHealthIndicator extends AbstractHealthIndicator {
private PodUtils utils;
private PodUtils utils;
public KubernetesHealthIndicator(PodUtils utils) {
this.utils = utils;
}
public KubernetesHealthIndicator(PodUtils utils) {
this.utils = utils;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
Pod current = utils.currentPod().get();
if (current != null) {
builder.up()
.withDetail("inside", true)
.withDetail("namespace", current.getMetadata().getNamespace())
.withDetail("podName", current.getMetadata().getName())
.withDetail("podIp", current.getStatus().getPodIP())
.withDetail("serviceAccount", current.getSpec().getServiceAccountName())
.withDetail("nodeName", current.getSpec().getNodeName())
.withDetail("hostIp", current.getStatus().getHostIP());
} else {
builder.up()
.withDetail("inside", false);
}
} catch (Exception e) {
builder.down(e);
}
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
Pod current = utils.currentPod().get();
if (current != null) {
builder.up().withDetail("inside", true)
.withDetail("namespace", current.getMetadata().getNamespace())
.withDetail("podName", current.getMetadata().getName())
.withDetail("podIp", current.getStatus().getPodIP())
.withDetail("serviceAccount",
current.getSpec().getServiceAccountName())
.withDetail("nodeName", current.getSpec().getNodeName())
.withDetail("hostIp", current.getStatus().getHostIP());
}
else {
builder.up().withDetail("inside", false);
}
}
catch (Exception e) {
builder.down(e);
}
}
}

View File

@@ -1,45 +1,45 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
import java.util.function.Supplier;
public class LazilyInstantiate<T> implements Supplier<T> {
public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) {
return new LazilyInstantiate<T>(supplier);
}
public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) {
return new LazilyInstantiate<T>(supplier);
}
public synchronized T get() {
return current.get();
}
public synchronized T get() {
return current.get();
}
private LazilyInstantiate(Supplier<T> supplier) {
this.supplier = supplier;
this.current = () -> swapper();
}
private LazilyInstantiate(Supplier<T> supplier) {
this.supplier = supplier;
this.current = () -> swapper();
}
private final Supplier<T> supplier;
private Supplier<T> current;
private final Supplier<T> supplier;
private Supplier<T> current;
private T swapper() {
T obj = supplier.get();
current = () -> obj;
return obj;
}
private T swapper() {
T obj = supplier.get();
current = () -> obj;
return obj;
}
}

View File

@@ -1,35 +1,36 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
import io.fabric8.kubernetes.api.model.Pod;
import java.util.function.Supplier;
import io.fabric8.kubernetes.api.model.Pod;
public interface PodUtils {
/**
* @return A supplier of the currentPod {@link Pod}. The supplier will hold the currentPod {@Pod} if inside Kubernetes
* or false, otherwise.
*/
Supplier<Pod> currentPod();
/**
* @return A supplier of the currentPod {@link Pod}. The supplier will hold the
* currentPod {@Pod} if inside Kubernetes or false, otherwise.
*/
Supplier<Pod> currentPod();
/**
* @return true if called from within Kubernetes, false otherwise.
*/
Boolean isInsideKubernetes();
/**
* @return true if called from within Kubernetes, false otherwise.
*/
Boolean isInsideKubernetes();
}

View File

@@ -1,79 +1,85 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.nio.file.Paths;
import java.util.function.Supplier;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class StandardPodUtils implements PodUtils {
private static final Log LOG = LogFactory.getLog(StandardPodUtils.class);
public static final String HOSTNAME = "HOSTNAME";
private static final Log LOG = LogFactory.getLog(StandardPodUtils.class);
public static final String HOSTNAME = "HOSTNAME";
private final KubernetesClient client;
private final String hostName;
private Supplier<Pod> current;
private final KubernetesClient client;
private final String hostName;
private Supplier<Pod> current;
public StandardPodUtils(KubernetesClient client) {
if (client == null) {
throw new IllegalArgumentException("Must provide an instance of KubernetesClient");
}
public StandardPodUtils(KubernetesClient client) {
if (client == null) {
throw new IllegalArgumentException(
"Must provide an instance of KubernetesClient");
}
this.client = client;
this.hostName = System.getenv(HOSTNAME);
this.current = LazilyInstantiate.using(() -> internalGetPod());
}
this.client = client;
this.hostName = System.getenv(HOSTNAME);
this.current = LazilyInstantiate.using(() -> internalGetPod());
}
@Override
public Supplier<Pod> currentPod() {
return current;
}
@Override
public Supplier<Pod> currentPod() {
return current;
}
@Override
public Boolean isInsideKubernetes() {
return currentPod().get() != null;
}
@Override
public Boolean isInsideKubernetes() {
return currentPod().get() != null;
}
private synchronized Pod internalGetPod() {
try {
if (isServiceAccountFound() && isHostNameEnvVarPresent()) {
return client.pods().withName(hostName).get();
} else {
return null;
}
} catch (Throwable t) {
LOG.warn("Failed to get pod with name:[" + hostName + "]. You should look into this if things aren't working as you expect. Are you missing serviceaccount permissions?", t);
return null;
}
}
private synchronized Pod internalGetPod() {
try {
if (isServiceAccountFound() && isHostNameEnvVarPresent()) {
return client.pods().withName(hostName).get();
}
else {
return null;
}
}
catch (Throwable t) {
LOG.warn("Failed to get pod with name:[" + hostName
+ "]. You should look into this if things aren't working as you expect. Are you missing serviceaccount permissions?",
t);
return null;
}
}
private boolean isHostNameEnvVarPresent() {
return hostName != null && !hostName.isEmpty();
}
private boolean isHostNameEnvVarPresent() {
return hostName != null && !hostName.isEmpty();
}
private boolean isServiceAccountFound() {
return Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH).toFile().exists() &&
Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile().exists();
}
private boolean isServiceAccountFound() {
return Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH).toFile().exists()
&& Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile()
.exists();
}
}

View File

@@ -1,23 +1,26 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.profile;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import java.util.function.Supplier;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import org.springframework.cloud.kubernetes.LazilyInstantiate;
import org.springframework.cloud.kubernetes.StandardPodUtils;
import org.springframework.context.ApplicationContextInitializer;
@@ -25,34 +28,33 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
public class KubernetesApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private static final int ORDER = 100;
private static final int ORDER = 100;
private final Supplier<KubernetesProfileApplicationListener> listenerSupplier;
private final Supplier<KubernetesProfileApplicationListener> listenerSupplier;
public KubernetesApplicationContextInitializer() {
this(LazilyInstantiate.using(() ->
//If we are inside Kubernetes this should be perfectly valid.
//If not then we won't add the Kubernetes profile anyway.
new KubernetesProfileApplicationListener(
new StandardPodUtils(new DefaultKubernetesClient()))
));
// If we are inside Kubernetes this should be perfectly valid.
// If not then we won't add the Kubernetes profile anyway.
new KubernetesProfileApplicationListener(
new StandardPodUtils(new DefaultKubernetesClient()))));
}
public KubernetesApplicationContextInitializer(
Supplier<KubernetesProfileApplicationListener> listenerSupplier) {
Supplier<KubernetesProfileApplicationListener> listenerSupplier) {
this.listenerSupplier = listenerSupplier;
}
@Override
public int getOrder() {
return ORDER;
}
public int getOrder() {
return ORDER;
}
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
listenerSupplier.get().addKubernetesProfile(applicationContext.getEnvironment());
}
}
}

View File

@@ -1,79 +1,86 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.profile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.PodUtils;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.cloud.kubernetes.PodUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
public class KubernetesProfileApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
public class KubernetesProfileApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
private static final Log LOG = LogFactory.getLog(KubernetesProfileApplicationListener.class);
private static final Log LOG = LogFactory
.getLog(KubernetesProfileApplicationListener.class);
private static final String KUBERNETES_PROFILE = "kubernetes";
private static final int OFFSET = 1;
private static final int ORDER = Ordered.HIGHEST_PRECEDENCE + OFFSET;
private final PodUtils utils;
private static final String KUBERNETES_PROFILE = "kubernetes";
private static final int OFFSET = 1;
private static final int ORDER = Ordered.HIGHEST_PRECEDENCE + OFFSET;
private final PodUtils utils;
public KubernetesProfileApplicationListener(PodUtils utils) {
this.utils = utils;
}
public KubernetesProfileApplicationListener(PodUtils utils) {
this.utils = utils;
}
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
addKubernetesProfile(environment);
}
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
addKubernetesProfile(environment);
}
void addKubernetesProfile(ConfigurableEnvironment environment) {
if (utils.isInsideKubernetes()) {
if (hasKubernetesProfile(environment)) {
if (LOG.isDebugEnabled()) {
LOG.debug("'kubernetes' already in list of active profiles");
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Adding 'kubernetes' to list of active profiles");
}
environment.addActiveProfile(KUBERNETES_PROFILE);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.warn("Not running inside kubernetes. Skipping 'kubernetes' profile activation.");
}
}
}
void addKubernetesProfile(ConfigurableEnvironment environment) {
if (utils.isInsideKubernetes()) {
if (hasKubernetesProfile(environment)) {
if (LOG.isDebugEnabled()) {
LOG.debug("'kubernetes' already in list of active profiles");
}
}
else {
if (LOG.isDebugEnabled()) {
LOG.debug("Adding 'kubernetes' to list of active profiles");
}
environment.addActiveProfile(KUBERNETES_PROFILE);
}
}
else {
if (LOG.isDebugEnabled()) {
LOG.warn(
"Not running inside kubernetes. Skipping 'kubernetes' profile activation.");
}
}
}
private boolean hasKubernetesProfile(Environment environment) {
for (String activeProfile : environment.getActiveProfiles()) {
if (KUBERNETES_PROFILE.equalsIgnoreCase(activeProfile)) {
return true;
}
}
return false;
}
private boolean hasKubernetesProfile(Environment environment) {
for (String activeProfile : environment.getActiveProfiles()) {
if (KUBERNETES_PROFILE.equalsIgnoreCase(activeProfile)) {
return true;
}
}
return false;
}
@Override
public int getOrder() {
return ORDER;
}
@Override
public int getOrder() {
return ORDER;
}
}

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes;
@@ -19,11 +20,11 @@ import org.junit.Test;
public class StandardPodUtilsTest {
@Test(expected = IllegalArgumentException.class)
public void constructorThrowsIllegalArgumentExceptionWhenKubeClientNull() {
// expect an IllegalArgumentException if KubernetesClient argument is
// null
new StandardPodUtils(null);
}
@Test(expected = IllegalArgumentException.class)
public void constructorThrowsIllegalArgumentExceptionWhenKubeClientNull() {
// expect an IllegalArgumentException if KubernetesClient argument is
// null
new StandardPodUtils(null);
}
}

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.profile;
import org.junit.Before;

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.discovery;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.discovery;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.discovery;
import io.fabric8.kubernetes.client.KubernetesClient;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.discovery;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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
* 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.
*
* 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 org.springframework.cloud.kubernetes.discovery;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.registry;
import java.util.concurrent.atomic.AtomicBoolean;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.registry;
import java.io.Closeable;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.registry;
import org.apache.commons.logging.Log;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.discovery
import io.fabric8.kubernetes.api.model.EndpointsBuilder

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.discovery;
import io.fabric8.kubernetes.client.KubernetesClient;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.discovery;
import io.fabric8.kubernetes.api.model.*;

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.examples;
import java.util.List;
@@ -5,7 +22,6 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.examples;
import org.junit.Test;
@@ -5,7 +22,6 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.*;
@@ -14,14 +30,15 @@ import static org.assertj.core.api.Assertions.*;
@SpringBootTest(classes = App.class)
public class ApplicationTestIT {
@Autowired
private ApplicationContext context;
@Autowired
private ApplicationContext context;
/*
* This test proves that the application can be loaded successful and that all @configurations and dependencies are there
*/
@Test
public void contextLoads() throws Exception {
assertThat(context).isNotNull();
}
/*
* This test proves that the application can be loaded successful and that
* all @configurations and dependencies are there
*/
@Test
public void contextLoads() throws Exception {
assertThat(context).isNotNull();
}
}

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -18,7 +18,6 @@ package org.springframework.cloud.kubernetes.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
@@ -28,8 +27,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -23,14 +23,14 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties(prefix = "dummy")
public class DummyConfig {
private String message = "this is a dummy message";
private String message = "this is a dummy message";
public String getMessage() {
return message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -23,17 +23,17 @@ import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Autowired
private MyConfig myConfig;
@Autowired
private MyConfig myConfig;
@Autowired
private DummyConfig dummyConfig;
@Autowired
private DummyConfig dummyConfig;
@Scheduled(fixedDelay = 5000)
public void hello() {
System.out.println("The first message is: " + myConfig.getMessage());
System.out.println("The other message is: " + dummyConfig.getMessage());
}
@Scheduled(fixedDelay = 5000)
public void hello() {
System.out.println("The first message is: " + myConfig.getMessage());
System.out.println("The other message is: " + dummyConfig.getMessage());
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -23,14 +23,14 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties(prefix = "bean")
public class MyConfig {
private String message = "a message that can be changed live";
private String message = "a message that can be changed live";
public String getMessage() {
return message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,17 +1,18 @@
/*
* Copyright (C) 2018 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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 org.springframework.cloud.kubernetes.leader;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.leader;
import org.junit.Before;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.leader;
import java.util.concurrent.ScheduledExecutorService;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.leader;
import java.util.Collections;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.leader;
import org.junit.Before;

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.leader;
import java.util.Collections;

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -30,86 +30,88 @@ import com.netflix.client.config.IClientConfigKey;
public abstract class KubernetesConfigKey<T> implements IClientConfigKey<T> {
public static final IClientConfigKey<String> Namespace = new KubernetesConfigKey<String>("KubernetesNamespace"){};
public static final IClientConfigKey<String> PortName = new KubernetesConfigKey<String>("PortName"){};
public static final IClientConfigKey<String> Namespace = new KubernetesConfigKey<String>("KubernetesNamespace") {
};
public static final IClientConfigKey<String> PortName = new KubernetesConfigKey<String>("PortName") {
};
private static final Set<IClientConfigKey> keys = new HashSet<IClientConfigKey>();
private static final Set<IClientConfigKey> keys = new HashSet<IClientConfigKey>();
static {
for (Field f: KubernetesConfigKey.class.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()) //&& Modifier.isPublic(f.getModifiers())
&& IClientConfigKey.class.isAssignableFrom(f.getType())) {
try {
keys.add((IClientConfigKey) f.get(null));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
static {
for (Field f : KubernetesConfigKey.class.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()) //&& Modifier.isPublic(f.getModifiers())
&& IClientConfigKey.class.isAssignableFrom(f.getType())) {
try {
keys.add((IClientConfigKey) f.get(null));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* @deprecated see {@link #keys()}
*/
@Deprecated
public static IClientConfigKey[] values() {
return keys().toArray(new IClientConfigKey[0]);
}
/**
* @deprecated see {@link #keys()}
*/
@Deprecated
public static IClientConfigKey[] values() {
return keys().toArray(new IClientConfigKey[0]);
}
/**
* return all the public static keys defined in this class
*/
public static Set<IClientConfigKey> keys() {
return keys;
}
/**
* return all the public static keys defined in this class
*/
public static Set<IClientConfigKey> keys() {
return keys;
}
public static IClientConfigKey valueOf(final String name) {
for (IClientConfigKey key: keys()) {
if (key.key().equals(name)) {
return key;
}
}
return new IClientConfigKey() {
@Override
public String key() {
return name;
}
public static IClientConfigKey valueOf(final String name) {
for (IClientConfigKey key : keys()) {
if (key.key().equals(name)) {
return key;
}
}
return new IClientConfigKey() {
@Override
public String key() {
return name;
}
@Override
public Class type() {
return String.class;
}
};
}
@Override
public Class type() {
return String.class;
}
};
}
private final String configKey;
private final Class<T> type;
private final String configKey;
private final Class<T> type;
@SuppressWarnings("unchecked")
protected KubernetesConfigKey(String configKey) {
this.configKey = configKey;
Type superclass = getClass().getGenericSuperclass();
Assert.isTrue(superclass instanceof ParameterizedType,
superclass + " isn't parameterized");
Type runtimeType = ((ParameterizedType) superclass).getActualTypeArguments()[0];
type = (Class<T>) Types.rawType(runtimeType);
}
@SuppressWarnings("unchecked")
protected KubernetesConfigKey(String configKey) {
this.configKey = configKey;
Type superclass = getClass().getGenericSuperclass();
Assert.isTrue(superclass instanceof ParameterizedType,
superclass + " isn't parameterized");
Type runtimeType = ((ParameterizedType) superclass).getActualTypeArguments()[0];
type = (Class<T>) Types.rawType(runtimeType);
}
@Override
public Class<T> type() {
return type;
}
@Override
public Class<T> type() {
return type;
}
/* (non-Javadoc)
/* (non-Javadoc)
* @see com.netflix.niws.client.ClientConfig#key()
*/
@Override
public String key() {
return configKey;
}
@Override
public String key() {
return configKey;
}
@Override
public String toString() {
return configKey;
}
@Override
public String toString() {
return configKey;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -20,6 +20,7 @@ package org.springframework.cloud.kubernetes.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -27,14 +28,14 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class KubernetesRibbonClientConfiguration {
public KubernetesRibbonClientConfiguration() {
}
public KubernetesRibbonClientConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(KubernetesClient client, IClientConfig config) {
KubernetesServerList serverList = new KubernetesServerList(client);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(KubernetesClient client, IClientConfig config) {
KubernetesServerList serverList = new KubernetesServerList(client);
serverList.initWithNiwsConfig(config);
return serverList;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -17,86 +17,89 @@
package org.springframework.cloud.kubernetes.ribbon;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import io.fabric8.kubernetes.api.model.EndpointAddress;
import io.fabric8.kubernetes.api.model.EndpointPort;
import io.fabric8.kubernetes.api.model.EndpointSubset;
import io.fabric8.kubernetes.api.model.Endpoints;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.utils.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class KubernetesServerList extends AbstractServerList<Server>
implements ServerList<Server> {
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
private static final int FIRST = 0;
private static final Log LOG = LogFactory.getLog(KubernetesServerList.class);
public class KubernetesServerList extends AbstractServerList<Server> implements ServerList<Server> {
private final KubernetesClient client;
private static final int FIRST = 0;
private static final Log LOG = LogFactory.getLog(KubernetesServerList.class);
private String serviceId;
private final KubernetesClient client;
private String namespace;
private String portName;
private String serviceId;
public KubernetesServerList(KubernetesClient client) {
this.client = client;
}
private String namespace;
private String portName;
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.serviceId = clientConfig.getClientName();
this.namespace = clientConfig.getPropertyAsString(KubernetesConfigKey.Namespace,
client.getNamespace());
this.portName = clientConfig.getPropertyAsString(KubernetesConfigKey.PortName,
null);
}
public List<Server> getInitialListOfServers() {
return Collections.emptyList();
}
public KubernetesServerList(KubernetesClient client) {
this.client = client;
}
public List<Server> getUpdatedListOfServers() {
Endpoints endpoints = namespace != null
? client.endpoints().inNamespace(namespace).withName(serviceId).get()
: client.endpoints().withName(serviceId).get();
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.serviceId = clientConfig.getClientName();
this.namespace = clientConfig.getPropertyAsString(KubernetesConfigKey.Namespace, client.getNamespace());
this.portName = clientConfig.getPropertyAsString(KubernetesConfigKey.PortName, null);
}
List<Server> result = new ArrayList<Server>();
if (endpoints != null) {
public List<Server> getInitialListOfServers() {
return Collections.emptyList();
}
if (LOG.isDebugEnabled()) {
LOG.debug("Found [" + endpoints.getSubsets().size()
+ "] endpoints in namespace [" + namespace + "] for name ["
+ serviceId + "] and portName [" + portName + "]");
}
for (EndpointSubset subset : endpoints.getSubsets()) {
public List<Server> getUpdatedListOfServers() {
Endpoints endpoints = namespace != null
? client.endpoints().inNamespace(namespace).withName(serviceId).get()
: client.endpoints().withName(serviceId).get();
List<Server> result = new ArrayList<Server>();
if (endpoints != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Found [" + endpoints.getSubsets().size() + "] endpoints in namespace [" +
namespace + "] for name [" + serviceId + "] and portName [" + portName + "]");
}
for (EndpointSubset subset : endpoints.getSubsets()) {
if (subset.getPorts().size() == 1) {
EndpointPort port = subset.getPorts().get(FIRST);
for (EndpointAddress address : subset.getAddresses()) {
result.add(new Server(address.getIp(), port.getPort()));
}
} else {
for (EndpointPort port : subset.getPorts()) {
if (Utils.isNullOrEmpty(portName) || portName.endsWith(port.getName())) {
for (EndpointAddress address : subset.getAddresses()) {
result.add(new Server(address.getIp(), port.getPort()));
}
}
}
}
}
} else {
LOG.warn("Did not find any endpoints in ribbon in namespace [" + namespace + "] for name [" +
serviceId + "] and portName [" + portName + "]");
}
return result;
}
if (subset.getPorts().size() == 1) {
EndpointPort port = subset.getPorts().get(FIRST);
for (EndpointAddress address : subset.getAddresses()) {
result.add(new Server(address.getIp(), port.getPort()));
}
}
else {
for (EndpointPort port : subset.getPorts()) {
if (Utils.isNullOrEmpty(portName)
|| portName.endsWith(port.getName())) {
for (EndpointAddress address : subset.getAddresses()) {
result.add(new Server(address.getIp(), port.getPort()));
}
}
}
}
}
}
else {
LOG.warn("Did not find any endpoints in ribbon in namespace [" + namespace
+ "] for name [" + serviceId + "] and portName [" + portName + "]");
}
return result;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,36 +1,55 @@
package org.springframework.cloud.kubernetes.ribbon;
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.ribbon;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Set;
final class Types {
private Types() {
//Utlity
}
private Types() {
// Utlity
}
static Class rawType(Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof TypeVariable) {
return rawType(firstOrObject(((TypeVariable) type).getBounds()));
} else if (type instanceof WildcardType) {
return rawType(firstOrObject(((WildcardType) type).getUpperBounds()));
} else if (type instanceof GenericArrayType) {
return rawType(((GenericArrayType) type).getGenericComponentType());
}
return Object.class;
}
static Class rawType(Type type) {
if (type instanceof Class) {
return (Class) type;
}
else if (type instanceof TypeVariable) {
return rawType(firstOrObject(((TypeVariable) type).getBounds()));
}
else if (type instanceof WildcardType) {
return rawType(firstOrObject(((WildcardType) type).getUpperBounds()));
}
else if (type instanceof GenericArrayType) {
return rawType(((GenericArrayType) type).getGenericComponentType());
}
return Object.class;
}
private static Type firstOrObject(Type[] types) {
if (types.length > 0) {
return rawType(types[0]);
} else {
return Void.class;
}
}
private static Type firstOrObject(Type[] types) {
if (types.length > 0) {
return rawType(types[0]);
}
else {
return Void.class;
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,

View File

@@ -1,27 +1,47 @@
package org.springframework.cloud.kubernetes.ribbon;
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.ribbon;
import org.junit.Assert;
import org.junit.Test;
public class KubernetesConfigKeyTest {
private class TypeOne<T> {}
private class TypeOne<T> {
}
@Test
public <T extends TypeOne, I> void testTypes() {
//with class
KubernetesConfigKey<String> key1 = new KubernetesConfigKey<String>("key1"){};
@Test
public <T extends TypeOne, I> void testTypes() {
// with class
KubernetesConfigKey<String> key1 = new KubernetesConfigKey<String>("key1") {
};
//with type variable
KubernetesConfigKey<T> key2 = new KubernetesConfigKey<T>("key2"){};
// with type variable
KubernetesConfigKey<T> key2 = new KubernetesConfigKey<T>("key2") {
};
//with type variable with no bounds
KubernetesConfigKey<I> key3 = new KubernetesConfigKey<I>("key3"){};
// with type variable with no bounds
KubernetesConfigKey<I> key3 = new KubernetesConfigKey<I>("key3") {
};
Assert.assertEquals(String.class, key1.type());
Assert.assertEquals(TypeOne.class, key2.type());
Assert.assertEquals(Object.class, key3.type());
}
Assert.assertEquals(String.class, key1.type());
Assert.assertEquals(TypeOne.class, key2.type());
Assert.assertEquals(Object.class, key3.type());
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -30,6 +30,7 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -44,12 +45,11 @@ import static org.junit.Assert.fail;
* @author Charles Moulliard
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class,
properties = {
"spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns"})
@SpringBootTest(classes = TestApplication.class, properties = {
"spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns" })
@EnableAutoConfiguration
@EnableDiscoveryClient
public class RibbonFallbackTest {
@@ -76,11 +76,13 @@ public class RibbonFallbackTest {
public static void setUpBefore() throws Exception {
mockClient = mockServer.getClient();
//Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY,
"false");
mockEndpoint = new DefaultMockServer(false);
mockEndpoint.start();
@@ -89,28 +91,27 @@ public class RibbonFallbackTest {
@Test
public void testFallBackGreetingEndpoint() {
/**
* Scenario tested
* 1. Register the mock endpoint of the service into KubeMockServer and call /greeting service
* 2. Unregister the mock endpoint and verify that Ribbon doesn't have any instances anymore in its list
* 3. Re register the mock endpoint and play step 1)
* Scenario tested 1. Register the mock endpoint of the service into
* KubeMockServer and call /greeting service 2. Unregister the mock endpoint and
* verify that Ribbon doesn't have any instances anymore in its list 3. Re
* register the mock endpoint and play step 1)
**/
LOG.info(">>>>>>>>>> BEGIN PART 1 <<<<<<<<<<<<<");
// As Ribbon refreshes its list every serverListRefreshInterval ms,
// we configure the API Server endpoint to reply to exactly serviceOccurrence attempts
// we configure the API Server endpoint to reply to exactly serviceOccurrence
// attempts
// to be sure that Ribbon will get the mockendpoint to access it for the call
mockServer.expect().get()
.withPath("/api/v1/namespaces/testns/endpoints/testapp")
.andReturn(200, newEndpoint("testapp-a","testns", mockEndpoint))
.times(serviceOccurrence);
mockServer.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp")
.andReturn(200, newEndpoint("testapp-a", "testns", mockEndpoint))
.times(serviceOccurrence);
mockEndpoint.expect().get()
.withPath("/greeting")
.andReturn(200, "Hello from A")
.once();
mockEndpoint.expect().get().withPath("/greeting").andReturn(200, "Hello from A")
.once();
String response = restTemplate.getForObject("http://testapp/greeting", String.class);
String response = restTemplate.getForObject("http://testapp/greeting",
String.class);
Assert.assertEquals("Hello from A", response);
LOG.info(">>>>>>>>>> END PART 1 <<<<<<<<<<<<<");
@@ -118,53 +119,66 @@ public class RibbonFallbackTest {
try {
ensureEndpointsNoLongerReturnedByAPIServer();
restTemplate.getForObject("http://testapp/greeting", String.class);
fail("Ribbon was supposed to throw an Exception due to not knowing of any endpoints to route the request to");
} catch (Exception e) {
fail("Ribbon was supposed to throw an Exception due to not knowing of any endpoints to route the request to");
}
catch (Exception e) {
// No endpoint is available anymore and Ribbon list is empty
Assert.assertEquals("No instances available for testapp", e.getMessage());
}
LOG.info(">>>>>>>>>> END PART 2 <<<<<<<<<<<<<");
LOG.info(">>>>>>>>>> BEGIN PART 3 <<<<<<<<<<<<<");
mockServer.expect().get()
.withPath("/api/v1/namespaces/testns/endpoints/testapp")
.andReturn(200, newEndpoint("testapp-a","testns", mockEndpoint))
.always();
mockServer.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp")
.andReturn(200, newEndpoint("testapp-a", "testns", mockEndpoint))
.always();
// the purpose of sleeping here is to make sure that even after some refreshes to it's list
// the purpose of sleeping here is to make sure that even after some refreshes to
// it's list
// Ribbon still has endpoints to route to
// This is different than the first part of the test because the API server has now been
// configured to always respond with some endpoints as opposed to only a certain amount of
// This is different than the first part of the test because the API server has
// now been
// configured to always respond with some endpoints as opposed to only a certain
// amount of
// requests which was the case in part 1
try {
Thread.sleep(2000);
} catch(InterruptedException ex) {
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
mockEndpoint.expect().get().withPath("/greeting").andReturn(200, "Hello from A").once();
mockEndpoint.expect().get().withPath("/greeting").andReturn(200, "Hello from A")
.once();
response = restTemplate.getForObject("http://testapp/greeting", String.class);
Assert.assertEquals("Hello from A",response);
Assert.assertEquals("Hello from A", response);
LOG.info(">>>>>>>>>> END PART 3 <<<<<<<<<<<<<");
}
// This works because the (mock) API server is configured to return the endpoints exactly
// serviceOccurrence times while Ribbon refreshes it's list every serverListRefreshInterval milliseconds
private void ensureEndpointsNoLongerReturnedByAPIServer() throws InterruptedException {
// This works because the (mock) API server is configured to return the endpoints
// exactly
// serviceOccurrence times while Ribbon refreshes it's list every
// serverListRefreshInterval milliseconds
private void ensureEndpointsNoLongerReturnedByAPIServer()
throws InterruptedException {
Thread.sleep((serviceOccurrence + 1) * serverListRefreshInterval);
}
public static Endpoints newEndpoint(String name, String namespace, DefaultMockServer mockServer) {
public static Endpoints newEndpoint(String name, String namespace,
DefaultMockServer mockServer) {
// @formatter:off
return new EndpointsBuilder()
.withNewMetadata()
.withName(name)
.withNamespace(namespace)
.endMetadata()
.addNewSubset()
.addNewAddress().withIp(mockServer.getHostName()).endAddress()
.addNewPort("http",mockServer.getPort(),"http")
.endSubset()
.build();
.withNewMetadata()
.withName(name)
.withNamespace(namespace)
.endMetadata()
.addNewSubset()
.addNewAddress()
.withIp(mockServer.getHostName())
.endAddress()
.addNewPort("http", mockServer.getPort(), "http")
.endSubset()
.build();
// @formatter:on
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2016 to the original authors.
* Copyright 2013-2018 the original author or authors.
*
* 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
* 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,
@@ -28,6 +28,7 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
@@ -39,12 +40,11 @@ import org.springframework.web.client.RestTemplate;
* @author Charles Moulliard
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class,
properties = {
"spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns"})
@SpringBootTest(classes = TestApplication.class, properties = {
"spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns" })
@EnableAutoConfiguration
@EnableDiscoveryClient
public class RibbonTest {
@@ -67,36 +67,43 @@ public class RibbonTest {
public static void setUpBefore() throws Exception {
mockClient = server.getClient();
//Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY,
"false");
//Configured
server.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp").andReturn(200, new EndpointsBuilder()
.withNewMetadata()
.withName("testapp-a")
.endMetadata()
.addNewSubset()
.addNewAddress().withIp(mockEndpointA.getMockServer().getHostName()).endAddress()
.addNewPort("http", mockEndpointA.getMockServer().getPort(), "http")
.endSubset()
.addNewSubset()
.addNewAddress().withIp(mockEndpointB.getMockServer().getHostName()).endAddress()
.addNewPort("http", mockEndpointB.getMockServer().getPort(), "http")
.endSubset()
.build()).always();
// Configured
server.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp")
.andReturn(200,
new EndpointsBuilder().withNewMetadata().withName("testapp-a")
.endMetadata().addNewSubset().addNewAddress()
.withIp(mockEndpointA.getMockServer().getHostName())
.endAddress()
.addNewPort("http",
mockEndpointA.getMockServer().getPort(), "http")
.endSubset().addNewSubset().addNewAddress()
.withIp(mockEndpointB.getMockServer().getHostName())
.endAddress()
.addNewPort("http",
mockEndpointB.getMockServer().getPort(), "http")
.endSubset().build())
.always();
mockEndpointA.expect().get().withPath("/greeting").andReturn(200, "Hello from A").always();
mockEndpointB.expect().get().withPath("/greeting").andReturn(200, "Hello from B").always();
mockEndpointA.expect().get().withPath("/greeting").andReturn(200, "Hello from A")
.always();
mockEndpointB.expect().get().withPath("/greeting").andReturn(200, "Hello from B")
.always();
}
@Test
public void testGreetingEndpoint() {
List<String> greetings = new ArrayList<>();
for (int i = 0; i < 2 ; i++) {
greetings.add(restTemplate.getForObject("http://testapp/greeting", String.class));
for (int i = 0; i < 2; i++) {
greetings.add(
restTemplate.getForObject("http://testapp/greeting", String.class));
}
greetings.contains("Hello from A");
greetings.contains("Hello from B");

View File

@@ -1,3 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.ribbon;
import org.springframework.boot.SpringApplication;

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"

View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016 to the original authors.
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.
~ Copyright 2013-2018 the original author or authors.
~
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"