Added checkstyle
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.yaml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
117
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Executable file
117
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Executable file
@@ -0,0 +1,117 @@
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is
|
||||
* provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl
|
||||
* property to use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for
|
||||
* the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a
|
||||
// custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory,
|
||||
MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if (mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(
|
||||
mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.out.println(
|
||||
"- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: : " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(),
|
||||
MAVEN_WRAPPER_JAR_PATH);
|
||||
if (!outputFile.getParentFile().exists()) {
|
||||
if (!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println("- ERROR creating output direcrory '"
|
||||
+ outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination)
|
||||
throws Exception {
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file → Executable file
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file → Executable file
Binary file not shown.
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file → Executable file
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file → Executable file
@@ -1 +1 @@
|
||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
||||
0
.springformat
Normal file
0
.springformat
Normal file
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
|
||||
177
mvnw
vendored
177
mvnw
vendored
@@ -54,38 +54,16 @@ case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
@@ -130,7 +108,7 @@ if $cygwin ; then
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
@@ -184,27 +162,28 @@ fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
@@ -216,38 +195,92 @@ concat_lines() {
|
||||
fi
|
||||
}
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
echo "Running version check"
|
||||
VERSION=$( sed '\!<parent!,\!</parent!d' `dirname $0`/pom.xml | grep '<version' | head -1 | sed -e 's/.*<version>//' -e 's!</version>.*$!!' )
|
||||
echo "The found version is [${VERSION}]"
|
||||
|
||||
if echo $VERSION | egrep -q 'M|RC'; then
|
||||
echo Activating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
|
||||
else
|
||||
echo Deactivating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
|
||||
fi
|
||||
|
||||
if echo $VERSION | egrep -q 'RELEASE'; then
|
||||
echo Activating \"central\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral"
|
||||
else
|
||||
echo Deactivating \"central\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//')
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
|
||||
306
mvnw.cmd
vendored
Normal file → Executable file
306
mvnw.cmd
vendored
Normal file → Executable file
@@ -1,145 +1,161 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
|
||||
34
pom.xml
34
pom.xml
@@ -16,8 +16,8 @@
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
|
||||
@@ -52,8 +52,11 @@
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/spring-cloud-incubator/spring-cloud-kubernetes</url>
|
||||
<connection>scm:git:git://github.com/spring-cloud-incubator/spring-cloud-kubernetes.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud-incubator/spring-cloud-kubernetes.git
|
||||
<connection>
|
||||
scm:git:git://github.com/spring-cloud-incubator/spring-cloud-kubernetes.git
|
||||
</connection>
|
||||
<developerConnection>
|
||||
scm:git:ssh://git@github.com/spring-cloud-incubator/spring-cloud-kubernetes.git
|
||||
</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
@@ -74,6 +77,12 @@
|
||||
<groovy.version>2.4.12</groovy.version>
|
||||
<restassured.version>3.0.2</restassured.version>
|
||||
<spock-spring.version>1.1-groovy-2.4</spock-spring.version>
|
||||
|
||||
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError>
|
||||
<maven-checkstyle-plugin.failsOnViolation>true
|
||||
</maven-checkstyle-plugin.failsOnViolation>
|
||||
<maven-checkstyle-plugin.includeTestSourceDirectory>true
|
||||
</maven-checkstyle-plugin.includeTestSourceDirectory>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
@@ -176,9 +185,26 @@
|
||||
<useSystemClassLoader>false</useSystemClassLoader>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.spring.javaformat</groupId>
|
||||
<artifactId>spring-javaformat-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,21 +12,27 @@
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Abstraction over configuration properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public abstract class AbstractConfigProperties {
|
||||
|
||||
protected boolean enabled = true;
|
||||
|
||||
protected String name;
|
||||
|
||||
protected String namespace;
|
||||
|
||||
public abstract String getConfigurationTarget();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
@@ -34,7 +40,7 @@ public abstract class AbstractConfigProperties {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -42,10 +48,11 @@ public abstract class AbstractConfigProperties {
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -30,6 +29,11 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Auto configuration that reuses Kubernetes config maps as property sources.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@ConditionalOnClass({ ConfigMap.class, Secret.class })
|
||||
@@ -40,6 +44,7 @@ public class BootstrapConfiguration {
|
||||
@EnableConfigurationProperties({ ConfigMapConfigProperties.class,
|
||||
SecretsConfigProperties.class })
|
||||
protected static class KubernetesPropertySourceConfiguration {
|
||||
|
||||
@Autowired
|
||||
private KubernetesClient client;
|
||||
|
||||
@@ -47,14 +52,16 @@ public class BootstrapConfiguration {
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true)
|
||||
public ConfigMapPropertySourceLocator configMapPropertySourceLocator(
|
||||
ConfigMapConfigProperties properties) {
|
||||
return new ConfigMapPropertySourceLocator(client, properties);
|
||||
return new ConfigMapPropertySourceLocator(this.client, properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.secrets.enabled", matchIfMissing = true)
|
||||
public SecretsPropertySourceLocator secretsPropertySourceLocator(
|
||||
SecretsConfigProperties properties) {
|
||||
return new SecretsPropertySourceLocator(client, properties);
|
||||
return new SecretsPropertySourceLocator(this.client, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -25,33 +24,40 @@ import java.util.stream.Collectors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Config map configuration properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.kubernetes.config")
|
||||
public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
private static final String TARGET = "Config Map";
|
||||
|
||||
private boolean enableApi = true;
|
||||
|
||||
private List<String> paths = new LinkedList<>();
|
||||
|
||||
private List<Source> sources = new LinkedList<>();
|
||||
|
||||
public boolean isEnableApi() {
|
||||
return enableApi;
|
||||
return this.enableApi;
|
||||
}
|
||||
|
||||
public void setEnableApi(boolean enableApi) {
|
||||
this.enableApi = enableApi;
|
||||
}
|
||||
|
||||
public List<String> getPaths() {
|
||||
return this.paths;
|
||||
}
|
||||
|
||||
public void setPaths(List<String> paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
public List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
public List<Source> getSources() {
|
||||
return sources;
|
||||
return this.sources;
|
||||
}
|
||||
|
||||
public void setSources(List<Source> sources) {
|
||||
@@ -67,15 +73,16 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
* ConfigMapPropertySource
|
||||
*/
|
||||
public List<NormalizedSource> determineSources() {
|
||||
if (sources.isEmpty()) {
|
||||
if (this.sources.isEmpty()) {
|
||||
return new ArrayList<NormalizedSource>() {
|
||||
{
|
||||
add(new NormalizedSource(name, namespace));
|
||||
add(new NormalizedSource(ConfigMapConfigProperties.this.name,
|
||||
ConfigMapConfigProperties.this.namespace));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return sources.stream().map(s -> s.normalize(name, namespace))
|
||||
return this.sources.stream().map(s -> s.normalize(this.name, this.namespace))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -84,15 +91,18 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
return TARGET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Config map source.
|
||||
*/
|
||||
public static class Source {
|
||||
|
||||
/**
|
||||
* The name of the ConfigMap
|
||||
* The name of the ConfigMap.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The namespace where the ConfigMap is found
|
||||
* The namespace where the ConfigMap is found.
|
||||
*/
|
||||
private String namespace;
|
||||
|
||||
@@ -105,7 +115,7 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -113,7 +123,7 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
@@ -121,7 +131,7 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return StringUtils.isEmpty(name) && StringUtils.isEmpty(namespace);
|
||||
return StringUtils.isEmpty(this.name) && StringUtils.isEmpty(this.namespace);
|
||||
}
|
||||
|
||||
public NormalizedSource normalize(String defaultName, String defaultNamespace) {
|
||||
@@ -132,23 +142,28 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
return new NormalizedSource(normalizedName, normalizedNamespace);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class NormalizedSource {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String namespace;
|
||||
|
||||
public NormalizedSource(String name, String namespace) {
|
||||
NormalizedSource(String name, String namespace) {
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,32 +12,41 @@
|
||||
* 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 org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
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.core.env.MapPropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
/**
|
||||
* A {@link MapPropertySource} that uses Kubernetes config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class ConfigMapPropertySource extends MapPropertySource {
|
||||
|
||||
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 PREFIX = "configmap";
|
||||
@@ -47,7 +56,7 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
}
|
||||
|
||||
public ConfigMapPropertySource(KubernetesClient client, String name, String namespace,
|
||||
String[] profiles) {
|
||||
String[] profiles) {
|
||||
super(getName(client, name, namespace),
|
||||
asObjectMap(getData(client, name, namespace, profiles)));
|
||||
}
|
||||
@@ -63,11 +72,11 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
}
|
||||
|
||||
private static Map<String, String> getData(KubernetesClient client, String name,
|
||||
String namespace, String[] profiles) {
|
||||
String namespace, String[] profiles) {
|
||||
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) {
|
||||
return processAllEntries(map.getData(), profiles);
|
||||
@@ -75,7 +84,7 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Can't read configMap with name: [" + name + "] in namespace:["
|
||||
+ namespace + "]. Ignoring");
|
||||
+ namespace + "]. Ignoring");
|
||||
}
|
||||
|
||||
return new HashMap<>();
|
||||
@@ -97,8 +106,7 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
+ "] will be treated as a yaml file");
|
||||
}
|
||||
|
||||
return yamlParserGenerator(profiles).andThen(
|
||||
PROPERTIES_TO_MAP)
|
||||
return yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP)
|
||||
.apply(propertyValue);
|
||||
}
|
||||
else if (propertyName.endsWith(".properties")) {
|
||||
@@ -107,8 +115,7 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
+ "] will be treated as a properties file");
|
||||
}
|
||||
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(
|
||||
PROPERTIES_TO_MAP)
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP)
|
||||
.apply(propertyValue);
|
||||
}
|
||||
else {
|
||||
@@ -124,24 +131,27 @@ public class ConfigMapPropertySource extends MapPropertySource {
|
||||
|
||||
return input.entrySet().stream()
|
||||
.map(e -> extractProperties(e.getKey(), e.getValue(), profiles))
|
||||
.filter(m -> !m.isEmpty())
|
||||
.flatMap(m -> m.entrySet().stream())
|
||||
.filter(m -> !m.isEmpty()).flatMap(m -> m.entrySet().stream())
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
|
||||
private static Map<String, String> extractProperties(String resourceName,
|
||||
String content, String[] profiles) {
|
||||
|
||||
if (resourceName.equals(APPLICATION_YAML) || resourceName.equals(APPLICATION_YML)) {
|
||||
return yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
if (resourceName.equals(APPLICATION_YAML)
|
||||
|| resourceName.equals(APPLICATION_YML)) {
|
||||
return yamlParserGenerator(profiles).andThen(PROPERTIES_TO_MAP)
|
||||
.apply(content);
|
||||
}
|
||||
else if (resourceName.equals(APPLICATION_PROPERTIES)) {
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
|
||||
return new HashMap<String, String>() {{
|
||||
put(resourceName, content);
|
||||
}};
|
||||
return new HashMap<String, String>() {
|
||||
{
|
||||
put(resourceName, content);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Map<String, Object> asObjectMap(Map<String, String> source) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,27 +12,22 @@
|
||||
* 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 org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
import io.fabric8.kubernetes.api.builder.Function;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.builder.Function;
|
||||
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.cloud.kubernetes.config.ConfigMapConfigProperties.NormalizedSource;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -42,12 +37,25 @@ 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;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
/**
|
||||
* A {@link PropertySourceLocator} that uses config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@Order(0)
|
||||
public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySourceLocator.class);
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(ConfigMapPropertySourceLocator.class);
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
private final ConfigMapConfigProperties properties;
|
||||
|
||||
public ConfigMapPropertySourceLocator(KubernetesClient client,
|
||||
@@ -61,11 +69,11 @@ public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
|
||||
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = properties
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = this.properties
|
||||
.determineSources();
|
||||
CompositePropertySource composite = new CompositePropertySource(
|
||||
"composite-configmap");
|
||||
if (properties.isEnableApi()) {
|
||||
if (this.properties.isEnableApi()) {
|
||||
sources.forEach(s -> composite.addFirstPropertySource(
|
||||
getMapPropertySourceForSingleConfigMap(env, s)));
|
||||
}
|
||||
@@ -80,71 +88,63 @@ public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
private MapPropertySource getMapPropertySourceForSingleConfigMap(
|
||||
ConfigurableEnvironment environment, NormalizedSource normalizedSource) {
|
||||
|
||||
String configurationTarget = properties.getConfigurationTarget();
|
||||
return new ConfigMapPropertySource(client,
|
||||
String configurationTarget = this.properties.getConfigurationTarget();
|
||||
return new ConfigMapPropertySource(this.client,
|
||||
getApplicationName(environment, normalizedSource.getName(),
|
||||
configurationTarget),
|
||||
getApplicationNamespace(client, normalizedSource.getNamespace(),
|
||||
getApplicationNamespace(this.client, normalizedSource.getNamespace(),
|
||||
configurationTarget),
|
||||
environment.getActiveProfiles());
|
||||
}
|
||||
|
||||
private void addPropertySourcesFromPaths(Environment environment,
|
||||
CompositePropertySource composite) {
|
||||
properties
|
||||
.getPaths()
|
||||
.stream()
|
||||
.map(Paths::get)
|
||||
.peek(p -> {
|
||||
if(!Files.exists(p)) {
|
||||
LOG.warn("Configured input path: " + p + " will be ignored because it does not exist on the file system");
|
||||
CompositePropertySource composite) {
|
||||
this.properties.getPaths().stream().map(Paths::get).peek(p -> {
|
||||
if (!Files.exists(p)) {
|
||||
LOG.warn("Configured input path: " + p
|
||||
+ " will be ignored because it does not exist on the file system");
|
||||
}
|
||||
}).filter(Files::exists).peek(p -> {
|
||||
if (!Files.isRegularFile(p)) {
|
||||
LOG.warn("Configured input path: " + p
|
||||
+ " will be ignored because it is not a regular file");
|
||||
}
|
||||
}).filter(Files::isRegularFile).forEach(p -> {
|
||||
try {
|
||||
String content = new String(Files.readAllBytes(p)).trim();
|
||||
String filename = p.getFileName().toString().toLowerCase();
|
||||
if (filename.endsWith(".properties")) {
|
||||
addPropertySourceIfNeeded(
|
||||
c -> PROPERTIES_TO_MAP
|
||||
.apply(KEY_VALUE_TO_PROPERTIES.apply(c)),
|
||||
content, filename, composite);
|
||||
}
|
||||
})
|
||||
.filter(Files::exists)
|
||||
.peek(p -> {
|
||||
if(!Files.isRegularFile(p)) {
|
||||
LOG.warn("Configured input path: " + p + " will be ignored because it is not a regular file");
|
||||
else if (filename.endsWith(".yml") || filename.endsWith(".yaml")) {
|
||||
addPropertySourceIfNeeded(c -> PROPERTIES_TO_MAP
|
||||
.apply(yamlParserGenerator(environment.getActiveProfiles())
|
||||
.apply(c)),
|
||||
content, filename, composite);
|
||||
}
|
||||
})
|
||||
.filter(Files::isRegularFile)
|
||||
.forEach(p -> {
|
||||
try {
|
||||
String content = new String(Files.readAllBytes(p)).trim();
|
||||
String filename = p.getFileName().toString().toLowerCase();
|
||||
if(filename.endsWith(".properties")) {
|
||||
addPropertySourceIfNeeded(
|
||||
c -> PROPERTIES_TO_MAP.apply(KEY_VALUE_TO_PROPERTIES.apply(c)),
|
||||
content,
|
||||
filename,
|
||||
composite
|
||||
);
|
||||
}
|
||||
else if(filename.endsWith(".yml") || filename.endsWith(".yaml")) {
|
||||
addPropertySourceIfNeeded(
|
||||
c -> PROPERTIES_TO_MAP.apply(
|
||||
yamlParserGenerator(environment.getActiveProfiles()).apply(c)
|
||||
),
|
||||
content,
|
||||
filename,
|
||||
composite
|
||||
);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Error reading input file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn("Error reading input file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addPropertySourceIfNeeded(Function<String, Map<String, String>> contentToMapFunction,
|
||||
String content, String name, CompositePropertySource composite) {
|
||||
private void addPropertySourceIfNeeded(
|
||||
Function<String, Map<String, String>> contentToMapFunction, String content,
|
||||
String name, CompositePropertySource composite) {
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.putAll(contentToMapFunction.apply(content));
|
||||
if(map.isEmpty()) {
|
||||
LOG.warn("Property source: " + name + "will be ignored because no properties could be found");
|
||||
if (map.isEmpty()) {
|
||||
LOG.warn("Property source: " + name
|
||||
+ "will be ignored because no properties could be found");
|
||||
}
|
||||
else {
|
||||
composite.addFirstPropertySource(new MapPropertySource(name, map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -27,10 +26,19 @@ import org.springframework.util.StringUtils;
|
||||
import static org.springframework.cloud.kubernetes.config.Constants.FALLBACK_APPLICATION_NAME;
|
||||
import static org.springframework.cloud.kubernetes.config.Constants.SPRING_APPLICATION_NAME;
|
||||
|
||||
public class ConfigUtils {
|
||||
/**
|
||||
* Utility class that works with configuration properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public final class ConfigUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ConfigUtils.class);
|
||||
|
||||
private ConfigUtils() {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
public static <C extends AbstractConfigProperties> String getApplicationName(
|
||||
Environment env, String configName, String configurationTarget) {
|
||||
String name = configName;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,15 +12,17 @@
|
||||
* 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;
|
||||
|
||||
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 = ".";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,15 +12,10 @@
|
||||
* 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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -28,10 +23,18 @@ import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
/**
|
||||
* Secrets and ConfigMaps shared features.
|
||||
*
|
||||
* @author Stefan Larsson
|
||||
*/
|
||||
public class KubernetesPropertySource extends MapPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesPropertySource.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -39,31 +42,30 @@ public class KubernetesPropertySource extends MapPropertySource {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected static void putPathConfig(Map<String, ? super String> result, List<String> paths) {
|
||||
paths
|
||||
.stream()
|
||||
.map(Paths::get)
|
||||
.filter(Files::exists)
|
||||
.forEach(p -> putAll(p, result));
|
||||
protected static void putPathConfig(Map<String, ? super String> result,
|
||||
List<String> paths) {
|
||||
paths.stream().map(Paths::get).filter(Files::exists)
|
||||
.forEach(p -> putAll(p, result));
|
||||
}
|
||||
|
||||
private static void putAll(Path path, Map<String, ? super String> result) {
|
||||
try {
|
||||
Files.walk(path)
|
||||
.filter(Files::isRegularFile)
|
||||
.forEach(p -> readFile(p, result));
|
||||
} catch (IOException e) {
|
||||
Files.walk(path).filter(Files::isRegularFile)
|
||||
.forEach(p -> readFile(p, result));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn("Error walking properties files", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readFile(Path path, Map<String, ? super String> result) {
|
||||
try {
|
||||
result.put(
|
||||
path.getFileName().toString(),
|
||||
new String(Files.readAllBytes(path)).trim());
|
||||
} catch (IOException e) {
|
||||
result.put(path.getFileName().toString(),
|
||||
new String(Files.readAllBytes(path)).trim());
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn("Error reading properties file", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
/*
|
||||
* Copyright 2013-2019 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -11,35 +22,41 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
public class PropertySourceUtils {
|
||||
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;
|
||||
|
||||
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();
|
||||
/**
|
||||
* Utility class to work with property sources.
|
||||
*
|
||||
* @author Georgios Andrianakis
|
||||
*/
|
||||
public final class PropertySourceUtils {
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
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())));
|
||||
|
||||
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 PropertySourceUtils() {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
static Function<String, Properties> yamlParserGenerator(
|
||||
final String[] profiles) {
|
||||
static Function<String, Properties> yamlParserGenerator(final String[] profiles) {
|
||||
return s -> {
|
||||
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
|
||||
yamlFactory.setDocumentMatchers(properties -> {
|
||||
@@ -55,4 +72,5 @@ public class PropertySourceUtils {
|
||||
return yamlFactory.getObject();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 java.util.HashMap;
|
||||
@@ -23,41 +23,49 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties for configuring Kubernetes secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.kubernetes.secrets")
|
||||
public class SecretsConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
private static final String TARGET = "Secret";
|
||||
|
||||
private boolean enableApi = false;
|
||||
|
||||
private Map<String, String> labels = new HashMap<>();
|
||||
|
||||
private List<String> paths = new LinkedList<>();
|
||||
|
||||
public boolean isEnableApi() {
|
||||
return enableApi;
|
||||
return this.enableApi;
|
||||
}
|
||||
|
||||
public void setEnableApi(boolean enableApi) {
|
||||
this.enableApi = enableApi;
|
||||
}
|
||||
|
||||
public Map<String, String> getLabels() {
|
||||
return this.labels;
|
||||
}
|
||||
|
||||
public void setLabels(Map<String, String> labels) {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public Map<String, String> getLabels() {
|
||||
return labels;
|
||||
public List<String> getPaths() {
|
||||
return this.paths;
|
||||
}
|
||||
|
||||
public void setPaths(List<String> paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
public List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigurationTarget() {
|
||||
return TARGET;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 java.util.Base64;
|
||||
@@ -31,33 +31,40 @@ import org.springframework.util.StringUtils;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
|
||||
|
||||
/**
|
||||
* Kubernetes property source for secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
*/
|
||||
public class SecretsPropertySource extends KubernetesPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SecretsPropertySource.class);
|
||||
|
||||
private static final String PREFIX = "secrets";
|
||||
|
||||
public SecretsPropertySource(KubernetesClient client, Environment env,
|
||||
SecretsConfigProperties config) {
|
||||
SecretsConfigProperties config) {
|
||||
super(getSourceName(client, env, config), getSourceData(client, env, config));
|
||||
}
|
||||
|
||||
private static String getSourceName(KubernetesClient client, Environment env,
|
||||
SecretsConfigProperties config) {
|
||||
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();
|
||||
.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) {
|
||||
Environment env, SecretsConfigProperties config) {
|
||||
String name = getApplicationName(env, config.getName(),
|
||||
config.getConfigurationTarget());
|
||||
config.getConfigurationTarget());
|
||||
String namespace = getApplicationNamespace(client, config.getNamespace(),
|
||||
config.getConfigurationTarget());
|
||||
config.getConfigurationTarget());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (config.isEnableApi()) {
|
||||
@@ -76,20 +83,19 @@ public class SecretsPropertySource extends KubernetesPropertySource {
|
||||
if (!config.getLabels().isEmpty()) {
|
||||
if (StringUtils.isEmpty(namespace)) {
|
||||
client.secrets().withLabels(config.getLabels()).list().getItems()
|
||||
.forEach(s -> putAll(s, result));
|
||||
.forEach(s -> putAll(s, result));
|
||||
}
|
||||
else {
|
||||
client.secrets().inNamespace(namespace)
|
||||
.withLabels(config.getLabels()).list().getItems()
|
||||
.forEach(s -> putAll(s, result));
|
||||
.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");
|
||||
LOG.warn("Can't read secret with name: [" + name + "] or labels ["
|
||||
+ config.getLabels() + "] in namespace:[" + namespace
|
||||
+ "] (cause: " + e.getMessage() + "). Ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,17 +105,19 @@ public class SecretsPropertySource extends KubernetesPropertySource {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
||||
}
|
||||
|
||||
// *****************************
|
||||
// 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()));
|
||||
secret.getData().forEach((k, v) -> result.put(k,
|
||||
new String(Base64.getDecoder().decode(v)).trim()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -25,9 +24,16 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
/**
|
||||
* Kubernetes {@link PropertySourceLocator} for secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
*/
|
||||
@Order(1)
|
||||
public class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
private final SecretsConfigProperties properties;
|
||||
|
||||
public SecretsPropertySourceLocator(KubernetesClient client,
|
||||
@@ -39,6 +45,8 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
@Override
|
||||
public MapPropertySource locate(Environment environment) {
|
||||
return environment instanceof ConfigurableEnvironment
|
||||
? new SecretsPropertySource(client, environment, properties) : null;
|
||||
? new SecretsPropertySource(this.client, environment, this.properties)
|
||||
: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
@@ -41,6 +41,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* Definition of beans needed for the automatic reload of configuration.
|
||||
*
|
||||
* @author Nicolla Ferraro
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@@ -54,7 +56,7 @@ public class ConfigReloadAutoConfiguration {
|
||||
/**
|
||||
* Configuration reload must be enabled explicitly.
|
||||
*/
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.reload.enabled")
|
||||
@ConditionalOnProperty("spring.cloud.kubernetes.reload.enabled")
|
||||
@ConditionalOnClass({ RestartEndpoint.class, ContextRefresher.class })
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
@@ -73,7 +75,9 @@ public class ConfigReloadAutoConfiguration {
|
||||
private SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
|
||||
/**
|
||||
* Provides a bean that listen to configuration changes and fire a reload.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@@ -81,20 +85,26 @@ public class ConfigReloadAutoConfiguration {
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy) {
|
||||
switch (properties.getMode()) {
|
||||
case POLLING:
|
||||
return new PollingConfigurationChangeDetector(environment, properties,
|
||||
kubernetesClient, strategy, configMapPropertySourceLocator,
|
||||
secretsPropertySourceLocator);
|
||||
return new PollingConfigurationChangeDetector(this.environment,
|
||||
properties, this.kubernetesClient, strategy,
|
||||
this.configMapPropertySourceLocator,
|
||||
this.secretsPropertySourceLocator);
|
||||
case EVENT:
|
||||
return new EventBasedConfigurationChangeDetector(environment, properties,
|
||||
kubernetesClient, strategy, configMapPropertySourceLocator,
|
||||
secretsPropertySourceLocator);
|
||||
return new EventBasedConfigurationChangeDetector(this.environment,
|
||||
properties, this.kubernetesClient, strategy,
|
||||
this.configMapPropertySourceLocator,
|
||||
this.secretsPropertySourceLocator);
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Unsupported configuration reload mode: " + properties.getMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the action to execute when the configuration changes.
|
||||
* @param properties config reload properties
|
||||
* @param ctx application context
|
||||
* @param restarter restart endpoint
|
||||
* @param refresher context refresher
|
||||
* @return provides the action to execute when the configuration changes.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import java.time.Duration;
|
||||
@@ -22,6 +22,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* General configuration for the configuration reload.
|
||||
*
|
||||
* @author Nicola Ferraro
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.cloud.kubernetes.reload")
|
||||
public class ConfigReloadProperties {
|
||||
@@ -60,7 +62,7 @@ public class ConfigReloadProperties {
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
@@ -68,7 +70,7 @@ public class ConfigReloadProperties {
|
||||
}
|
||||
|
||||
public boolean isMonitoringConfigMaps() {
|
||||
return monitoringConfigMaps;
|
||||
return this.monitoringConfigMaps;
|
||||
}
|
||||
|
||||
public void setMonitoringConfigMaps(boolean monitoringConfigMaps) {
|
||||
@@ -76,7 +78,7 @@ public class ConfigReloadProperties {
|
||||
}
|
||||
|
||||
public boolean isMonitoringSecrets() {
|
||||
return monitoringSecrets;
|
||||
return this.monitoringSecrets;
|
||||
}
|
||||
|
||||
public void setMonitoringSecrets(boolean monitoringSecrets) {
|
||||
@@ -84,7 +86,7 @@ public class ConfigReloadProperties {
|
||||
}
|
||||
|
||||
public ReloadStrategy getStrategy() {
|
||||
return strategy;
|
||||
return this.strategy;
|
||||
}
|
||||
|
||||
public void setStrategy(ReloadStrategy strategy) {
|
||||
@@ -92,22 +94,26 @@ public class ConfigReloadProperties {
|
||||
}
|
||||
|
||||
public ReloadDetectionMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setPeriod(Duration period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public Duration getPeriod() {
|
||||
return period;
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void setMode(ReloadDetectionMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Duration getPeriod() {
|
||||
return this.period;
|
||||
}
|
||||
|
||||
public void setPeriod(Duration period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload strategies.
|
||||
*/
|
||||
public enum ReloadStrategy {
|
||||
|
||||
/**
|
||||
* Fire a refresh of beans annotated with @ConfigurationProperties
|
||||
* or @RefreshScope.
|
||||
@@ -126,9 +132,14 @@ public class ConfigReloadProperties {
|
||||
* configured to restart the pod.
|
||||
*/
|
||||
SHUTDOWN
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload detection modes.
|
||||
*/
|
||||
public enum ReloadDetectionMode {
|
||||
|
||||
/**
|
||||
* Enables a polling task that retrieves periodically all external properties and
|
||||
* fire a reload when they change.
|
||||
@@ -140,6 +151,7 @@ public class ConfigReloadProperties {
|
||||
* or secrets change.
|
||||
*/
|
||||
EVENT
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -38,6 +38,8 @@ 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.
|
||||
*
|
||||
* @author Nicola Ferraro
|
||||
*/
|
||||
public abstract class ConfigurationChangeDetector {
|
||||
|
||||
@@ -64,22 +66,27 @@ public abstract class ConfigurationChangeDetector {
|
||||
public void shutdown() {
|
||||
// Ensure the kubernetes client is cleaned up from spare threads when shutting
|
||||
// down
|
||||
kubernetesClient.close();
|
||||
this.kubernetesClient.close();
|
||||
}
|
||||
|
||||
public void reloadProperties() {
|
||||
log.info("Reloading using strategy: " + strategy.getName());
|
||||
strategy.reload();
|
||||
this.log.info("Reloading using strategy: " + this.strategy.getName());
|
||||
this.strategy.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two property sources are different.
|
||||
* @param mp1 map property sources 1
|
||||
* @param mp2 map property sources 2
|
||||
* @return {@code true} if source has changed
|
||||
*/
|
||||
protected boolean changed(MapPropertySource mp1, MapPropertySource mp2) {
|
||||
if (mp1 == mp2)
|
||||
if (mp1 == mp2) {
|
||||
return false;
|
||||
if (mp1 == null && mp2 != null || mp1 != null && mp2 == null)
|
||||
}
|
||||
if (mp1 == null && mp2 != null || mp1 != null && mp2 == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, Object> s1 = mp1.getSource();
|
||||
Map<String, Object> s2 = mp2.getSource();
|
||||
@@ -91,8 +98,9 @@ public abstract class ConfigurationChangeDetector {
|
||||
List<? extends MapPropertySource> l2) {
|
||||
|
||||
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");
|
||||
this.log.debug(
|
||||
"The current number of Confimap PropertySources does not match "
|
||||
+ "the ones loaded from the Kubernetes - No reload will take place");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,6 +115,9 @@ public abstract class ConfigurationChangeDetector {
|
||||
/**
|
||||
* Finds one registered property source of the given type, logging a warning if
|
||||
* multiple property sources of that type are available.
|
||||
* @param <S> property source type
|
||||
* @param sourceClass class for which property sources will be searched for
|
||||
* @return matched property source
|
||||
*/
|
||||
protected <S extends PropertySource<?>> S findPropertySource(Class<S> sourceClass) {
|
||||
List<S> sources = findPropertySources(sourceClass);
|
||||
@@ -114,20 +125,22 @@ public abstract class ConfigurationChangeDetector {
|
||||
return null;
|
||||
}
|
||||
if (sources.size() > 1) {
|
||||
log.warn("Found more than one property source of type " + sourceClass);
|
||||
this.log.warn("Found more than one property source of type " + sourceClass);
|
||||
}
|
||||
return sources.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all registered property sources of the given type.
|
||||
* @param <S> property source type
|
||||
* @param sourceClass class for which property sources will be found
|
||||
* @return 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());
|
||||
this.environment.getPropertySources());
|
||||
while (!sources.isEmpty()) {
|
||||
PropertySource<?> source = sources.pop();
|
||||
if (source instanceof CompositePropertySource) {
|
||||
@@ -152,7 +165,11 @@ public abstract class ConfigurationChangeDetector {
|
||||
|
||||
/**
|
||||
* Returns a list of MapPropertySource that correspond to the current state of the
|
||||
* system This only handles the PropertySource objects that are returned
|
||||
* system. This only handles the PropertySource objects that are returned.
|
||||
* @param propertySourceLocator Spring's property source locator
|
||||
* @param environment Spring environment
|
||||
* @return a list of MapPropertySource that correspond to the current state of the
|
||||
* system
|
||||
*/
|
||||
protected List<MapPropertySource> locateMapPropertySources(
|
||||
PropertySourceLocator propertySourceLocator, Environment environment) {
|
||||
@@ -168,7 +185,7 @@ public abstract class ConfigurationChangeDetector {
|
||||
.map(p -> (MapPropertySource) p).collect(Collectors.toList()));
|
||||
}
|
||||
else {
|
||||
log.debug("Found property source that cannot be handled: "
|
||||
this.log.debug("Found property source that cannot be handled: "
|
||||
+ propertySource.getClass());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -21,6 +21,8 @@ import java.util.Objects;
|
||||
/**
|
||||
* This is the superclass of all named strategies that can be fired when the configuration
|
||||
* changes.
|
||||
*
|
||||
* @author Nicola Ferraro
|
||||
*/
|
||||
public class ConfigurationUpdateStrategy {
|
||||
|
||||
@@ -36,7 +38,7 @@ public class ConfigurationUpdateStrategy {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
@@ -46,8 +48,9 @@ public class ConfigurationUpdateStrategy {
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("ConfigurationUpdateStrategy{");
|
||||
sb.append("name='").append(name).append('\'');
|
||||
sb.append("name='").append(this.name).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -39,6 +39,8 @@ import org.springframework.core.env.MapPropertySource;
|
||||
/**
|
||||
* A change detector that subscribes to changes in secrets and configmaps and fire a
|
||||
* reload when something changes.
|
||||
*
|
||||
* @author Nicola Ferraro
|
||||
*/
|
||||
public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
@@ -64,11 +66,11 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
|
||||
public void watch() {
|
||||
boolean activated = false;
|
||||
|
||||
if (properties.isMonitoringConfigMaps()) {
|
||||
if (this.properties.isMonitoringConfigMaps()) {
|
||||
try {
|
||||
String name = "config-maps-watch";
|
||||
watches.put(name,
|
||||
kubernetesClient.configMaps().watch(new Watcher<ConfigMap>() {
|
||||
this.watches.put(name, this.kubernetesClient.configMaps()
|
||||
.watch(new Watcher<ConfigMap>() {
|
||||
@Override
|
||||
public void eventReceived(Action action,
|
||||
ConfigMap configMap) {
|
||||
@@ -80,41 +82,43 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
|
||||
}
|
||||
}));
|
||||
activated = true;
|
||||
log.info("Added new Kubernetes watch: " + name);
|
||||
this.log.info("Added new Kubernetes watch: " + name);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(
|
||||
this.log.error(
|
||||
"Error while establishing a connection to watch config maps: configuration may remain stale",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.isMonitoringSecrets()) {
|
||||
if (this.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);
|
||||
}
|
||||
this.watches.put(name,
|
||||
this.kubernetesClient.secrets().watch(new Watcher<Secret>() {
|
||||
@Override
|
||||
public void eventReceived(Action action, Secret secret) {
|
||||
onEvent(secret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(KubernetesClientException e) {
|
||||
}
|
||||
}));
|
||||
@Override
|
||||
public void onClose(KubernetesClientException e) {
|
||||
}
|
||||
}));
|
||||
activated = true;
|
||||
log.info("Added new Kubernetes watch: " + name);
|
||||
this.log.info("Added new Kubernetes watch: " + name);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(
|
||||
this.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");
|
||||
this.log.info(
|
||||
"Kubernetes event-based configuration change detector activated");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +127,12 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
|
||||
if (this.watches != null) {
|
||||
for (Map.Entry<String, Watch> entry : this.watches.entrySet()) {
|
||||
try {
|
||||
log.debug("Closing the watch " + entry.getKey());
|
||||
this.log.debug("Closing the watch " + entry.getKey());
|
||||
entry.getValue().close();
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Error while closing the watch connection", e);
|
||||
this.log.error("Error while closing the watch connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,10 +140,11 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
|
||||
|
||||
private void onEvent(ConfigMap configMap) {
|
||||
boolean changed = changed(
|
||||
locateMapPropertySources(configMapPropertySourceLocator, environment),
|
||||
locateMapPropertySources(this.configMapPropertySourceLocator,
|
||||
this.environment),
|
||||
findPropertySources(ConfigMapPropertySource.class));
|
||||
if (changed) {
|
||||
log.info("Detected change in config maps");
|
||||
this.log.info("Detected change in config maps");
|
||||
reloadProperties();
|
||||
}
|
||||
}
|
||||
@@ -148,10 +153,10 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
|
||||
MapPropertySource currentSecretSource = findPropertySource(
|
||||
SecretsPropertySource.class);
|
||||
if (currentSecretSource != null) {
|
||||
MapPropertySource newSecretSource = secretsPropertySourceLocator
|
||||
.locate(environment);
|
||||
MapPropertySource newSecretSource = this.secretsPropertySourceLocator
|
||||
.locate(this.environment);
|
||||
if (changed(currentSecretSource, newSecretSource)) {
|
||||
log.info("Detected change in secrets");
|
||||
this.log.info("Detected change in secrets");
|
||||
reloadProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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.reload;
|
||||
|
||||
import java.util.List;
|
||||
@@ -35,6 +35,8 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
/**
|
||||
* A change detector that periodically retrieves secrets and configmaps and fire a reload
|
||||
* when something changes.
|
||||
*
|
||||
* @author Nicola Ferraro
|
||||
*/
|
||||
public class PollingConfigurationChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
@@ -57,32 +59,32 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
log.info("Kubernetes polling configuration change detector activated");
|
||||
this.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() {
|
||||
|
||||
boolean changedConfigMap = false;
|
||||
if (properties.isMonitoringConfigMaps()) {
|
||||
if (this.properties.isMonitoringConfigMaps()) {
|
||||
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(
|
||||
ConfigMapPropertySource.class);
|
||||
|
||||
if (!currentConfigMapSources.isEmpty()) {
|
||||
changedConfigMap = changed(
|
||||
locateMapPropertySources(configMapPropertySourceLocator,
|
||||
environment),
|
||||
locateMapPropertySources(this.configMapPropertySourceLocator,
|
||||
this.environment),
|
||||
currentConfigMapSources);
|
||||
}
|
||||
}
|
||||
|
||||
boolean changedSecrets = false;
|
||||
if (properties.isMonitoringSecrets()) {
|
||||
if (this.properties.isMonitoringSecrets()) {
|
||||
MapPropertySource currentSecretSource = findPropertySource(
|
||||
SecretsPropertySource.class);
|
||||
if (currentSecretSource != null) {
|
||||
MapPropertySource newSecretSource = secretsPropertySourceLocator
|
||||
.locate(environment);
|
||||
MapPropertySource newSecretSource = this.secretsPropertySourceLocator
|
||||
.locate(this.environment);
|
||||
changedSecrets = changed(currentSecretSource, newSecretSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
{"properties": [
|
||||
{
|
||||
"name": "spring.cloud.kubernetes.config.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enable the ConfigMap property source locator.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.cloud.kubernetes.secrets.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enable the Secrets property source locator.",
|
||||
"defaultValue": true
|
||||
}
|
||||
]}
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.cloud.kubernetes.config.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enable the ConfigMap property source locator.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.cloud.kubernetes.secrets.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enable the Secrets property source locator.",
|
||||
"defaultValue": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.config.reload.ConfigReloadAutoConfiguration
|
||||
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.config.BootstrapConfiguration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,27 +12,27 @@
|
||||
* 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.api.model.SecretBuilder
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.fabric8.kubernetes.api.model.ConfigMapBuilder
|
||||
import io.fabric8.kubernetes.api.model.SecretBuilder
|
||||
import io.fabric8.kubernetes.client.Config
|
||||
import io.fabric8.kubernetes.client.KubernetesClient
|
||||
import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.core.env.Environment
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import spock.lang.Specification
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
@Slf4j
|
||||
@ContextConfiguration(classes=[TestApplication.class])
|
||||
@SpringBootTest(properties=[
|
||||
@ContextConfiguration(classes = [TestApplication.class])
|
||||
@SpringBootTest(properties = [
|
||||
"spring.application.name=testapp",
|
||||
"spring.cloud.kubernetes.client.namespace=testns",
|
||||
"spring.cloud.kubernetes.client.trustCerts=true",
|
||||
@@ -42,84 +42,87 @@ import groovy.util.logging.Slf4j
|
||||
@EnableConfigurationProperties
|
||||
class CoreTest extends Specification {
|
||||
|
||||
private static KubernetesMockServer mockServer = new KubernetesMockServer()
|
||||
private static KubernetesClient mockClient
|
||||
private static KubernetesMockServer mockServer = new KubernetesMockServer()
|
||||
private static KubernetesClient mockClient
|
||||
|
||||
@Autowired
|
||||
Environment environment
|
||||
@Autowired
|
||||
Environment environment
|
||||
|
||||
@Autowired(required = false)
|
||||
Config config
|
||||
@Autowired(required = false)
|
||||
Config config
|
||||
|
||||
@Autowired(required = false)
|
||||
KubernetesClient client
|
||||
@Autowired(required = false)
|
||||
KubernetesClient client
|
||||
|
||||
def setupSpec() {
|
||||
mockServer.init()
|
||||
mockClient = mockServer.createClient()
|
||||
def setupSpec() {
|
||||
mockServer.init()
|
||||
mockClient = mockServer.createClient()
|
||||
|
||||
mockServer.expect().get()
|
||||
.withPath("/api/v1/namespaces/testns/configmaps/testapp")
|
||||
.andReturn(
|
||||
200,
|
||||
new ConfigMapBuilder()
|
||||
.withData([
|
||||
'spring.kubernetes.test.value': 'value1'])
|
||||
.build())
|
||||
.always()
|
||||
mockServer.expect().get()
|
||||
.withPath("/api/v1/namespaces/testns/secrets/testapp")
|
||||
.andReturn(
|
||||
200,
|
||||
new SecretBuilder()
|
||||
.withData([
|
||||
'amq.pwd': 'MWYyZDFlMmU2N2Rm',
|
||||
'amq.usr': 'YWRtaW4K'
|
||||
])
|
||||
.build())
|
||||
.always()
|
||||
mockServer.expect().get()
|
||||
.withPath("/api/v1/namespaces/testns/configmaps/testapp")
|
||||
.andReturn(
|
||||
200,
|
||||
new ConfigMapBuilder()
|
||||
.withData([
|
||||
'spring.kubernetes.test.value': 'value1'])
|
||||
.build())
|
||||
.always()
|
||||
mockServer.expect().get()
|
||||
.withPath("/api/v1/namespaces/testns/secrets/testapp")
|
||||
.andReturn(
|
||||
200,
|
||||
new SecretBuilder()
|
||||
.withData([
|
||||
'amq.pwd': 'MWYyZDFlMmU2N2Rm',
|
||||
'amq.usr': 'YWRtaW4K'
|
||||
])
|
||||
.build())
|
||||
.always()
|
||||
|
||||
//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")
|
||||
}
|
||||
//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")
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
mockServer.destroy();
|
||||
}
|
||||
def cleanupSpec() {
|
||||
mockServer.destroy();
|
||||
}
|
||||
|
||||
def "Kubernetes client config bean should be present"() {
|
||||
expect:
|
||||
config != null
|
||||
}
|
||||
def "Kubernetes client config bean should be present"() {
|
||||
expect:
|
||||
config != null
|
||||
}
|
||||
|
||||
def "Kubernetes client config bean should be configurable via system properties"() {
|
||||
expect:
|
||||
config.getMasterUrl().equals(mockClient.getConfiguration().getMasterUrl())
|
||||
config.getNamespace().equals("testns")
|
||||
config.trustCerts
|
||||
}
|
||||
def "Kubernetes client config bean should be configurable via system properties"() {
|
||||
expect:
|
||||
config.getMasterUrl().equals(mockClient.getConfiguration().getMasterUrl())
|
||||
config.getNamespace().equals("testns")
|
||||
config.trustCerts
|
||||
}
|
||||
|
||||
def "Kubernetes client bean should be present"() {
|
||||
expect:
|
||||
client != null
|
||||
}
|
||||
def "Kubernetes client bean should be present"() {
|
||||
expect:
|
||||
client != null
|
||||
}
|
||||
|
||||
def "Kubernetes client should be configured from system properties"() {
|
||||
expect:
|
||||
client.getConfiguration().getMasterUrl().equals(mockClient.getConfiguration().getMasterUrl())
|
||||
}
|
||||
def "Kubernetes client should be configured from system properties"() {
|
||||
expect:
|
||||
client.getConfiguration().getMasterUrl().
|
||||
equals(mockClient.getConfiguration().getMasterUrl())
|
||||
}
|
||||
|
||||
def "properties should be read from config map"() {
|
||||
expect:
|
||||
environment.getProperty("spring.kubernetes.test.value").equals("value1")
|
||||
}
|
||||
def "properties should be read from config map"() {
|
||||
expect:
|
||||
environment.getProperty("spring.kubernetes.test.value").equals("value1")
|
||||
}
|
||||
|
||||
def "properties should be read from secrets"() {
|
||||
expect:
|
||||
environment.getProperty("amq.pwd").equals("1f2d1e2e67df")
|
||||
environment.getProperty("amq.usr").equals('admin');
|
||||
}
|
||||
def "properties should be read from secrets"() {
|
||||
expect:
|
||||
environment.getProperty("amq.pwd").equals("1f2d1e2e67df")
|
||||
environment.getProperty("amq.usr").equals('admin');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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
|
||||
@@ -23,7 +22,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
@SpringBootApplication
|
||||
class TestApplication {
|
||||
|
||||
def main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
def main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,28 +12,27 @@
|
||||
* 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;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import io.fabric8.kubernetes.client.utils.IOHelpers;
|
||||
|
||||
final class ConfigMapTestUtil {
|
||||
|
||||
private ConfigMapTestUtil() {
|
||||
}
|
||||
|
||||
|
||||
static String readResourceFile(String file) {
|
||||
String resource;
|
||||
try {
|
||||
resource = IOHelpers.readFully(
|
||||
ConfigMapTestUtil.class.getClassLoader().getResourceAsStream(file));
|
||||
ConfigMapTestUtil.class.getClassLoader().getResourceAsStream(file));
|
||||
}
|
||||
catch (IOException e) {
|
||||
resource = "";
|
||||
@@ -44,4 +43,5 @@ final class ConfigMapTestUtil {
|
||||
static void createFileWithContent(String file, String content) throws IOException {
|
||||
Files.write(Paths.get(file), content.getBytes(), StandardOpenOption.CREATE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,56 +12,65 @@
|
||||
* 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 org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.createFileWithContent;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.AfterClass;
|
||||
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.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.createFileWithContent;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class , properties = {
|
||||
"spring.application.name=configmap-path-example",
|
||||
"spring.cloud.kubernetes.config.enableApi=false",
|
||||
"spring.cloud.kubernetes.config.paths="
|
||||
+ ConfigMapsFromFilePathsSpringBootTest.FIRST_FILE_NAME_FULL_PATH + ","
|
||||
+ ConfigMapsFromFilePathsSpringBootTest.SECOND_FILE_NAME_FULL_PATH
|
||||
})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"spring.application.name=configmap-path-example",
|
||||
"spring.cloud.kubernetes.config.enableApi=false",
|
||||
"spring.cloud.kubernetes.config.paths="
|
||||
+ ConfigMapsFromFilePathsSpringBootTest.FIRST_FILE_NAME_FULL_PATH + ","
|
||||
+ ConfigMapsFromFilePathsSpringBootTest.SECOND_FILE_NAME_FULL_PATH })
|
||||
public class ConfigMapsFromFilePathsSpringBootTest {
|
||||
|
||||
protected static final String FILES_ROOT_PATH = "/tmp/scktests";
|
||||
|
||||
protected static final String FIRST_FILE_NAME = "application.properties";
|
||||
|
||||
protected static final String SECOND_FILE_NAME = "extra.properties";
|
||||
|
||||
protected static final String UNUSED_FILE_NAME = "unused.properties";
|
||||
protected static final String FIRST_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/" + FIRST_FILE_NAME;
|
||||
protected static final String SECOND_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/" + SECOND_FILE_NAME;
|
||||
protected static final String UNUSED_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/" + UNUSED_FILE_NAME;
|
||||
|
||||
protected static final String FIRST_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/"
|
||||
+ FIRST_FILE_NAME;
|
||||
|
||||
protected static final String SECOND_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/"
|
||||
+ SECOND_FILE_NAME;
|
||||
|
||||
protected static final String UNUSED_FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/"
|
||||
+ UNUSED_FILE_NAME;
|
||||
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer();
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws IOException {
|
||||
@@ -77,41 +86,41 @@ public class ConfigMapsFromFilePathsSpringBootTest {
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
|
||||
Files.createDirectories(Paths.get(FILES_ROOT_PATH));
|
||||
createFileWithContent(FIRST_FILE_NAME_FULL_PATH, "bean.greeting=Hello from path!");
|
||||
createFileWithContent(FIRST_FILE_NAME_FULL_PATH,
|
||||
"bean.greeting=Hello from path!");
|
||||
createFileWithContent(SECOND_FILE_NAME_FULL_PATH, "bean.farewell=Bye from path!");
|
||||
createFileWithContent(UNUSED_FILE_NAME_FULL_PATH, "bean.morning=Morning from path!");
|
||||
createFileWithContent(UNUSED_FILE_NAME_FULL_PATH,
|
||||
"bean.morning=Morning from path!");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardownAfterClass() {
|
||||
newArrayList(
|
||||
FIRST_FILE_NAME_FULL_PATH,
|
||||
SECOND_FILE_NAME_FULL_PATH,
|
||||
SECOND_FILE_NAME_FULL_PATH,
|
||||
FILES_ROOT_PATH
|
||||
).forEach(fn -> {
|
||||
try {
|
||||
Files.delete(Paths.get(fn));
|
||||
} catch (IOException ignored) {}
|
||||
});
|
||||
newArrayList(FIRST_FILE_NAME_FULL_PATH, SECOND_FILE_NAME_FULL_PATH,
|
||||
SECOND_FILE_NAME_FULL_PATH, FILES_ROOT_PATH).forEach(fn -> {
|
||||
try {
|
||||
Files.delete(Paths.get(fn));
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void greetingInputShouldReturnPropertyFromFirstFile() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello from path!");
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello from path!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void farewellInputShouldReturnPropertyFromSecondFile() {
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Bye from path!");
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Bye from path!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void morningInputShouldReturnDefaultValue() {
|
||||
this.webClient.get().uri("/api/morning").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Good morning, World!");
|
||||
this.webClient.get().uri("/api/morning").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Good morning, World!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,44 +12,46 @@
|
||||
* 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 org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
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 java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import org.junit.AfterClass;
|
||||
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.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class , properties = {
|
||||
"spring.application.name=" + ConfigMapsMixedSpringBootTest.APPLICATION_NAME,
|
||||
"spring.cloud.kubernetes.config.enableApi=true",
|
||||
"spring.cloud.kubernetes.config.paths="
|
||||
+ ConfigMapsMixedSpringBootTest.FILE_NAME_FULL_PATH
|
||||
})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"spring.application.name=" + ConfigMapsMixedSpringBootTest.APPLICATION_NAME,
|
||||
"spring.cloud.kubernetes.config.enableApi=true",
|
||||
"spring.cloud.kubernetes.config.paths="
|
||||
+ ConfigMapsMixedSpringBootTest.FILE_NAME_FULL_PATH })
|
||||
public class ConfigMapsMixedSpringBootTest {
|
||||
|
||||
protected static final String FILES_ROOT_PATH = "/tmp/scktests";
|
||||
|
||||
protected static final String FILE_NAME = "application-path.yaml";
|
||||
|
||||
protected static final String FILE_NAME_FULL_PATH = FILES_ROOT_PATH + "/" + FILE_NAME;
|
||||
|
||||
protected static final String APPLICATION_NAME = "configmap-mixed-example";
|
||||
@@ -59,8 +61,8 @@ public class ConfigMapsMixedSpringBootTest {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws IOException {
|
||||
@@ -76,44 +78,47 @@ public class ConfigMapsMixedSpringBootTest {
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
|
||||
Files.createDirectories(Paths.get(FILES_ROOT_PATH));
|
||||
ConfigMapTestUtil.createFileWithContent(FILE_NAME_FULL_PATH, readResourceFile("application-path.yaml"));
|
||||
ConfigMapTestUtil.createFileWithContent(FILE_NAME_FULL_PATH,
|
||||
readResourceFile("application-path.yaml"));
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("bean.morning", "Buenos Dias 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();
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
|
||||
.withName(APPLICATION_NAME).endMetadata().addToData(data).build())
|
||||
.always();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardownAfterClass() {
|
||||
newArrayList(
|
||||
FILE_NAME_FULL_PATH,
|
||||
FILES_ROOT_PATH
|
||||
).forEach(fn -> {
|
||||
newArrayList(FILE_NAME_FULL_PATH, FILES_ROOT_PATH).forEach(fn -> {
|
||||
try {
|
||||
Files.delete(Paths.get(fn));
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void greetingInputShouldReturnPropertyFromFile() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap, World from path");
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Hello ConfigMap, World from path");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void farewellInputShouldReturnPropertyFromFile() {
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Bye ConfigMap, World from path");
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Bye ConfigMap, World from path");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void morningInputShouldReturnPropertyFromApi() {
|
||||
this.webClient.get().uri("/api/morning").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Buenos Dias ConfigMap, World");
|
||||
this.webClient.get().uri("/api/morning").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Buenos Dias ConfigMap, World");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,21 +12,22 @@
|
||||
* 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 java.util.HashMap;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
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 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.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -34,7 +35,7 @@ import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
@@ -46,6 +47,8 @@ import static org.junit.Assert.assertEquals;
|
||||
@AutoConfigureWebTestClient
|
||||
public class ConfigMapsSpringBootTest {
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-example";
|
||||
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer();
|
||||
|
||||
@@ -54,8 +57,6 @@ public class ConfigMapsSpringBootTest {
|
||||
@Autowired(required = false)
|
||||
private Config config;
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-example";
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@@ -82,8 +83,9 @@ public class ConfigMapsSpringBootTest {
|
||||
|
||||
@Test
|
||||
public void testConfig() {
|
||||
assertEquals(config.getMasterUrl(), mockClient.getConfiguration().getMasterUrl());
|
||||
assertEquals(config.getNamespace(), mockClient.getNamespace());
|
||||
assertThat(mockClient.getConfiguration().getMasterUrl())
|
||||
.isEqualTo(this.config.getMasterUrl());
|
||||
assertThat(mockClient.getNamespace()).isEqualTo(this.config.getNamespace());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -91,13 +93,13 @@ public class ConfigMapsSpringBootTest {
|
||||
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!");
|
||||
assertThat("Hello ConfigMap, %s!").isEqualTo(keys.get("bean.greeting"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreetingEndpoint() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap, World!");
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap, World!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,25 +12,23 @@
|
||||
* 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 org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
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 java.util.Map;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
*/
|
||||
@@ -41,40 +39,40 @@ public class ConfigMapsTest {
|
||||
|
||||
@Test
|
||||
public void testConfigMapList() {
|
||||
server.expect().withPath("/api/v1/namespaces/ns1/configmaps")
|
||||
this.server.expect().withPath("/api/v1/namespaces/ns1/configmaps")
|
||||
.andReturn(200, new ConfigMapListBuilder().build()).once();
|
||||
|
||||
KubernetesClient client = server.getClient();
|
||||
KubernetesClient client = this.server.getClient();
|
||||
|
||||
ConfigMapList configMapList = client.configMaps().inNamespace("ns1").list();
|
||||
assertNotNull(configMapList);
|
||||
assertEquals(0, configMapList.getItems().size());
|
||||
assertThat(configMapList).isNotNull();
|
||||
assertThat(configMapList.getItems().size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigMapGet() {
|
||||
server.expect().withPath("/api/v1/namespaces/ns2/configmaps")
|
||||
this.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();
|
||||
KubernetesClient client = this.server.getClient();
|
||||
ConfigMapList configMapList = client.configMaps().inNamespace("ns2").list();
|
||||
assertNotNull(configMapList);
|
||||
assertEquals(1, configMapList.getAdditionalProperties().size());
|
||||
assertThat(configMapList).isNotNull();
|
||||
assertThat(configMapList.getAdditionalProperties().size()).isEqualTo(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> data = (Map<String, String>) configMapList
|
||||
.getAdditionalProperties().get("data");
|
||||
assertEquals("123", data.get("KEY"));
|
||||
assertThat(data.get("KEY")).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigMapFromSingleApplicationProperties() {
|
||||
String configMapName = "app-properties-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
|
||||
@@ -85,18 +83,18 @@ public class ConfigMapsTest {
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
|
||||
server.getClient().inNamespace(namespace), configMapName);
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertEquals("a", cmps.getProperty("dummy.property.string1"));
|
||||
assertEquals("1", cmps.getProperty("dummy.property.int1"));
|
||||
assertEquals("true", cmps.getProperty("dummy.property.bool1"));
|
||||
assertThat(cmps.getProperty("dummy.property.string1")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int1")).isEqualTo("1");
|
||||
assertThat(cmps.getProperty("dummy.property.bool1")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigMapFromSingleApplicationYaml() {
|
||||
String configMapName = "app-yaml-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200,
|
||||
@@ -108,18 +106,18 @@ public class ConfigMapsTest {
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
|
||||
server.getClient().inNamespace(namespace), configMapName);
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertEquals("a", cmps.getProperty("dummy.property.string2"));
|
||||
assertEquals("1", cmps.getProperty("dummy.property.int2"));
|
||||
assertEquals("true", cmps.getProperty("dummy.property.bool2"));
|
||||
assertThat(cmps.getProperty("dummy.property.string2")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int2")).isEqualTo("1");
|
||||
assertThat(cmps.getProperty("dummy.property.bool2")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigMapFromSingleNonStandardFileName() {
|
||||
String configMapName = "single-non-standard-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
|
||||
@@ -128,18 +126,18 @@ public class ConfigMapsTest {
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
|
||||
server.getClient().inNamespace(namespace), configMapName);
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertEquals("a", cmps.getProperty("dummy.property.string3"));
|
||||
assertEquals("1", cmps.getProperty("dummy.property.int3"));
|
||||
assertEquals("true", cmps.getProperty("dummy.property.bool3"));
|
||||
assertThat(cmps.getProperty("dummy.property.string3")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int3")).isEqualTo("1");
|
||||
assertThat(cmps.getProperty("dummy.property.bool3")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigMapFromSingleInvalidPropertiesContent() {
|
||||
String configMapName = "single-unparseable-properties-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200,
|
||||
@@ -148,7 +146,7 @@ public class ConfigMapsTest {
|
||||
.addToData("application.properties", "somevalue").build())
|
||||
.once();
|
||||
|
||||
new ConfigMapPropertySource(server.getClient().inNamespace(namespace),
|
||||
new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
|
||||
// no exception is thrown for unparseable content
|
||||
@@ -158,7 +156,7 @@ public class ConfigMapsTest {
|
||||
public void testConfigMapFromSingleInvalidYamlContent() {
|
||||
String configMapName = "single-unparseable-yaml-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200,
|
||||
@@ -167,7 +165,7 @@ public class ConfigMapsTest {
|
||||
.build())
|
||||
.once();
|
||||
|
||||
new ConfigMapPropertySource(server.getClient().inNamespace(namespace),
|
||||
new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
|
||||
// no exception is thrown for unparseable content
|
||||
@@ -177,7 +175,7 @@ public class ConfigMapsTest {
|
||||
public void testConfigMapFromMultipleApplicationProperties() {
|
||||
String configMapName = "app-multiple-properties-test";
|
||||
String namespace = "app-props";
|
||||
server.expect()
|
||||
this.server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200,
|
||||
@@ -191,17 +189,17 @@ public class ConfigMapsTest {
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(
|
||||
server.getClient().inNamespace(namespace), configMapName);
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
// 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"));
|
||||
assertThat(cmps.getProperty("dummy.property.string1")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int1")).isEqualTo("1");
|
||||
assertThat(cmps.getProperty("dummy.property.bool1")).isEqualTo("true");
|
||||
|
||||
// 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"));
|
||||
assertThat(cmps.getProperty("dummy.property.bool2")).isNull();
|
||||
assertThat(cmps.getProperty("dummy.property.bool2")).isNull();
|
||||
assertThat(cmps.getProperty("dummy.property.bool2")).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,20 +12,21 @@
|
||||
* 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 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 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.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -45,13 +46,13 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read
|
||||
@AutoConfigureWebTestClient
|
||||
public class ConfigMapsWithProfilesNoActiveProfileSpringBootTest {
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-with-profile-no-active-profiles-example";
|
||||
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer();
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-with-profile-no-active-profiles-example";
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@@ -79,14 +80,15 @@ public class ConfigMapsWithProfilesNoActiveProfileSpringBootTest {
|
||||
@Test
|
||||
public void testGreetingEndpoint() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap default, World!");
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Hello ConfigMap default, World!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFarewellEndpoint() {
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Goodbye ConfigMap default, World!");
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Goodbye ConfigMap default, World!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,20 +12,21 @@
|
||||
* 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 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 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.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -47,6 +48,8 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read
|
||||
@AutoConfigureWebTestClient
|
||||
public class ConfigMapsWithProfilesSpringBootTest {
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-with-profile-example";
|
||||
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer();
|
||||
|
||||
@@ -55,8 +58,6 @@ public class ConfigMapsWithProfilesSpringBootTest {
|
||||
@Autowired(required = false)
|
||||
Config config;
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-with-profile-example";
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@@ -84,14 +85,15 @@ public class ConfigMapsWithProfilesSpringBootTest {
|
||||
@Test
|
||||
public void testGreetingEndpoint() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Hello ConfigMap dev, World!");
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Hello ConfigMap dev, World!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFarewellEndpoint() {
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Goodbye ConfigMap default, World!");
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Goodbye ConfigMap default, World!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,20 +12,21 @@
|
||||
* 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 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 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.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -37,22 +38,20 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = App.class,
|
||||
properties = { "spring.application.name=configmap-without-profile-example",
|
||||
"spring.cloud.kubernetes.reload.enabled=false"}
|
||||
)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"spring.application.name=configmap-without-profile-example",
|
||||
"spring.cloud.kubernetes.reload.enabled=false" })
|
||||
@ActiveProfiles("development")
|
||||
@AutoConfigureWebTestClient
|
||||
public class ConfigMapsWithoutProfilesSpringBootTest {
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-without-profile-example";
|
||||
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer();
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
private static final String APPLICATION_NAME = "configmap-without-profile-example";
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@@ -60,32 +59,34 @@ public class ConfigMapsWithoutProfilesSpringBootTest {
|
||||
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("application.yml", readResourceFile("application-without-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();
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("application.yml",
|
||||
readResourceFile("application-without-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();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreetingEndpoint() {
|
||||
this.webClient.get().uri("/api/greeting").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap, World!");
|
||||
.expectBody().jsonPath("content").isEqualTo("Hello ConfigMap, World!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFarewellEndpoint() {
|
||||
this.webClient.get().uri("/api/farewell").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("content")
|
||||
.isEqualTo("Goodbye ConfigMap, World!");
|
||||
.expectBody().jsonPath("content").isEqualTo("Goodbye ConfigMap, World!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.Config;
|
||||
@@ -19,10 +35,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = {
|
||||
"management.endpoint.health.show-details=always"
|
||||
})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"management.endpoint.health.show-details=always" })
|
||||
public class HealthIndicatorTest {
|
||||
|
||||
@ClassRule
|
||||
@@ -40,23 +54,21 @@ public class HealthIndicatorTest {
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthEndpointShouldContainKubernetes() {
|
||||
webClient.get()
|
||||
.uri("http://localhost:{port}/actuator/health", port)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).value(containsString("kubernetes"));
|
||||
this.webClient.get().uri("http://localhost:{port}/actuator/health", this.port)
|
||||
.accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(containsString("kubernetes"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -27,38 +43,36 @@ public class KubernetesConfigConfigurationTest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void kubernetesWhenKubernetesDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.enabled=false");
|
||||
assertFalse(context.containsBean("configMapPropertySourceLocator"));
|
||||
assertFalse(context.containsBean("secretsPropertySourceLocator"));
|
||||
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isFalse();
|
||||
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void kubernetesWhenKubernetesConfigDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.config.enabled=false",
|
||||
"spring.cloud.kubernetes.secrets.enabled=false");
|
||||
assertFalse(context.containsBean("configMapPropertySourceLocator"));
|
||||
assertFalse(context.containsBean("secretsPropertySourceLocator"));
|
||||
"spring.cloud.kubernetes.secrets.enabled=false");
|
||||
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isFalse();
|
||||
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void kubernetesDefaultEnabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.enabled=true");
|
||||
assertTrue(context.containsBean("configMapPropertySourceLocator"));
|
||||
assertTrue(context.containsBean("secretsPropertySourceLocator"));
|
||||
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isTrue();
|
||||
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isTrue();
|
||||
}
|
||||
|
||||
private void setup(String... env) {
|
||||
this.context = new SpringApplicationBuilder(
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class,
|
||||
BootstrapConfiguration.class).web(org.springframework.boot.WebApplicationType.NONE)
|
||||
.properties(env).run();
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class, BootstrapConfiguration.class)
|
||||
.web(org.springframework.boot.WebApplicationType.NONE)
|
||||
.properties(env).run();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class KubernetesClientTestConfiguration {
|
||||
|
||||
@@ -67,6 +81,6 @@ public class KubernetesConfigConfigurationTest {
|
||||
return mock(KubernetesClient.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
/*
|
||||
* Copyright 2013-2019 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.
|
||||
*/
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
@@ -14,28 +29,33 @@ import org.springframework.cloud.test.ModifiedClassPathRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
// inspired by spring-cloud-commons: RefreshAutoConfigurationMoreClassPathTests
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions({"spring-boot-actuator-autoconfigure-*.jar", "spring-boot-starter-actuator-*.jar"})
|
||||
@ClassPathExclusions({ "spring-boot-actuator-autoconfigure-*.jar",
|
||||
"spring-boot-starter-actuator-*.jar" })
|
||||
public class MissingActuatorTest {
|
||||
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@Test
|
||||
public void unknownClassProtected() {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(
|
||||
Config.class, "debug=true")) {
|
||||
String output = this.outputCapture.toString();
|
||||
assertThat(output).doesNotContain("Failed to introspect annotations on [class org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration")
|
||||
.doesNotContain("TypeNotPresentExceptionProxy");
|
||||
}
|
||||
private static ConfigurableApplicationContext getApplicationContext(
|
||||
Class<?> configuration, String... properties) {
|
||||
return new SpringApplicationBuilder(configuration).web(WebApplicationType.NONE)
|
||||
.properties(properties).run();
|
||||
}
|
||||
|
||||
private static ConfigurableApplicationContext getApplicationContext(
|
||||
Class<?> configuration, String... properties) {
|
||||
return new SpringApplicationBuilder(configuration).web(WebApplicationType.NONE).properties(properties).run();
|
||||
@Test
|
||||
public void unknownClassProtected() {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(Config.class,
|
||||
"debug=true")) {
|
||||
String output = this.outputCapture.toString();
|
||||
assertThat(output).doesNotContain("Failed to introspect annotations on"
|
||||
+ " [class org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration")
|
||||
.doesNotContain("TypeNotPresentExceptionProxy");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,21 +12,22 @@
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -38,8 +39,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
* @author Charles Moulliard
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ExampleApp.class,
|
||||
properties = {"spring.cloud.bootstrap.name=multiplecms"})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ExampleApp.class, properties = {
|
||||
"spring.cloud.bootstrap.name=multiplecms" })
|
||||
@AutoConfigureWebTestClient
|
||||
public class MultipleConfigMapsSpringBootTest {
|
||||
|
||||
@@ -55,59 +56,51 @@ public class MultipleConfigMapsSpringBootTest {
|
||||
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");
|
||||
|
||||
createConfigmap(
|
||||
server,
|
||||
"s1",
|
||||
"defnamespace",
|
||||
new HashMap<String, String>() {{
|
||||
put("bean.common-message","c1");
|
||||
createConfigmap(server, "s1", "defnamespace", new HashMap<String, String>() {
|
||||
{
|
||||
put("bean.common-message", "c1");
|
||||
put("bean.message1", "m1");
|
||||
}});
|
||||
}
|
||||
});
|
||||
|
||||
createConfigmap(
|
||||
server,
|
||||
"defname",
|
||||
"s2",
|
||||
new HashMap<String, String>() {{
|
||||
put("bean.common-message","c2");
|
||||
createConfigmap(server, "defname", "s2", new HashMap<String, String>() {
|
||||
{
|
||||
put("bean.common-message", "c2");
|
||||
put("bean.message2", "m2");
|
||||
}});
|
||||
}
|
||||
});
|
||||
|
||||
createConfigmap(
|
||||
server,
|
||||
"othername",
|
||||
"othernamespace",
|
||||
new HashMap<String, String>() {{
|
||||
put("bean.common-message","c3");
|
||||
put("bean.message3", "m3");
|
||||
}});
|
||||
createConfigmap(server, "othername", "othernamespace",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("bean.common-message", "c3");
|
||||
put("bean.message3", "m3");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void createConfigmap(KubernetesServer server, String configMapName,
|
||||
String namespace, Map<String, String> data) {
|
||||
String namespace, Map<String, String> data) {
|
||||
|
||||
server
|
||||
.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace, configMapName))
|
||||
.andReturn(
|
||||
200,
|
||||
new ConfigMapBuilder()
|
||||
.withNewMetadata().withName(configMapName).endMetadata()
|
||||
.addToData(data)
|
||||
.build()
|
||||
)
|
||||
.always();
|
||||
server.expect()
|
||||
.withPath(String.format("/api/v1/namespaces/%s/configmaps/%s", namespace,
|
||||
configMapName))
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata()
|
||||
.withName(configMapName).endMetadata().addToData(data).build())
|
||||
.always();
|
||||
}
|
||||
|
||||
//the last confimap defined in 'multiplecms.yml' has the highest priority, so
|
||||
//the common property defined in all configmaps is taken from the last one defined
|
||||
// the last confimap defined in 'multiplecms.yml' has the highest priority, so
|
||||
// the common property defined in all configmaps is taken from the last one defined
|
||||
@Test
|
||||
public void testCommonMessage() {
|
||||
assertResponse("/common", "c3");
|
||||
@@ -129,9 +122,8 @@ public class MultipleConfigMapsSpringBootTest {
|
||||
}
|
||||
|
||||
private void assertResponse(String path, String expectedMessage) {
|
||||
this.webClient.get().uri(path).exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath("message")
|
||||
.isEqualTo(expectedMessage);
|
||||
this.webClient.get().uri(path).exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("message").isEqualTo(expectedMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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 java.util.Base64;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Secret;
|
||||
import io.fabric8.kubernetes.api.model.SecretBuilder;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
@@ -9,6 +27,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.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
@@ -16,43 +35,53 @@ import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class) @TestPropertySource("classpath:/application-secrets.properties") public class SecretsPropertySourceTest {
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class)
|
||||
@TestPropertySource("classpath:/application-secrets.properties")
|
||||
public class SecretsPropertySourceTest {
|
||||
|
||||
private static final String NAMESPACE = "test";
|
||||
|
||||
private static final String SECRET_VALUE = "secretValue";
|
||||
|
||||
@ClassRule public static KubernetesServer server = new KubernetesServer(false, true);
|
||||
@ClassRule
|
||||
public static KubernetesServer server = new KubernetesServer(false, true);
|
||||
|
||||
@Autowired private SecretsPropertySourceLocator propertySourceLocator;
|
||||
@Autowired private Environment environment;
|
||||
@Autowired
|
||||
private SecretsPropertySourceLocator propertySourceLocator;
|
||||
|
||||
@BeforeClass public static void setUpBeforeClass() {
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() {
|
||||
KubernetesClient mockClient = server.getClient();
|
||||
|
||||
// Configure the kubernetes master url to point to the mock server
|
||||
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
|
||||
mockClient.getConfiguration().getMasterUrl());
|
||||
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");
|
||||
"false");
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, NAMESPACE);
|
||||
|
||||
Secret secret = new SecretBuilder().withNewMetadata()
|
||||
.withLabels(singletonMap("foo", "bar")).endMetadata()
|
||||
.addToData("secretName", Base64.getEncoder().encodeToString(SECRET_VALUE.getBytes()))
|
||||
.build();
|
||||
.withLabels(singletonMap("foo", "bar")).endMetadata()
|
||||
.addToData("secretName",
|
||||
Base64.getEncoder().encodeToString(SECRET_VALUE.getBytes()))
|
||||
.build();
|
||||
mockClient.secrets().inNamespace(NAMESPACE).create(secret);
|
||||
}
|
||||
|
||||
@Test public void toStringShouldNotExposeSecretValues() {
|
||||
String actual = propertySourceLocator.locate(environment).toString();
|
||||
@Test
|
||||
public void toStringShouldNotExposeSecretValues() {
|
||||
String actual = this.propertySourceLocator.locate(this.environment).toString();
|
||||
|
||||
assertThat(actual).doesNotContain(SECRET_VALUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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.example;
|
||||
@@ -25,7 +24,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class App {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(App.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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.example;
|
||||
@@ -36,17 +35,21 @@ public class GreetingController {
|
||||
}
|
||||
|
||||
@RequestMapping("/api/greeting")
|
||||
public ResponseMessage greeting(@RequestParam(value="name", defaultValue="World") String name) {
|
||||
return new ResponseMessage(String.format(properties.getGreeting(), name));
|
||||
public ResponseMessage greeting(
|
||||
@RequestParam(value = "name", defaultValue = "World") String name) {
|
||||
return new ResponseMessage(String.format(this.properties.getGreeting(), name));
|
||||
}
|
||||
|
||||
@RequestMapping("/api/farewell")
|
||||
public ResponseMessage farewell(@RequestParam(value="name", defaultValue="World") String name) {
|
||||
return new ResponseMessage(String.format(properties.getFarewell(), name));
|
||||
public ResponseMessage farewell(
|
||||
@RequestParam(value = "name", defaultValue = "World") String name) {
|
||||
return new ResponseMessage(String.format(this.properties.getFarewell(), name));
|
||||
}
|
||||
|
||||
@RequestMapping("/api/morning")
|
||||
public ResponseMessage morning(@RequestParam(value="name", defaultValue="World") String name) {
|
||||
return new ResponseMessage(String.format(properties.getMorning(), name));
|
||||
public ResponseMessage morning(
|
||||
@RequestParam(value = "name", defaultValue = "World") String name) {
|
||||
return new ResponseMessage(String.format(this.properties.getMorning(), name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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.example;
|
||||
@@ -25,11 +24,13 @@ import org.springframework.context.annotation.Configuration;
|
||||
public class GreetingProperties {
|
||||
|
||||
private String greeting = "Hello, %s!";
|
||||
|
||||
private String farewell = "Goodbye, %s!";
|
||||
|
||||
private String morning = "Good morning, %s!";
|
||||
|
||||
public String getGreeting() {
|
||||
return greeting;
|
||||
return this.greeting;
|
||||
}
|
||||
|
||||
public void setGreeting(String greeting) {
|
||||
@@ -37,7 +38,7 @@ public class GreetingProperties {
|
||||
}
|
||||
|
||||
public String getFarewell() {
|
||||
return farewell;
|
||||
return this.farewell;
|
||||
}
|
||||
|
||||
public void setFarewell(String farewell) {
|
||||
@@ -45,10 +46,11 @@ public class GreetingProperties {
|
||||
}
|
||||
|
||||
public String getMorning() {
|
||||
return morning;
|
||||
return this.morning;
|
||||
}
|
||||
|
||||
public void setMorning(String morning) {
|
||||
this.morning = morning;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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.example;
|
||||
@@ -33,6 +32,7 @@ public class ResponseMessage {
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
return this.content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -28,7 +27,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class ExampleApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(org.springframework.cloud.kubernetes.config.example.App.class, args);
|
||||
SpringApplication
|
||||
.run(org.springframework.cloud.kubernetes.config.example.App.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -42,27 +42,28 @@ public class ExampleApp {
|
||||
|
||||
@GetMapping("/common")
|
||||
public Response commonMessage() {
|
||||
return new Response(exampleAppProps.getCommonMessage());
|
||||
return new Response(this.exampleAppProps.getCommonMessage());
|
||||
}
|
||||
|
||||
@GetMapping("/m1")
|
||||
public Response message1() {
|
||||
return new Response(exampleAppProps.getMessage1());
|
||||
return new Response(this.exampleAppProps.getMessage1());
|
||||
}
|
||||
|
||||
@GetMapping("/m2")
|
||||
public Response message2() {
|
||||
return new Response(exampleAppProps.getMessage2());
|
||||
return new Response(this.exampleAppProps.getMessage2());
|
||||
}
|
||||
|
||||
@GetMapping("/m3")
|
||||
public Response message3() {
|
||||
return new Response(exampleAppProps.getMessage3());
|
||||
return new Response(this.exampleAppProps.getMessage3());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class Response {
|
||||
|
||||
|
||||
private final String message;
|
||||
|
||||
public Response(String message) {
|
||||
@@ -70,8 +71,9 @@ public class ExampleApp {
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
return this.message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -23,12 +22,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
public class ExampleAppProps {
|
||||
|
||||
private String commonMessage;
|
||||
|
||||
private String message1;
|
||||
|
||||
private String message2;
|
||||
|
||||
private String message3;
|
||||
|
||||
public String getCommonMessage() {
|
||||
return commonMessage;
|
||||
return this.commonMessage;
|
||||
}
|
||||
|
||||
public void setCommonMessage(String commonMessage) {
|
||||
@@ -36,7 +38,7 @@ public class ExampleAppProps {
|
||||
}
|
||||
|
||||
public String getMessage1() {
|
||||
return message1;
|
||||
return this.message1;
|
||||
}
|
||||
|
||||
public void setMessage1(String message1) {
|
||||
@@ -44,7 +46,7 @@ public class ExampleAppProps {
|
||||
}
|
||||
|
||||
public String getMessage2() {
|
||||
return message2;
|
||||
return this.message2;
|
||||
}
|
||||
|
||||
public void setMessage2(String message2) {
|
||||
@@ -52,10 +54,11 @@ public class ExampleAppProps {
|
||||
}
|
||||
|
||||
public String getMessage3() {
|
||||
return message3;
|
||||
return this.message3;
|
||||
}
|
||||
|
||||
public void setMessage3(String message3) {
|
||||
this.message3 = message3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
dummy.property.string1=a
|
||||
dummy.property.int1=1
|
||||
dummy.property.bool1=true
|
||||
dummy.property.bool1=true
|
||||
|
||||
@@ -2,4 +2,4 @@ dummy:
|
||||
property:
|
||||
string2: "a"
|
||||
int2: 1
|
||||
bool2: true
|
||||
bool2: true
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml" />
|
||||
<logger name="org.hibernate.validator" level="info" /> <!-- Validator prints a lot of debug messages during integration tests -->
|
||||
<logger name="okhttp3.mockwebserver" level="debug" />
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="org.hibernate.validator"
|
||||
level="info"/> <!-- Validator prints a lot of debug messages during integration tests -->
|
||||
<logger name="okhttp3.mockwebserver" level="debug"/>
|
||||
</configuration>
|
||||
|
||||
@@ -10,7 +10,7 @@ spring:
|
||||
name: defname
|
||||
namespace: defnamespace
|
||||
sources:
|
||||
- name: s1
|
||||
- namespace: s2
|
||||
- name: othername
|
||||
namespace: othernamespace
|
||||
- name: s1
|
||||
- namespace: s2
|
||||
- name: othername
|
||||
namespace: othernamespace
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,20 +12,19 @@
|
||||
* 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.time.Duration;
|
||||
|
||||
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 java.time.Duration;
|
||||
|
||||
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;
|
||||
@@ -34,6 +33,11 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Auto configuration for Kubernetes.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties(KubernetesClientProperties.class)
|
||||
@@ -41,6 +45,33 @@ public class KubernetesAutoConfiguration {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesAutoConfiguration.class);
|
||||
|
||||
private static <D> D or(D dis, D dat) {
|
||||
if (dis != null) {
|
||||
return dis;
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer orDurationInt(Duration dis, Integer dat) {
|
||||
if (dis != null) {
|
||||
return (int) dis.toMillis();
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
|
||||
private static Long orDurationLong(Duration dis, Long dat) {
|
||||
if (dis != null) {
|
||||
return dis.toMillis();
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Config.class)
|
||||
public Config kubernetesClientConfig(
|
||||
@@ -83,27 +114,29 @@ public class KubernetesAutoConfiguration {
|
||||
.withConnectionTimeout(
|
||||
orDurationInt(kubernetesClientProperties.getConnectionTimeout(),
|
||||
base.getConnectionTimeout()))
|
||||
.withRequestTimeout(orDurationInt(kubernetesClientProperties.getRequestTimeout(),
|
||||
base.getRequestTimeout()))
|
||||
.withRollingTimeout(orDurationLong(kubernetesClientProperties.getRollingTimeout(),
|
||||
base.getRollingTimeout()))
|
||||
.withRequestTimeout(
|
||||
orDurationInt(kubernetesClientProperties.getRequestTimeout(),
|
||||
base.getRequestTimeout()))
|
||||
.withRollingTimeout(
|
||||
orDurationLong(kubernetesClientProperties.getRollingTimeout(),
|
||||
base.getRollingTimeout()))
|
||||
.withTrustCerts(or(kubernetesClientProperties.isTrustCerts(),
|
||||
base.isTrustCerts()))
|
||||
.withHttpProxy(or(kubernetesClientProperties.getHttpProxy(),
|
||||
base.getHttpProxy()))
|
||||
base.getHttpProxy()))
|
||||
.withHttpsProxy(or(kubernetesClientProperties.getHttpsProxy(),
|
||||
base.getHttpsProxy()))
|
||||
base.getHttpsProxy()))
|
||||
.withProxyUsername(or(kubernetesClientProperties.getProxyUsername(),
|
||||
base.getProxyUsername()))
|
||||
base.getProxyUsername()))
|
||||
.withPassword(or(kubernetesClientProperties.getProxyPassword(),
|
||||
base.getProxyPassword()))
|
||||
.withNoProxy(or(kubernetesClientProperties.getNoProxy(),
|
||||
base.getNoProxy()))
|
||||
base.getProxyPassword()))
|
||||
.withNoProxy(
|
||||
or(kubernetesClientProperties.getNoProxy(), base.getNoProxy()))
|
||||
.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)");
|
||||
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;
|
||||
}
|
||||
@@ -123,41 +156,17 @@ public class KubernetesAutoConfiguration {
|
||||
@Configuration
|
||||
@ConditionalOnClass(HealthIndicator.class)
|
||||
protected static class KubernetesActuatorConfiguration {
|
||||
|
||||
@Bean
|
||||
public KubernetesHealthIndicator kubernetesHealthIndicator(PodUtils podUtils) {
|
||||
return new KubernetesHealthIndicator(podUtils);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public KubernetesInfoContributor kubernetesInfoContributor(PodUtils podUtils) {
|
||||
return new KubernetesInfoContributor(podUtils);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static <D> D or(D dis, D dat) {
|
||||
if (dis != null) {
|
||||
return dis;
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer orDurationInt(Duration dis, Integer dat) {
|
||||
if (dis != null) {
|
||||
return (int)dis.toMillis();
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
|
||||
private static Long orDurationLong(Duration dis, Long dat) {
|
||||
if (dis != null) {
|
||||
return dis.toMillis();
|
||||
}
|
||||
else {
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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,37 +20,66 @@ import java.time.Duration;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Kubernetes client properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@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 Duration watchReconnectInterval;
|
||||
|
||||
private Duration watchReconnectLimit;
|
||||
|
||||
private Duration connectionTimeout;
|
||||
|
||||
private Duration requestTimeout;
|
||||
|
||||
private Duration rollingTimeout;
|
||||
|
||||
private Duration loggingInterval;
|
||||
|
||||
private String httpProxy;
|
||||
|
||||
private String httpsProxy;
|
||||
|
||||
private String proxyUsername;
|
||||
|
||||
private String proxyPassword;
|
||||
|
||||
private String[] noProxy;
|
||||
|
||||
public String getClientCertData() {
|
||||
return clientCertData;
|
||||
return this.clientCertData;
|
||||
}
|
||||
|
||||
public void setClientCertData(String clientCertData) {
|
||||
@@ -59,15 +87,11 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Boolean isTrustCerts() {
|
||||
return trustCerts;
|
||||
}
|
||||
|
||||
public void setTrustCerts(Boolean trustCerts) {
|
||||
this.trustCerts = trustCerts;
|
||||
return this.trustCerts;
|
||||
}
|
||||
|
||||
public String getMasterUrl() {
|
||||
return masterUrl;
|
||||
return this.masterUrl;
|
||||
}
|
||||
|
||||
public void setMasterUrl(String masterUrl) {
|
||||
@@ -75,7 +99,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getApiVersion() {
|
||||
return apiVersion;
|
||||
return this.apiVersion;
|
||||
}
|
||||
|
||||
public void setApiVersion(String apiVersion) {
|
||||
@@ -83,7 +107,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
@@ -91,7 +115,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getCaCertFile() {
|
||||
return caCertFile;
|
||||
return this.caCertFile;
|
||||
}
|
||||
|
||||
public void setCaCertFile(String caCertFile) {
|
||||
@@ -99,7 +123,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getCaCertData() {
|
||||
return caCertData;
|
||||
return this.caCertData;
|
||||
}
|
||||
|
||||
public void setCaCertData(String caCertData) {
|
||||
@@ -107,7 +131,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getClientCertFile() {
|
||||
return clientCertFile;
|
||||
return this.clientCertFile;
|
||||
}
|
||||
|
||||
public void setClientCertFile(String clientCertFile) {
|
||||
@@ -115,7 +139,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getClientKeyFile() {
|
||||
return clientKeyFile;
|
||||
return this.clientKeyFile;
|
||||
}
|
||||
|
||||
public void setClientKeyFile(String clientKeyFile) {
|
||||
@@ -123,7 +147,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getClientKeyData() {
|
||||
return clientKeyData;
|
||||
return this.clientKeyData;
|
||||
}
|
||||
|
||||
public void setClientKeyData(String clientKeyData) {
|
||||
@@ -131,7 +155,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getClientKeyAlgo() {
|
||||
return clientKeyAlgo;
|
||||
return this.clientKeyAlgo;
|
||||
}
|
||||
|
||||
public void setClientKeyAlgo(String clientKeyAlgo) {
|
||||
@@ -139,7 +163,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getClientKeyPassphrase() {
|
||||
return clientKeyPassphrase;
|
||||
return this.clientKeyPassphrase;
|
||||
}
|
||||
|
||||
public void setClientKeyPassphrase(String clientKeyPassphrase) {
|
||||
@@ -147,7 +171,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
@@ -155,7 +179,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
@@ -163,7 +187,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getWatchReconnectInterval() {
|
||||
return watchReconnectInterval;
|
||||
return this.watchReconnectInterval;
|
||||
}
|
||||
|
||||
public void setWatchReconnectInterval(Duration watchReconnectInterval) {
|
||||
@@ -171,7 +195,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getWatchReconnectLimit() {
|
||||
return watchReconnectLimit;
|
||||
return this.watchReconnectLimit;
|
||||
}
|
||||
|
||||
public void setWatchReconnectLimit(Duration watchReconnectLimit) {
|
||||
@@ -179,7 +203,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getConnectionTimeout() {
|
||||
return connectionTimeout;
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
@@ -187,7 +211,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getRequestTimeout() {
|
||||
return requestTimeout;
|
||||
return this.requestTimeout;
|
||||
}
|
||||
|
||||
public void setRequestTimeout(Duration requestTimeout) {
|
||||
@@ -195,7 +219,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getRollingTimeout() {
|
||||
return rollingTimeout;
|
||||
return this.rollingTimeout;
|
||||
}
|
||||
|
||||
public void setRollingTimeout(Duration rollingTimeout) {
|
||||
@@ -203,7 +227,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Duration getLoggingInterval() {
|
||||
return loggingInterval;
|
||||
return this.loggingInterval;
|
||||
}
|
||||
|
||||
public void setLoggingInterval(Duration loggingInterval) {
|
||||
@@ -211,11 +235,15 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public Boolean getTrustCerts() {
|
||||
return trustCerts;
|
||||
return this.trustCerts;
|
||||
}
|
||||
|
||||
public void setTrustCerts(Boolean trustCerts) {
|
||||
this.trustCerts = trustCerts;
|
||||
}
|
||||
|
||||
public String getHttpProxy() {
|
||||
return httpProxy;
|
||||
return this.httpProxy;
|
||||
}
|
||||
|
||||
public void setHttpProxy(String httpProxy) {
|
||||
@@ -223,7 +251,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getHttpsProxy() {
|
||||
return httpsProxy;
|
||||
return this.httpsProxy;
|
||||
}
|
||||
|
||||
public void setHttpsProxy(String httpsProxy) {
|
||||
@@ -231,7 +259,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getProxyUsername() {
|
||||
return proxyUsername;
|
||||
return this.proxyUsername;
|
||||
}
|
||||
|
||||
public void setProxyUsername(String proxyUsername) {
|
||||
@@ -239,7 +267,7 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String getProxyPassword() {
|
||||
return proxyPassword;
|
||||
return this.proxyPassword;
|
||||
}
|
||||
|
||||
public void setProxyPassword(String proxyPassword) {
|
||||
@@ -247,10 +275,11 @@ public class KubernetesClientProperties {
|
||||
}
|
||||
|
||||
public String[] getNoProxy() {
|
||||
return noProxy;
|
||||
return this.noProxy;
|
||||
}
|
||||
|
||||
public void setNoProxy(String[] noProxy) {
|
||||
this.noProxy = noProxy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -22,6 +21,11 @@ import io.fabric8.kubernetes.api.model.Pod;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
|
||||
/**
|
||||
* Kubernetes implementation of {@link AbstractHealthIndicator}.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class KubernetesHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private PodUtils utils;
|
||||
@@ -33,7 +37,7 @@ public class KubernetesHealthIndicator extends AbstractHealthIndicator {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
try {
|
||||
Pod current = utils.currentPod().get();
|
||||
Pod current = this.utils.currentPod().get();
|
||||
if (current != null) {
|
||||
builder.up().withDetail("inside", true)
|
||||
.withDetail("namespace", current.getMetadata().getNamespace())
|
||||
@@ -52,4 +56,5 @@ public class KubernetesHealthIndicator extends AbstractHealthIndicator {
|
||||
builder.down(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,25 +12,29 @@
|
||||
* 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.actuate.info.Info.Builder;
|
||||
import org.springframework.boot.actuate.info.InfoContributor;
|
||||
|
||||
/**
|
||||
* Kubernetes implementation of {@link InfoContributor}.
|
||||
*
|
||||
* @author Mark Anderson
|
||||
*/
|
||||
public class KubernetesInfoContributor implements InfoContributor {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesInfoContributor.class);
|
||||
|
||||
|
||||
private PodUtils utils;
|
||||
|
||||
public KubernetesInfoContributor(PodUtils utils) {
|
||||
@@ -40,7 +44,7 @@ public class KubernetesInfoContributor implements InfoContributor {
|
||||
@Override
|
||||
public void contribute(Builder builder) {
|
||||
try {
|
||||
Pod current = utils.currentPod().get();
|
||||
Pod current = this.utils.currentPod().get();
|
||||
Map<String, Object> details = new HashMap<>();
|
||||
if (current != null) {
|
||||
details.put("inside", true);
|
||||
@@ -60,4 +64,5 @@ public class KubernetesInfoContributor implements InfoContributor {
|
||||
LOG.warn("Failed to get pod details", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,34 +12,41 @@
|
||||
* 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> {
|
||||
/**
|
||||
* Lazy instantiation utility class.
|
||||
*
|
||||
* @param <T> return type
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public final class LazilyInstantiate<T> implements Supplier<T> {
|
||||
|
||||
public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) {
|
||||
return new LazilyInstantiate<T>(supplier);
|
||||
}
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public synchronized T get() {
|
||||
return current.get();
|
||||
}
|
||||
private Supplier<T> current;
|
||||
|
||||
private LazilyInstantiate(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
this.current = () -> swapper();
|
||||
}
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
private Supplier<T> current;
|
||||
public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) {
|
||||
return new LazilyInstantiate<T>(supplier);
|
||||
}
|
||||
|
||||
public synchronized T get() {
|
||||
return this.current.get();
|
||||
}
|
||||
|
||||
private T swapper() {
|
||||
T obj = supplier.get();
|
||||
current = () -> obj;
|
||||
T obj = this.supplier.get();
|
||||
this.current = () -> obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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,6 +20,11 @@ import java.util.function.Supplier;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
/**
|
||||
* Utility interface to retrieve {@link Pod} related information.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public interface PodUtils {
|
||||
|
||||
/**
|
||||
@@ -33,4 +37,5 @@ public interface PodUtils {
|
||||
* @return true if called from within Kubernetes, false otherwise.
|
||||
*/
|
||||
Boolean isInsideKubernetes();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -26,13 +25,24 @@ import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Utility class to work with pods.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class StandardPodUtils implements PodUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(StandardPodUtils.class);
|
||||
/**
|
||||
* Hostname environment variable name.
|
||||
*/
|
||||
public static final String HOSTNAME = "HOSTNAME";
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(StandardPodUtils.class);
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
private final String hostName;
|
||||
|
||||
private Supplier<Pod> current;
|
||||
|
||||
public StandardPodUtils(KubernetesClient client) {
|
||||
@@ -48,7 +58,7 @@ public class StandardPodUtils implements PodUtils {
|
||||
|
||||
@Override
|
||||
public Supplier<Pod> currentPod() {
|
||||
return current;
|
||||
return this.current;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,22 +69,23 @@ public class StandardPodUtils implements PodUtils {
|
||||
private synchronized Pod internalGetPod() {
|
||||
try {
|
||||
if (isServiceAccountFound() && isHostNameEnvVarPresent()) {
|
||||
return client.pods().withName(hostName).get();
|
||||
return this.client.pods().withName(this.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?",
|
||||
LOG.warn("Failed to get pod with name:[" + this.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();
|
||||
return this.hostName != null && !this.hostName.isEmpty();
|
||||
}
|
||||
|
||||
private boolean isServiceAccountFound() {
|
||||
@@ -82,4 +93,5 @@ public class StandardPodUtils implements PodUtils {
|
||||
&& Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile()
|
||||
.exists();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -27,6 +26,11 @@ import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Kubernetes specific application context initializer.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class KubernetesApplicationContextInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||
|
||||
@@ -54,7 +58,8 @@ public class KubernetesApplicationContextInitializer implements
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
listenerSupplier.get().addKubernetesProfile(applicationContext.getEnvironment());
|
||||
this.listenerSupplier.get()
|
||||
.addKubernetesProfile(applicationContext.getEnvironment());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -27,6 +26,11 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Adds Kubernetes profiles.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class KubernetesProfileApplicationListener
|
||||
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
|
||||
|
||||
@@ -34,8 +38,11 @@ public class KubernetesProfileApplicationListener
|
||||
.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;
|
||||
|
||||
public KubernetesProfileApplicationListener(PodUtils utils) {
|
||||
@@ -49,7 +56,7 @@ public class KubernetesProfileApplicationListener
|
||||
}
|
||||
|
||||
void addKubernetesProfile(ConfigurableEnvironment environment) {
|
||||
if (utils.isInsideKubernetes()) {
|
||||
if (this.utils.isInsideKubernetes()) {
|
||||
if (hasKubernetesProfile(environment)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("'kubernetes' already in list of active profiles");
|
||||
@@ -83,4 +90,5 @@ public class KubernetesProfileApplicationListener
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
package org.springframework.cloud.kubernetes;
|
||||
/*
|
||||
* Copyright 2013-2019 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.
|
||||
*/
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
package org.springframework.cloud.kubernetes;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
@@ -11,16 +24,18 @@ import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = {
|
||||
"management.endpoint.health.show-details=always"
|
||||
})
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"management.endpoint.health.show-details=always" })
|
||||
public class HealthIndicatorTest {
|
||||
|
||||
@ClassRule
|
||||
@@ -31,29 +46,26 @@ public class HealthIndicatorTest {
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthEndpointShouldContainKubernetes() {
|
||||
RestAssured.baseURI = String.format("http://localhost:%d/actuator/health", port);
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.get()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body(containsString("kubernetes"));
|
||||
RestAssured.baseURI = String.format("http://localhost:%d/actuator/health",
|
||||
this.port);
|
||||
given().contentType("application/json").get().then().statusCode(200)
|
||||
.body(containsString("kubernetes"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,14 +12,10 @@
|
||||
* 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 static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.server.mock.KubernetesServer;
|
||||
@@ -28,11 +24,15 @@ import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class)
|
||||
public class InfoContributorTest {
|
||||
@@ -45,29 +45,26 @@ public class InfoContributorTest {
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void infoEndpointShouldContainKubernetes() {
|
||||
RestAssured.baseURI = String.format("http://localhost:%d/actuator/info", port);
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.get()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body(containsString("kubernetes"));
|
||||
RestAssured.baseURI = String.format("http://localhost:%d/actuator/info",
|
||||
this.port);
|
||||
given().contentType("application/json").get().then().statusCode(200)
|
||||
.body(containsString("kubernetes"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,15 +12,10 @@
|
||||
* 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 static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -29,6 +24,10 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LazilyInstantiateTest {
|
||||
|
||||
@@ -40,30 +39,32 @@ public class LazilyInstantiateTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// common setup
|
||||
when(mockSupplier.get()).thenReturn(SINGLETON)
|
||||
when(this.mockSupplier.get()).thenReturn(SINGLETON)
|
||||
.thenThrow(new RuntimeException("Supplier was called more than once!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supplierNotCalledInLazyInstantiateFactoryMethod() {
|
||||
LazilyInstantiate.using(mockSupplier);
|
||||
LazilyInstantiate.using(this.mockSupplier);
|
||||
|
||||
// verify
|
||||
verifyZeroInteractions(mockSupplier);
|
||||
verifyZeroInteractions(this.mockSupplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void factoryReturnsSingletonFromSupplier() {
|
||||
LazilyInstantiate<String> lazyStringFactory = LazilyInstantiate.using(mockSupplier);
|
||||
LazilyInstantiate<String> lazyStringFactory = LazilyInstantiate
|
||||
.using(this.mockSupplier);
|
||||
String singletonString = lazyStringFactory.get();
|
||||
|
||||
// verify
|
||||
assertEquals(SINGLETON, singletonString);
|
||||
assertThat(singletonString).isEqualTo(SINGLETON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void factoryOnlyCallsSupplierOnce() {
|
||||
LazilyInstantiate<String> lazyStringFactory = LazilyInstantiate.using(mockSupplier);
|
||||
LazilyInstantiate<String> lazyStringFactory = LazilyInstantiate
|
||||
.using(this.mockSupplier);
|
||||
lazyStringFactory.get();
|
||||
|
||||
// mock will throw exception if it is called more than once
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 org.junit.Test;
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.example;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -22,6 +21,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.cloud.kubernetes.PodUtils;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
@@ -48,23 +48,23 @@ public class KubernetesProfileApplicationListenerTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
when(mockEnvironment.getActiveProfiles()).thenReturn(ACTIVE_PROFILES);
|
||||
when(mockEvent.getEnvironment()).thenReturn(mockEnvironment);
|
||||
listener = new KubernetesProfileApplicationListener(mockPodUtils);
|
||||
when(this.mockEnvironment.getActiveProfiles()).thenReturn(ACTIVE_PROFILES);
|
||||
when(this.mockEvent.getEnvironment()).thenReturn(this.mockEnvironment);
|
||||
this.listener = new KubernetesProfileApplicationListener(this.mockPodUtils);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEnableKubernetesProfile() {
|
||||
when(mockPodUtils.isInsideKubernetes()).thenReturn(true);
|
||||
listener.onApplicationEvent(mockEvent);
|
||||
verify(mockEnvironment).addActiveProfile("kubernetes");
|
||||
when(this.mockPodUtils.isInsideKubernetes()).thenReturn(true);
|
||||
this.listener.onApplicationEvent(this.mockEvent);
|
||||
verify(this.mockEnvironment).addActiveProfile("kubernetes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotEnableKubernetesProfile() {
|
||||
when(mockPodUtils.isInsideKubernetes()).thenReturn(false);
|
||||
listener.onApplicationEvent(mockEvent);
|
||||
verify(mockEnvironment, times(0)).addActiveProfile("kubernetes");
|
||||
when(this.mockPodUtils.isInsideKubernetes()).thenReturn(false);
|
||||
this.listener.onApplicationEvent(this.mockEvent);
|
||||
verify(this.mockEnvironment, times(0)).addActiveProfile("kubernetes");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
<parent>
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,69 +12,76 @@
|
||||
* 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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* TODO break up into delegates if the implementation get's more complicated
|
||||
* <p>
|
||||
* Returns true if one of the following conditions apply:
|
||||
* Returns true if one of the following conditions apply.
|
||||
* <p>
|
||||
* spring.cloud.kubernetes.discovery.secured has been set to true
|
||||
* the service contains a label or an annotation named 'secured' that is truthy
|
||||
* the port is one of the known ports used for secure communication
|
||||
* spring.cloud.kubernetes.discovery.secured has been set to true the service contains a
|
||||
* label or an annotation named 'secured' that is truthy the port is one of the known
|
||||
* ports used for secure communication
|
||||
*/
|
||||
class DefaultIsServicePortSecureResolver {
|
||||
|
||||
private static final Log log = LogFactory.getLog(DefaultIsServicePortSecureResolver.class);
|
||||
private static final Log log = LogFactory
|
||||
.getLog(DefaultIsServicePortSecureResolver.class);
|
||||
|
||||
|
||||
private static final Set<String> TRUTHY_STRINGS = new HashSet<String>() {{
|
||||
add("true");
|
||||
add("on");
|
||||
add("yes");
|
||||
add("1");
|
||||
}};
|
||||
private static final Set<String> TRUTHY_STRINGS = new HashSet<String>() {
|
||||
{
|
||||
add("true");
|
||||
add("on");
|
||||
add("yes");
|
||||
add("1");
|
||||
}
|
||||
};
|
||||
|
||||
private final KubernetesDiscoveryProperties properties;
|
||||
|
||||
public DefaultIsServicePortSecureResolver(KubernetesDiscoveryProperties properties) {
|
||||
DefaultIsServicePortSecureResolver(KubernetesDiscoveryProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
boolean resolve(Input input) {
|
||||
final String securedLabelValue = input.getServiceLabels().getOrDefault("secured", "false");
|
||||
final String securedLabelValue = input.getServiceLabels().getOrDefault("secured",
|
||||
"false");
|
||||
if (TRUTHY_STRINGS.contains(securedLabelValue)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Considering service with name: " + input.getServiceName() + " and port " + input.getPort()
|
||||
+ " is secure since the service contains a true value for the 'secured' label");
|
||||
log.debug("Considering service with name: " + input.getServiceName()
|
||||
+ " and port " + input.getPort()
|
||||
+ " is secure since the service contains a true value for the 'secured' label");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final String securedAnnotationValue = input.getServiceAnnotations().getOrDefault("secured", "false");
|
||||
final String securedAnnotationValue = input.getServiceAnnotations()
|
||||
.getOrDefault("secured", "false");
|
||||
if (TRUTHY_STRINGS.contains(securedAnnotationValue)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Considering service with name: " + input.getServiceName() + " and port " + input.getPort()
|
||||
+ " is secure since the service contains a true value for the 'secured' annotation");
|
||||
log.debug("Considering service with name: " + input.getServiceName()
|
||||
+ " and port " + input.getPort()
|
||||
+ " is secure since the service contains a true value for the 'secured' annotation");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.getPort() != null && properties.getKnownSecurePorts().contains(input.getPort())) {
|
||||
if (input.getPort() != null
|
||||
&& this.properties.getKnownSecurePorts().contains(input.getPort())) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Considering service with name: " + input.getServiceName() + " and port " + input.getPort()
|
||||
+ " is secure due to the port being a known https port");
|
||||
log.debug("Considering service with name: " + input.getServiceName()
|
||||
+ " and port " + input.getPort()
|
||||
+ " is secure due to the port being a known https port");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -83,38 +90,45 @@ class DefaultIsServicePortSecureResolver {
|
||||
}
|
||||
|
||||
static class Input {
|
||||
|
||||
private final Integer port;
|
||||
|
||||
private final String serviceName;
|
||||
|
||||
private final Map<String, String> serviceLabels;
|
||||
|
||||
private final Map<String, String> serviceAnnotations;
|
||||
|
||||
//used only for testing
|
||||
// used only for testing
|
||||
Input(Integer port, String serviceName) {
|
||||
this(port, serviceName, null, null);
|
||||
}
|
||||
|
||||
Input(Integer port, String serviceName,
|
||||
Map<String, String> serviceLabels, Map<String, String> serviceAnnotations) {
|
||||
Input(Integer port, String serviceName, Map<String, String> serviceLabels,
|
||||
Map<String, String> serviceAnnotations) {
|
||||
this.port = port;
|
||||
this.serviceName = serviceName;
|
||||
this.serviceLabels = serviceLabels == null ? new HashMap<>() : serviceLabels;
|
||||
this.serviceAnnotations = serviceAnnotations == null ? new HashMap<>() : serviceAnnotations;
|
||||
this.serviceAnnotations = serviceAnnotations == null ? new HashMap<>()
|
||||
: serviceAnnotations;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
return this.serviceName;
|
||||
}
|
||||
|
||||
public Map<String, String> getServiceLabels() {
|
||||
return serviceLabels;
|
||||
return this.serviceLabels;
|
||||
}
|
||||
|
||||
public Map<String, String> getServiceAnnotations() {
|
||||
return serviceAnnotations;
|
||||
return this.serviceAnnotations;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
return this.port;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,11 +12,16 @@
|
||||
* 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 java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointAddress;
|
||||
import io.fabric8.kubernetes.api.model.EndpointSubset;
|
||||
import io.fabric8.kubernetes.api.model.Endpoints;
|
||||
@@ -24,29 +29,25 @@ import io.fabric8.kubernetes.api.model.ObjectReference;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* @author Oleg Vyukov
|
||||
*/
|
||||
public class KubernetesCatalogWatch implements ApplicationEventPublisherAware {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KubernetesCatalogWatch.class);
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(KubernetesCatalogWatch.class);
|
||||
|
||||
private final KubernetesClient kubernetesClient;
|
||||
private final AtomicReference<List<String>> catalogEndpointsState = new AtomicReference<>();
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
private final AtomicReference<List<String>> catalogEndpointsState = new AtomicReference<>();
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
public KubernetesCatalogWatch(KubernetesClient kubernetesClient) {
|
||||
this.kubernetesClient = kubernetesClient;
|
||||
@@ -60,33 +61,32 @@ public class KubernetesCatalogWatch implements ApplicationEventPublisherAware {
|
||||
@Scheduled(fixedDelayString = "${spring.cloud.kubernetes.discovery.catalogServicesWatchDelay:30000}")
|
||||
public void catalogServicesWatch() {
|
||||
try {
|
||||
List<String> previousState = catalogEndpointsState.get();
|
||||
List<String> previousState = this.catalogEndpointsState.get();
|
||||
|
||||
//not all pods participate in the service discovery. only those that have endpoints.
|
||||
List<Endpoints> endpoints = kubernetesClient.endpoints().list().getItems();
|
||||
List<String> endpointsPodNames =
|
||||
endpoints.stream()
|
||||
.map(Endpoints::getSubsets)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.map(EndpointSubset::getAddresses)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.map(EndpointAddress::getTargetRef)
|
||||
.filter(Objects::nonNull)
|
||||
.map(ObjectReference::getName) // pod name unique in namespace
|
||||
// not all pods participate in the service discovery. only those that have
|
||||
// endpoints.
|
||||
List<Endpoints> endpoints = this.kubernetesClient.endpoints().list()
|
||||
.getItems();
|
||||
List<String> endpointsPodNames = endpoints.stream().map(Endpoints::getSubsets)
|
||||
.filter(Objects::nonNull).flatMap(Collection::stream)
|
||||
.map(EndpointSubset::getAddresses).filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream).map(EndpointAddress::getTargetRef)
|
||||
.filter(Objects::nonNull).map(ObjectReference::getName) // pod name
|
||||
// unique in
|
||||
// namespace
|
||||
.sorted(String::compareTo).collect(Collectors.toList());
|
||||
|
||||
catalogEndpointsState.set(endpointsPodNames);
|
||||
this.catalogEndpointsState.set(endpointsPodNames);
|
||||
|
||||
if (!endpointsPodNames.equals(previousState)) {
|
||||
logger.trace("Received endpoints update from kubernetesClient: {}", endpointsPodNames);
|
||||
publisher.publishEvent(new HeartbeatEvent(this, endpointsPodNames));
|
||||
logger.trace("Received endpoints update from kubernetesClient: {}",
|
||||
endpointsPodNames);
|
||||
this.publisher.publishEvent(new HeartbeatEvent(this, endpointsPodNames));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Error watching Kubernetes Services", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,10 +12,12 @@
|
||||
* 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 java.util.function.Function;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceList;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
@@ -23,23 +25,25 @@ import io.fabric8.kubernetes.client.Watch;
|
||||
import io.fabric8.kubernetes.client.Watcher;
|
||||
import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A regular java.util.function that is used to hide the complexity of the KubernetesClient interfaces
|
||||
* A regular java.util.function that is used to hide the complexity of the
|
||||
* KubernetesClient interfaces.
|
||||
*
|
||||
* It's meant to be used to abstract things like:
|
||||
*
|
||||
* client.services()
|
||||
* client.services().withLabel("key", "value")
|
||||
* client.services() client.services().withLabel("key", "value")
|
||||
* client.services().withoutLabel("key")
|
||||
*
|
||||
* The result of the application of the function can then be used for example to list the services like so:
|
||||
* The result of the application of the function can then be used for example to list the
|
||||
* services like so:
|
||||
*
|
||||
* function.apply(client).list()
|
||||
*
|
||||
* See KubernetesDiscoveryClientAutoConfiguration.servicesFunction
|
||||
*
|
||||
* @author Georgios Andrianakis
|
||||
*/
|
||||
public interface KubernetesClientServicesFunction extends
|
||||
Function<KubernetesClient, FilterWatchListDeletable<Service, ServiceList, Boolean, Watch, Watcher<Service>>> {
|
||||
Function<KubernetesClient, FilterWatchListDeletable<Service, ServiceList, Boolean, Watch, Watcher<Service>>> {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,10 +12,17 @@
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointAddress;
|
||||
import io.fabric8.kubernetes.api.model.EndpointPort;
|
||||
import io.fabric8.kubernetes.api.model.EndpointSubset;
|
||||
@@ -24,6 +31,7 @@ import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.expression.Expression;
|
||||
@@ -32,42 +40,42 @@ import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
/**
|
||||
* Kubeneretes implementation of {@link DiscoveryClient}.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
private static final Log log = LogFactory.getLog(KubernetesDiscoveryClient.class);
|
||||
|
||||
private KubernetesClient client;
|
||||
private final KubernetesDiscoveryProperties properties;
|
||||
|
||||
private final DefaultIsServicePortSecureResolver isServicePortSecureResolver;
|
||||
|
||||
private final KubernetesClientServicesFunction kubernetesClientServicesFunction;
|
||||
|
||||
private final SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
private final SimpleEvaluationContext evalCtxt = SimpleEvaluationContext
|
||||
.forReadOnlyDataBinding()
|
||||
.withInstanceMethods()
|
||||
.build();
|
||||
.forReadOnlyDataBinding().withInstanceMethods().build();
|
||||
|
||||
private KubernetesClient client;
|
||||
|
||||
public KubernetesDiscoveryClient(KubernetesClient client,
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction) {
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction) {
|
||||
|
||||
this(client, kubernetesDiscoveryProperties, kubernetesClientServicesFunction,
|
||||
new DefaultIsServicePortSecureResolver(kubernetesDiscoveryProperties));
|
||||
new DefaultIsServicePortSecureResolver(kubernetesDiscoveryProperties));
|
||||
}
|
||||
|
||||
KubernetesDiscoveryClient(KubernetesClient client,
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction,
|
||||
DefaultIsServicePortSecureResolver isServicePortSecureResolver) {
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction,
|
||||
DefaultIsServicePortSecureResolver isServicePortSecureResolver) {
|
||||
|
||||
this.client = client;
|
||||
this.properties = kubernetesDiscoveryProperties;
|
||||
@@ -76,7 +84,7 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
}
|
||||
|
||||
public KubernetesClient getClient() {
|
||||
return client;
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public void setClient(KubernetesClient client) {
|
||||
@@ -93,62 +101,64 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
Assert.notNull(serviceId,
|
||||
"[Assertion failed] - the object argument must be null");
|
||||
|
||||
Endpoints endpoints = client.endpoints().withName(serviceId).get();
|
||||
Endpoints endpoints = this.client.endpoints().withName(serviceId).get();
|
||||
List<EndpointSubset> subsets = getSubsetsFromEndpoints(endpoints);
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!subsets.isEmpty()) {
|
||||
|
||||
final Service service = client.services().withName(serviceId).get();
|
||||
final Service service = this.client.services().withName(serviceId).get();
|
||||
|
||||
final Map<String, String> serviceMetadata = new HashMap<>();
|
||||
KubernetesDiscoveryProperties.Metadata metadataProps = properties.getMetadata();
|
||||
if(metadataProps.isAddLabels()) {
|
||||
KubernetesDiscoveryProperties.Metadata metadataProps = this.properties
|
||||
.getMetadata();
|
||||
if (metadataProps.isAddLabels()) {
|
||||
Map<String, String> labelMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getLabels(), metadataProps.getLabelsPrefix());
|
||||
service.getMetadata().getLabels(),
|
||||
metadataProps.getLabelsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding label metadata: "+labelMetadata);
|
||||
log.debug("Adding label metadata: " + labelMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(labelMetadata);
|
||||
}
|
||||
if(metadataProps.isAddAnnotations()) {
|
||||
if (metadataProps.isAddAnnotations()) {
|
||||
Map<String, String> annotationMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getAnnotations(), metadataProps.getAnnotationsPrefix());
|
||||
service.getMetadata().getAnnotations(),
|
||||
metadataProps.getAnnotationsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding annotation metadata: "+annotationMetadata);
|
||||
log.debug("Adding annotation metadata: " + annotationMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(annotationMetadata);
|
||||
}
|
||||
|
||||
for (EndpointSubset s : subsets) {
|
||||
// Extend the service metadata map with per-endpoint port information (if requested)
|
||||
// Extend the service metadata map with per-endpoint port information (if
|
||||
// requested)
|
||||
Map<String, String> endpointMetadata = new HashMap<>(serviceMetadata);
|
||||
if(metadataProps.isAddPorts()) {
|
||||
if (metadataProps.isAddPorts()) {
|
||||
Map<String, String> ports = s.getPorts().stream()
|
||||
.filter(port -> !StringUtils.isEmpty(port.getName()))
|
||||
.collect(toMap(EndpointPort::getName, port -> Integer.toString(port.getPort())));
|
||||
Map<String, String> portMetadata = getMapWithPrefixedKeys(ports, metadataProps.getPortsPrefix());
|
||||
.filter(port -> !StringUtils.isEmpty(port.getName()))
|
||||
.collect(toMap(EndpointPort::getName,
|
||||
port -> Integer.toString(port.getPort())));
|
||||
Map<String, String> portMetadata = getMapWithPrefixedKeys(ports,
|
||||
metadataProps.getPortsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding port metadata: "+portMetadata);
|
||||
log.debug("Adding port metadata: " + portMetadata);
|
||||
}
|
||||
endpointMetadata.putAll(portMetadata);
|
||||
}
|
||||
|
||||
List<EndpointAddress> addresses = s.getAddresses();
|
||||
for (EndpointAddress endpointAddress : addresses) {
|
||||
final EndpointPort endpointPort =
|
||||
s.getPorts().stream().findFirst().orElseThrow(IllegalStateException::new);
|
||||
final EndpointPort endpointPort = s.getPorts().stream().findFirst()
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
instances.add(new KubernetesServiceInstance(serviceId,
|
||||
endpointAddress,
|
||||
endpointPort,
|
||||
endpointMetadata,
|
||||
isServicePortSecureResolver.resolve(
|
||||
new DefaultIsServicePortSecureResolver.Input(
|
||||
endpointAddress, endpointPort, endpointMetadata,
|
||||
this.isServicePortSecureResolver
|
||||
.resolve(new DefaultIsServicePortSecureResolver.Input(
|
||||
endpointPort.getPort(),
|
||||
service.getMetadata().getName(),
|
||||
service.getMetadata().getLabels(),
|
||||
service.getMetadata().getAnnotations()
|
||||
)
|
||||
)));
|
||||
service.getMetadata().getAnnotations()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +180,8 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
// returns a new map that contain all the entries of the original map
|
||||
// but with the keys prefixed
|
||||
// if the prefix is null or empty, the map itself is returned (unchanged of course)
|
||||
private Map<String, String> getMapWithPrefixedKeys(Map<String, String> map, String prefix) {
|
||||
private Map<String, String> getMapWithPrefixedKeys(Map<String, String> map,
|
||||
String prefix) {
|
||||
if (map == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
@@ -188,14 +199,16 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public List<String> getServices() {
|
||||
String spelExpression = properties.getFilter();
|
||||
String spelExpression = this.properties.getFilter();
|
||||
Predicate<Service> filteredServices;
|
||||
if (spelExpression == null || spelExpression.isEmpty()) {
|
||||
filteredServices = (Service instance) -> true;
|
||||
} else {
|
||||
Expression filterExpr = parser.parseExpression(spelExpression);
|
||||
}
|
||||
else {
|
||||
Expression filterExpr = this.parser.parseExpression(spelExpression);
|
||||
filteredServices = (Service instance) -> {
|
||||
Boolean include = filterExpr.getValue(evalCtxt, instance, Boolean.class);
|
||||
Boolean include = filterExpr.getValue(this.evalCtxt, instance,
|
||||
Boolean.class);
|
||||
if (include == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -206,11 +219,8 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
}
|
||||
|
||||
public List<String> getServices(Predicate<Service> filter) {
|
||||
return kubernetesClientServicesFunction.apply(client).list()
|
||||
.getItems()
|
||||
.stream()
|
||||
.filter(filter)
|
||||
.map(s -> s.getMetadata().getName())
|
||||
return this.kubernetesClientServicesFunction.apply(this.client).list().getItems()
|
||||
.stream().filter(filter).map(s -> s.getMetadata().getName())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,12 +12,12 @@
|
||||
* 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;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -28,21 +28,28 @@ import org.springframework.cloud.kubernetes.registry.KubernetesServiceRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Auto configuration for discovery clients.
|
||||
*
|
||||
* @author Mauricio Salatino
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name="spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class,
|
||||
CommonsClientAutoConfiguration.class, })
|
||||
CommonsClientAutoConfiguration.class })
|
||||
public class KubernetesDiscoveryClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DefaultIsServicePortSecureResolver isServicePortSecureResolver(KubernetesDiscoveryProperties properties) {
|
||||
public DefaultIsServicePortSecureResolver isServicePortSecureResolver(
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
return new DefaultIsServicePortSecureResolver(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KubernetesClientServicesFunction servicesFunction(KubernetesDiscoveryProperties properties) {
|
||||
if (properties.getServiceLabels().isEmpty()) {
|
||||
public KubernetesClientServicesFunction servicesFunction(
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
if (properties.getServiceLabels().isEmpty()) {
|
||||
return KubernetesClient::services;
|
||||
}
|
||||
|
||||
@@ -51,12 +58,13 @@ public class KubernetesDiscoveryClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.enabled",matchIfMissing = true)
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.enabled", matchIfMissing = true)
|
||||
public KubernetesDiscoveryClient kubernetesDiscoveryClient(KubernetesClient client,
|
||||
KubernetesDiscoveryProperties properties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction,
|
||||
DefaultIsServicePortSecureResolver isServicePortSecureResolver) {
|
||||
return new KubernetesDiscoveryClient(client, properties, kubernetesClientServicesFunction, isServicePortSecureResolver);
|
||||
KubernetesDiscoveryProperties properties,
|
||||
KubernetesClientServicesFunction kubernetesClientServicesFunction,
|
||||
DefaultIsServicePortSecureResolver isServicePortSecureResolver) {
|
||||
return new KubernetesDiscoveryClient(client, properties,
|
||||
kubernetesClientServicesFunction, isServicePortSecureResolver);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -66,7 +74,7 @@ public class KubernetesDiscoveryClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public KubernetesRegistration getRegistration(KubernetesClient client,
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
return new KubernetesRegistration(client, properties);
|
||||
}
|
||||
|
||||
@@ -81,4 +89,5 @@ public class KubernetesDiscoveryClientAutoConfiguration {
|
||||
public KubernetesCatalogWatch kubernetesCatalogWatch(KubernetesClient client) {
|
||||
return new KubernetesCatalogWatch(client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -21,8 +21,15 @@ import org.springframework.cloud.kubernetes.KubernetesAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Bootstrap config for Kubernetes discovery config client.
|
||||
*
|
||||
* @author Zhanwei Wang
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled")
|
||||
@Import({KubernetesAutoConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class, })
|
||||
public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration {}
|
||||
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
|
||||
@Import({ KubernetesAutoConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class })
|
||||
public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,20 +12,24 @@
|
||||
* 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 org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Kubernetes discovery properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.kubernetes.discovery")
|
||||
public class KubernetesDiscoveryProperties {
|
||||
|
||||
@@ -36,23 +40,30 @@ public class KubernetesDiscoveryProperties {
|
||||
@Value("${spring.application.name:unknown}")
|
||||
private String serviceName = "unknown";
|
||||
|
||||
/** SpEL expression to filter services AFTER they have been retrieved from the Kubernetes API server. */
|
||||
/**
|
||||
* SpEL expression to filter services AFTER they have been retrieved from the
|
||||
* Kubernetes API server.
|
||||
*/
|
||||
private String filter;
|
||||
|
||||
/** Set the port numbers that are considered secure and use HTTPS. */
|
||||
private Set<Integer> knownSecurePorts = new HashSet<Integer>() {
|
||||
{
|
||||
add(443);
|
||||
add(8443);
|
||||
}
|
||||
};
|
||||
|
||||
/** Set the port numbers that are considered secure and use HTTPS */
|
||||
private Set<Integer> knownSecurePorts = new HashSet<Integer>() {{
|
||||
add(443);
|
||||
add(8443);
|
||||
}};
|
||||
|
||||
/** If set, then only the services matching these labels will be fetched from the Kubernetes API server */
|
||||
/**
|
||||
* If set, then only the services matching these labels will be fetched from the
|
||||
* Kubernetes API server.
|
||||
*/
|
||||
private Map<String, String> serviceLabels = new HashMap<>();
|
||||
|
||||
private Metadata metadata = new Metadata();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
@@ -60,7 +71,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
return this.serviceName;
|
||||
}
|
||||
|
||||
public void setServiceName(String serviceName) {
|
||||
@@ -68,15 +79,15 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public String getFilter() {
|
||||
return filter;
|
||||
return this.filter;
|
||||
}
|
||||
|
||||
public void setFilter(String filter){
|
||||
public void setFilter(String filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public Set<Integer> getKnownSecurePorts() {
|
||||
return knownSecurePorts;
|
||||
return this.knownSecurePorts;
|
||||
}
|
||||
|
||||
public void setKnownSecurePorts(Set<Integer> knownSecurePorts) {
|
||||
@@ -84,7 +95,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public Map<String, String> getServiceLabels() {
|
||||
return serviceLabels;
|
||||
return this.serviceLabels;
|
||||
}
|
||||
|
||||
public void setServiceLabels(Map<String, String> serviceLabels) {
|
||||
@@ -92,7 +103,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public Metadata getMetadata() {
|
||||
return metadata;
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Metadata metadata) {
|
||||
@@ -101,37 +112,56 @@ public class KubernetesDiscoveryProperties {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)
|
||||
.append("enabled", enabled)
|
||||
.append("serviceName", serviceName)
|
||||
.append("filter", filter)
|
||||
.append("knownSecurePorts", knownSecurePorts)
|
||||
.append("serviceLabels", serviceLabels)
|
||||
.append("metadata", metadata)
|
||||
.toString();
|
||||
return new ToStringCreator(this).append("enabled", this.enabled)
|
||||
.append("serviceName", this.serviceName).append("filter", this.filter)
|
||||
.append("knownSecurePorts", this.knownSecurePorts)
|
||||
.append("serviceLabels", this.serviceLabels)
|
||||
.append("metadata", this.metadata).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata properties.
|
||||
*/
|
||||
public class Metadata {
|
||||
/** When set, the Kubernetes labels of the services will be included as metadata of the returned ServiceInstance. */
|
||||
|
||||
/**
|
||||
* When set, the Kubernetes labels of the services will be included as metadata of
|
||||
* the returned ServiceInstance.
|
||||
*/
|
||||
private boolean addLabels = true;
|
||||
|
||||
/** When addLabels is set, then this will be used as a prefix to the key names in the metadata map. */
|
||||
/**
|
||||
* When addLabels is set, then this will be used as a prefix to the key names in
|
||||
* the metadata map.
|
||||
*/
|
||||
private String labelsPrefix;
|
||||
|
||||
/** When set, the Kubernetes annotations of the services will be included as metadata of the returned ServiceInstance. */
|
||||
/**
|
||||
* When set, the Kubernetes annotations of the services will be included as
|
||||
* metadata of the returned ServiceInstance.
|
||||
*/
|
||||
private boolean addAnnotations = true;
|
||||
|
||||
/** When addAnnotations is set, then this will be used as a prefix to the key names in the metadata map. */
|
||||
/**
|
||||
* When addAnnotations is set, then this will be used as a prefix to the key names
|
||||
* in the metadata map.
|
||||
*/
|
||||
private String annotationsPrefix;
|
||||
|
||||
/** When set, any named Kubernetes service ports will be included as metadata of the returned ServiceInstance. */
|
||||
/**
|
||||
* When set, any named Kubernetes service ports will be included as metadata of
|
||||
* the returned ServiceInstance.
|
||||
*/
|
||||
private boolean addPorts = true;
|
||||
|
||||
/** When addPorts is set, then this will be used as a prefix to the key names in the metadata map. */
|
||||
/**
|
||||
* When addPorts is set, then this will be used as a prefix to the key names in
|
||||
* the metadata map.
|
||||
*/
|
||||
private String portsPrefix = "port.";
|
||||
|
||||
public boolean isAddLabels() {
|
||||
return addLabels;
|
||||
return this.addLabels;
|
||||
}
|
||||
|
||||
public void setAddLabels(boolean addLabels) {
|
||||
@@ -139,7 +169,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public String getLabelsPrefix() {
|
||||
return labelsPrefix;
|
||||
return this.labelsPrefix;
|
||||
}
|
||||
|
||||
public void setLabelsPrefix(String labelsPrefix) {
|
||||
@@ -147,7 +177,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public boolean isAddAnnotations() {
|
||||
return addAnnotations;
|
||||
return this.addAnnotations;
|
||||
}
|
||||
|
||||
public void setAddAnnotations(boolean addAnnotations) {
|
||||
@@ -155,7 +185,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public String getAnnotationsPrefix() {
|
||||
return annotationsPrefix;
|
||||
return this.annotationsPrefix;
|
||||
}
|
||||
|
||||
public void setAnnotationsPrefix(String annotationsPrefix) {
|
||||
@@ -163,7 +193,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public boolean isAddPorts() {
|
||||
return addPorts;
|
||||
return this.addPorts;
|
||||
}
|
||||
|
||||
public void setAddPorts(boolean addPorts) {
|
||||
@@ -171,7 +201,7 @@ public class KubernetesDiscoveryProperties {
|
||||
}
|
||||
|
||||
public String getPortsPrefix() {
|
||||
return portsPrefix;
|
||||
return this.portsPrefix;
|
||||
}
|
||||
|
||||
public void setPortsPrefix(String portsPrefix) {
|
||||
@@ -180,14 +210,14 @@ public class KubernetesDiscoveryProperties {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)
|
||||
.append("addLabels", addLabels)
|
||||
.append("labelsPrefix", labelsPrefix)
|
||||
.append("addAnnotations", addAnnotations)
|
||||
.append("annotationsPrefix", annotationsPrefix)
|
||||
.append("addPorts", addPorts)
|
||||
.append("portsPrefix", portsPrefix)
|
||||
.toString();
|
||||
return new ToStringCreator(this).append("addLabels", this.addLabels)
|
||||
.append("labelsPrefix", this.labelsPrefix)
|
||||
.append("addAnnotations", this.addAnnotations)
|
||||
.append("annotationsPrefix", this.annotationsPrefix)
|
||||
.append("addPorts", this.addPorts)
|
||||
.append("portsPrefix", this.portsPrefix).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -23,25 +22,34 @@ import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointAddress;
|
||||
import io.fabric8.kubernetes.api.model.EndpointPort;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
|
||||
/**
|
||||
* Kubernetes {@link ServiceInstance}.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public class KubernetesServiceInstance implements ServiceInstance {
|
||||
|
||||
private static final String HTTP_PREFIX = "http://";
|
||||
|
||||
private static final String HTTPS_PREFIX = "https://";
|
||||
|
||||
private static final String COLN = ":";
|
||||
|
||||
private final String serviceId;
|
||||
|
||||
private final EndpointAddress endpointAddress;
|
||||
|
||||
private final EndpointPort endpointPort;
|
||||
|
||||
private final Boolean secure;
|
||||
|
||||
private final Map<String, String> metadata;
|
||||
|
||||
public KubernetesServiceInstance(String serviceId,
|
||||
EndpointAddress endpointAddress,
|
||||
EndpointPort endpointPort,
|
||||
Map<String, String> metadata,
|
||||
Boolean secure) {
|
||||
public KubernetesServiceInstance(String serviceId, EndpointAddress endpointAddress,
|
||||
EndpointPort endpointPort, Map<String, String> metadata, Boolean secure) {
|
||||
this.serviceId = serviceId;
|
||||
this.endpointAddress = endpointAddress;
|
||||
this.endpointPort = endpointPort;
|
||||
@@ -51,22 +59,22 @@ public class KubernetesServiceInstance implements ServiceInstance {
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
return this.serviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return endpointAddress.getIp();
|
||||
return this.endpointAddress.getIp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return endpointPort.getPort();
|
||||
return this.endpointPort.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return secure;
|
||||
return this.secure;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,19 +83,22 @@ public class KubernetesServiceInstance implements ServiceInstance {
|
||||
|
||||
if (isSecure()) {
|
||||
sb.append(HTTPS_PREFIX);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sb.append(HTTP_PREFIX);
|
||||
}
|
||||
|
||||
sb.append(getHost()).append(COLN).append(getPort());
|
||||
try {
|
||||
return new URI(sb.toString());
|
||||
} catch (URISyntaxException e) {
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -22,6 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
|
||||
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
|
||||
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration;
|
||||
@@ -31,11 +31,16 @@ import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
public class KubernetesAutoServiceRegistration implements AutoServiceRegistration,
|
||||
SmartLifecycle,
|
||||
Ordered {
|
||||
/**
|
||||
* Auto service registration for Kubernetes.
|
||||
*
|
||||
* @author Mauricio Salatino
|
||||
*/
|
||||
public class KubernetesAutoServiceRegistration
|
||||
implements AutoServiceRegistration, SmartLifecycle, Ordered {
|
||||
|
||||
private static final Log log = LogFactory.getLog(KubernetesAutoServiceRegistration.class);
|
||||
private static final Log log = LogFactory
|
||||
.getLog(KubernetesAutoServiceRegistration.class);
|
||||
|
||||
private AtomicBoolean running = new AtomicBoolean(false);
|
||||
|
||||
@@ -50,8 +55,8 @@ public class KubernetesAutoServiceRegistration implements AutoServiceRegistratio
|
||||
private KubernetesRegistration registration;
|
||||
|
||||
public KubernetesAutoServiceRegistration(ApplicationContext context,
|
||||
KubernetesServiceRegistry serviceRegistry,
|
||||
KubernetesRegistration registration) {
|
||||
KubernetesServiceRegistry serviceRegistry,
|
||||
KubernetesRegistration registration) {
|
||||
this.context = context;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
this.registration = registration;
|
||||
@@ -73,8 +78,7 @@ public class KubernetesAutoServiceRegistration implements AutoServiceRegistratio
|
||||
this.serviceRegistry.register(this.registration);
|
||||
|
||||
this.context.publishEvent(
|
||||
new InstanceRegisteredEvent<>(this,
|
||||
this.registration.getProperties()));
|
||||
new InstanceRegisteredEvent<>(this, this.registration.getProperties()));
|
||||
this.running.set(true);
|
||||
}
|
||||
|
||||
@@ -105,16 +109,16 @@ public class KubernetesAutoServiceRegistration implements AutoServiceRegistratio
|
||||
int localPort = event.getWebServer().getPort();
|
||||
if (this.port.get() == 0) {
|
||||
log.info("Updating port to " + localPort);
|
||||
this.port.compareAndSet(0,
|
||||
localPort);
|
||||
this.port.compareAndSet(0, localPort);
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener(ContextClosedEvent.class)
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == context) {
|
||||
if (event.getApplicationContext() == this.context) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -25,18 +24,25 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.kubernetes.discovery.KubernetesDiscoveryProperties;
|
||||
|
||||
/**
|
||||
* Kubernetes implementation of a {@link Registration}.
|
||||
*
|
||||
* @author Mauricio Salatino
|
||||
*/
|
||||
public class KubernetesRegistration implements Registration, Closeable {
|
||||
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
private KubernetesDiscoveryProperties properties;
|
||||
|
||||
private AtomicBoolean running = new AtomicBoolean(false);
|
||||
|
||||
public KubernetesRegistration(KubernetesClient client,
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
KubernetesDiscoveryProperties properties) {
|
||||
this.client = client;
|
||||
this.properties = properties;
|
||||
}
|
||||
@@ -48,12 +54,12 @@ public class KubernetesRegistration implements Registration, Closeable {
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return properties.getServiceName();
|
||||
return this.properties.getServiceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return client.getMasterUrl().getHost();
|
||||
return this.client.getMasterUrl().getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,15 +75,16 @@ public class KubernetesRegistration implements Registration, Closeable {
|
||||
@Override
|
||||
public URI getUri() {
|
||||
try {
|
||||
return client.getMasterUrl().toURI();
|
||||
} catch (URISyntaxException e) {
|
||||
return this.client.getMasterUrl().toURI();
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public KubernetesDiscoveryProperties getProperties() {
|
||||
return properties;
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,10 +94,8 @@ public class KubernetesRegistration implements Registration, Closeable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KubernetesRegistration{" +
|
||||
"client=" + client +
|
||||
", properties=" + properties +
|
||||
", running=" + running +
|
||||
'}';
|
||||
return "KubernetesRegistration{" + "client=" + this.client + ", properties="
|
||||
+ this.properties + ", running=" + this.running + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,16 +12,22 @@
|
||||
* 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;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||
|
||||
public class KubernetesServiceRegistry implements ServiceRegistry<KubernetesRegistration> {
|
||||
/**
|
||||
* Kubernetes {@link ServiceRegistry}.
|
||||
*
|
||||
* @author Mauricio Salatino
|
||||
*/
|
||||
public class KubernetesServiceRegistry
|
||||
implements ServiceRegistry<KubernetesRegistration> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(KubernetesServiceRegistry.class);
|
||||
|
||||
@@ -44,15 +50,15 @@ public class KubernetesServiceRegistry implements ServiceRegistry<KubernetesRegi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(KubernetesRegistration registration,
|
||||
String status) {
|
||||
public void setStatus(KubernetesRegistration registration, String status) {
|
||||
log.info("Set Status for : " + registration + " Status: " + status);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getStatus(KubernetesRegistration registration) {
|
||||
log.info("Get Status for : " + registration );
|
||||
log.info("Get Status for : " + registration);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.discovery.KubernetesDiscoveryClientAutoConfiguration
|
||||
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.discovery.KubernetesDiscoveryClientConfigClientBootstrapConfiguration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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
|
||||
@@ -23,9 +22,10 @@ import io.fabric8.kubernetes.api.model.ServiceListBuilder
|
||||
import io.fabric8.kubernetes.client.Config
|
||||
import io.fabric8.kubernetes.client.KubernetesClient
|
||||
import io.fabric8.kubernetes.server.mock.KubernetesMockServer
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat
|
||||
|
||||
@@ -40,10 +40,12 @@ class KubernetesDiscoveryClientTest extends Specification {
|
||||
mockClient = mockServer.createClient()
|
||||
|
||||
//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_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")
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
@@ -52,156 +54,186 @@ class KubernetesDiscoveryClientTest extends Specification {
|
||||
|
||||
def "getInstances should be able to handle endpoints single address"() {
|
||||
given:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint").andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
mockServer.expect().get().
|
||||
withPath("/api/v1/namespaces/test/endpoints/endpoint").
|
||||
andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.addNewAddress()
|
||||
.withIp("ip1")
|
||||
.withIp("ip1")
|
||||
.endAddress()
|
||||
.addNewPort("http",80,"TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
.addNewPort("http", 80, "TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
|
||||
and:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint").andReturn(200, new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("l", "v")
|
||||
}})
|
||||
.endMetadata()
|
||||
.build()).once()
|
||||
mockServer.expect().get().
|
||||
withPath("/api/v1/namespaces/test/services/endpoint").
|
||||
andReturn(200, new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("l", "v")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.build()).once()
|
||||
|
||||
final properties = new KubernetesDiscoveryProperties()
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient, properties, {client -> client.services()}, new DefaultIsServicePortSecureResolver(properties))
|
||||
mockClient, properties, { client ->
|
||||
client.services()
|
||||
}, new DefaultIsServicePortSecureResolver(properties))
|
||||
|
||||
when:
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
|
||||
then:
|
||||
instances != null
|
||||
instances.size() == 1
|
||||
instances.find({s -> s.host == "ip1" && !s.secure})
|
||||
instances != null
|
||||
instances.size() == 1
|
||||
instances.find({ s -> s.host == "ip1" && !s.secure })
|
||||
}
|
||||
|
||||
|
||||
|
||||
def "getInstances should be able to handle endpoints multiple addresses"() {
|
||||
given:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint").andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
mockServer.expect().get().
|
||||
withPath("/api/v1/namespaces/test/endpoints/endpoint").
|
||||
andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.addNewAddress()
|
||||
.withIp("ip1")
|
||||
.withIp("ip1")
|
||||
.endAddress()
|
||||
.addNewAddress()
|
||||
.withIp("ip2")
|
||||
.withIp("ip2")
|
||||
.endAddress()
|
||||
.addNewPort("https",443,"TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
.addNewPort("https", 443, "TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
|
||||
and:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint").andReturn(200, new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("l", "v")
|
||||
}})
|
||||
.endMetadata()
|
||||
.build()).once()
|
||||
mockServer.expect().get().
|
||||
withPath("/api/v1/namespaces/test/services/endpoint").
|
||||
andReturn(200, new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("l", "v")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.build()).once()
|
||||
|
||||
final properties = new KubernetesDiscoveryProperties()
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient, properties, {client -> client.services()}, new DefaultIsServicePortSecureResolver(properties))
|
||||
mockClient, properties, { client ->
|
||||
client.services()
|
||||
}, new DefaultIsServicePortSecureResolver(properties))
|
||||
|
||||
when:
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
|
||||
then:
|
||||
instances != null
|
||||
instances.size() == 2
|
||||
instances.find({s -> s.host == "ip1" && s.secure})
|
||||
instances.find({s -> s.host == "ip2" && s.secure})
|
||||
instances != null
|
||||
instances.size() == 2
|
||||
instances.find({ s -> s.host == "ip1" && s.secure })
|
||||
instances.find({ s -> s.host == "ip2" && s.secure })
|
||||
|
||||
}
|
||||
|
||||
def "getServices should return all services when no labels are applied to the client"() {
|
||||
given:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services").andReturn(200, new ServiceListBuilder()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s1")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("label", "value")
|
||||
}})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s2")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("label", "value")
|
||||
put("label2", "value2")
|
||||
}})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s3")
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.build()).once()
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services").
|
||||
andReturn(200, new ServiceListBuilder()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s1")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("label", "value")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s2")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("label", "value")
|
||||
put("label2", "value2")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s3")
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.build()).once()
|
||||
|
||||
and:
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient, new KubernetesDiscoveryProperties(), {client -> client.services()})
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient, new KubernetesDiscoveryProperties(), { client ->
|
||||
client.services()
|
||||
})
|
||||
|
||||
when:
|
||||
List<String> instances = discoveryClient.getServices()
|
||||
List<String> instances = discoveryClient.getServices()
|
||||
|
||||
then:
|
||||
assertThat(instances).containsOnly("s1", "s2", "s3")
|
||||
assertThat(instances).containsOnly("s1", "s2", "s3")
|
||||
}
|
||||
|
||||
def "getServices should return only matching services when labels are applied to the client"() {
|
||||
given:
|
||||
// this is the URL that is created by the KubernetesClient when a a label named 'label'
|
||||
// with a value of 'value' is specified
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services?labelSelector=label%3Dvalue").andReturn(200, new ServiceListBuilder()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s1")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("label", "value")
|
||||
}})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s2")
|
||||
.withLabels(new HashMap<String, String>() {{
|
||||
put("label", "value")
|
||||
put("label2", "value2")
|
||||
}})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.build()).once()
|
||||
// this is the URL that is created by the KubernetesClient when a a label named 'label'
|
||||
// with a value of 'value' is specified
|
||||
mockServer.expect().get().
|
||||
withPath("/api/v1/namespaces/test/services?labelSelector=label%3Dvalue").
|
||||
andReturn(200, new ServiceListBuilder()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s1")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("label", "value")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.addNewItem()
|
||||
.withNewMetadata()
|
||||
.withName("s2")
|
||||
.withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("label", "value")
|
||||
put("label2", "value2")
|
||||
}
|
||||
})
|
||||
.endMetadata()
|
||||
.endItem()
|
||||
.build()).once()
|
||||
|
||||
and:
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient,
|
||||
new KubernetesDiscoveryProperties(), {client -> client.services().withLabels(["label": "value"])})
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(
|
||||
mockClient,
|
||||
new KubernetesDiscoveryProperties(), { client ->
|
||||
client.services().withLabels(["label": "value"])
|
||||
})
|
||||
|
||||
when:
|
||||
List<String> instances = discoveryClient.getServices()
|
||||
List<String> instances = discoveryClient.getServices()
|
||||
|
||||
then:
|
||||
assertThat(instances).containsOnly("s1", "s2")
|
||||
assertThat(instances).containsOnly("s1", "s2")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,70 +12,74 @@
|
||||
* 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 org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class DefaultIsServicePortSecureResolverTest {
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testPortNumbersOnly() {
|
||||
final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties();
|
||||
properties.getKnownSecurePorts().add(12345);
|
||||
|
||||
final DefaultIsServicePortSecureResolver sut = new DefaultIsServicePortSecureResolver(properties);
|
||||
final DefaultIsServicePortSecureResolver sut = new DefaultIsServicePortSecureResolver(
|
||||
properties);
|
||||
|
||||
assertFalse(sut.resolve(new DefaultIsServicePortSecureResolver.Input(null, "dummy")));
|
||||
assertFalse(sut.resolve(new DefaultIsServicePortSecureResolver.Input(8080, "dummy")));
|
||||
assertFalse(sut.resolve(new DefaultIsServicePortSecureResolver.Input(1234, "dummy")));
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(null, "dummy")))
|
||||
.isFalse();
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(8080, "dummy")))
|
||||
.isFalse();
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(1234, "dummy")))
|
||||
.isFalse();
|
||||
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(443, "dummy")));
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(8443, "dummy")));
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(12345, "dummy")));
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(443, "dummy")))
|
||||
.isTrue();
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(8443, "dummy")))
|
||||
.isTrue();
|
||||
assertThat(
|
||||
sut.resolve(new DefaultIsServicePortSecureResolver.Input(12345, "dummy")))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelsAndAnnotations() {
|
||||
final DefaultIsServicePortSecureResolver sut
|
||||
= new DefaultIsServicePortSecureResolver(new KubernetesDiscoveryProperties());
|
||||
final DefaultIsServicePortSecureResolver sut = new DefaultIsServicePortSecureResolver(
|
||||
new KubernetesDiscoveryProperties());
|
||||
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(
|
||||
8080,
|
||||
"dummy",
|
||||
new HashMap<String, String>() {{
|
||||
put("secured", "true");
|
||||
put("other", "value");
|
||||
}},
|
||||
new HashMap<>()))
|
||||
);
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(
|
||||
1234,
|
||||
"dummy",
|
||||
new HashMap<String, String>() {{
|
||||
put("other", "value");
|
||||
put("secured", "1");
|
||||
}},
|
||||
new HashMap<>()))
|
||||
);
|
||||
assertTrue(sut.resolve(new DefaultIsServicePortSecureResolver.Input(
|
||||
4321,
|
||||
"dummy",
|
||||
new HashMap<>(),
|
||||
new HashMap<String, String>() {{
|
||||
put("other1", "value1");
|
||||
put("secured", "yes");
|
||||
put("other2", "value2");
|
||||
}}))
|
||||
);
|
||||
assertThat(sut.resolve(new DefaultIsServicePortSecureResolver.Input(8080, "dummy",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("secured", "true");
|
||||
put("other", "value");
|
||||
}
|
||||
}, new HashMap<>()))).isTrue();
|
||||
assertThat(sut.resolve(new DefaultIsServicePortSecureResolver.Input(1234, "dummy",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("other", "value");
|
||||
put("secured", "1");
|
||||
}
|
||||
}, new HashMap<>()))).isTrue();
|
||||
assertThat(sut.resolve(new DefaultIsServicePortSecureResolver.Input(4321, "dummy",
|
||||
new HashMap<>(), new HashMap<String, String>() {
|
||||
{
|
||||
put("other1", "value1");
|
||||
put("secured", "yes");
|
||||
put("other2", "value2");
|
||||
}
|
||||
}))).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -20,6 +19,7 @@ package org.springframework.cloud.kubernetes.discovery;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
@@ -27,7 +27,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -47,31 +47,29 @@ public class KubernetesCatalogServicesWatchConfigurationTest {
|
||||
@Test
|
||||
public void kubernetesCatalogWatchDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false");
|
||||
assertFalse(context.containsBean("kubernetesCatalogWatch"));
|
||||
assertThat(this.context.containsBean("kubernetesCatalogWatch")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void kubernetesCatalogWatchWhenKubernetesDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.enabled=false");
|
||||
assertFalse(context.containsBean("kubernetesCatalogWatch"));
|
||||
assertThat(this.context.containsBean("kubernetesCatalogWatch")).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void kubernetesCatalogWatchDefaultEnabled() throws Exception {
|
||||
setup();
|
||||
assertTrue(context.containsBean("kubernetesCatalogWatch"));
|
||||
assertThat(this.context.containsBean("kubernetesCatalogWatch")).isTrue();
|
||||
}
|
||||
|
||||
private void setup(String... env) {
|
||||
this.context = new SpringApplicationBuilder(
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class).web(WebApplicationType.NONE)
|
||||
.properties(env).run();
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class)
|
||||
.web(WebApplicationType.NONE).properties(env).run();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class KubernetesClientTestConfiguration {
|
||||
|
||||
@@ -80,6 +78,6 @@ public class KubernetesCatalogServicesWatchConfigurationTest {
|
||||
return mock(KubernetesClient.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,12 +12,21 @@
|
||||
* 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.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.DoneableEndpoints;
|
||||
import io.fabric8.kubernetes.api.model.EndpointAddress;
|
||||
import io.fabric8.kubernetes.api.model.EndpointSubset;
|
||||
import io.fabric8.kubernetes.api.model.Endpoints;
|
||||
import io.fabric8.kubernetes.api.model.EndpointsList;
|
||||
import io.fabric8.kubernetes.api.model.ObjectReference;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.dsl.MixedOperation;
|
||||
import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
@@ -29,19 +38,15 @@ import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Oleg Vyukov
|
||||
@@ -66,52 +71,57 @@ public class KubernetesCatalogWatchTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
underTest.setApplicationEventPublisher(applicationEventPublisher);
|
||||
this.underTest.setApplicationEventPublisher(this.applicationEventPublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomOrderChangePods() throws Exception {
|
||||
when(endpointsOperation.list())
|
||||
.thenReturn(createSingleEndpointEndpointListByPodName("api-pod", "other-pod"))
|
||||
.thenReturn(createSingleEndpointEndpointListByPodName("other-pod", "api-pod"));
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list())
|
||||
.thenReturn(
|
||||
createSingleEndpointEndpointListByPodName("api-pod", "other-pod"))
|
||||
.thenReturn(createSingleEndpointEndpointListByPodName("other-pod",
|
||||
"api-pod"));
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
// second execution on shuffleServices
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
verify(this.applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomOrderChangeServices() throws Exception {
|
||||
when(endpointsOperation.list())
|
||||
.thenReturn(createEndpointsListByServiceName("api-service", "other-service"))
|
||||
.thenReturn(createEndpointsListByServiceName("other-service", "api-service"));
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list())
|
||||
.thenReturn(
|
||||
createEndpointsListByServiceName("api-service", "other-service"))
|
||||
.thenReturn(
|
||||
createEndpointsListByServiceName("other-service", "api-service"));
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
// second execution on shuffleServices
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
verify(this.applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventBody() throws Exception {
|
||||
when(endpointsOperation.list())
|
||||
.thenReturn(createSingleEndpointEndpointListByPodName("api-pod", "other-pod"));
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list()).thenReturn(
|
||||
createSingleEndpointEndpointListByPodName("api-pod", "other-pod"));
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(heartbeatEventArgumentCaptor.capture());
|
||||
verify(this.applicationEventPublisher)
|
||||
.publishEvent(this.heartbeatEventArgumentCaptor.capture());
|
||||
|
||||
HeartbeatEvent event = heartbeatEventArgumentCaptor.getValue();
|
||||
assertThat(event.getValue(), instanceOf(List.class));
|
||||
HeartbeatEvent event = this.heartbeatEventArgumentCaptor.getValue();
|
||||
assertThat(event.getValue()).isInstanceOf(List.class);
|
||||
|
||||
List<String> expectedPodsList = Arrays.asList("api-pod", "other-pod");
|
||||
assertEquals(expectedPodsList, event.getValue());
|
||||
assertThat(event.getValue()).isEqualTo(expectedPodsList);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,14 +129,14 @@ public class KubernetesCatalogWatchTest {
|
||||
|
||||
EndpointsList endpoints = createSingleEndpointEndpointListWithoutSubsets();
|
||||
|
||||
when(endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
// second execution on shuffleServices
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
verify(this.applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,37 +145,37 @@ public class KubernetesCatalogWatchTest {
|
||||
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
|
||||
endpoints.getItems().get(0).getSubsets().get(0).setAddresses(null);
|
||||
|
||||
when(endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
// second execution on shuffleServices
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
verify(this.applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndpointsWithoutTargetRefs() {
|
||||
|
||||
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
|
||||
endpoints.getItems().get(0).getSubsets().get(0).getAddresses().get(0).setTargetRef(null);
|
||||
endpoints.getItems().get(0).getSubsets().get(0).getAddresses().get(0)
|
||||
.setTargetRef(null);
|
||||
|
||||
when(endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsOperation.list()).thenReturn(endpoints);
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
// second execution on shuffleServices
|
||||
underTest.catalogServicesWatch();
|
||||
this.underTest.catalogServicesWatch();
|
||||
|
||||
verify(applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
verify(this.applicationEventPublisher).publishEvent(any(HeartbeatEvent.class));
|
||||
}
|
||||
|
||||
|
||||
private EndpointsList createEndpointsListByServiceName(String... serviceNames) {
|
||||
List<Endpoints> endpoints = stream(serviceNames)
|
||||
.map(s -> createEndpointsByPodName(s + "-singlePodUniqueId"))
|
||||
.collect(Collectors.toList());
|
||||
.map(s -> createEndpointsByPodName(s + "-singlePodUniqueId"))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
EndpointsList endpointsList = new EndpointsList();
|
||||
endpointsList.setItems(endpoints);
|
||||
@@ -189,14 +199,12 @@ public class KubernetesCatalogWatchTest {
|
||||
return endpointsList;
|
||||
}
|
||||
|
||||
|
||||
private Endpoints createEndpointsByPodName(String podName) {
|
||||
Endpoints endpoints = new Endpoints();
|
||||
endpoints.setSubsets(createSubsetsByPodName(podName));
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
|
||||
private List<EndpointSubset> createSubsetsByPodName(String... names) {
|
||||
EndpointSubset endpointSubset = new EndpointSubset();
|
||||
endpointSubset.setAddresses(createEndpointAddressByPodNames(names));
|
||||
@@ -213,5 +221,4 @@ public class KubernetesCatalogWatchTest {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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;
|
||||
@@ -29,35 +45,35 @@ public class KubernetesDiscoveryClientAutoConfigurationPropertiesTests {
|
||||
|
||||
@Test
|
||||
public void kubernetesDiscoveryDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.discovery.enabled=false","spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false");
|
||||
assertThat(context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.isEmpty();
|
||||
setup("spring.cloud.kubernetes.discovery.enabled=false",
|
||||
"spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false");
|
||||
assertThat(this.context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void kubernetesDiscoveryWhenKubernetesDisabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.enabled=false");
|
||||
assertThat(context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void kubernetesDiscoveryDefaultEnabled() throws Exception {
|
||||
setup("spring.cloud.kubernetes.enabled=true");
|
||||
assertThat(context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeanNamesForType(KubernetesDiscoveryClient.class))
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
private void setup(String... env) {
|
||||
this.context = new SpringApplicationBuilder(
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class).web(org.springframework.boot.WebApplicationType.NONE)
|
||||
.properties(env).run();
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class)
|
||||
.web(org.springframework.boot.WebApplicationType.NONE)
|
||||
.properties(env).run();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class KubernetesClientTestConfiguration {
|
||||
|
||||
@@ -66,6 +82,6 @@ public class KubernetesDiscoveryClientAutoConfigurationPropertiesTests {
|
||||
return mock(KubernetesClient.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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;
|
||||
@@ -40,15 +39,18 @@ public class KubernetesDiscoveryClientAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void kubernetesDiscoveryClientCreated() {
|
||||
assertThat(discoveryClient).isNotNull()
|
||||
.isInstanceOf(CompositeDiscoveryClient.class);
|
||||
assertThat(this.discoveryClient).isNotNull()
|
||||
.isInstanceOf(CompositeDiscoveryClient.class);
|
||||
|
||||
CompositeDiscoveryClient composite = (CompositeDiscoveryClient) discoveryClient;
|
||||
CompositeDiscoveryClient composite = (CompositeDiscoveryClient) this.discoveryClient;
|
||||
assertThat(composite.getDiscoveryClients().stream()
|
||||
.anyMatch(dc -> dc instanceof KubernetesDiscoveryClient)).isTrue();
|
||||
.anyMatch(dc -> dc instanceof KubernetesDiscoveryClient)).isTrue();
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
protected static class TestConfig {}
|
||||
protected static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 java.util.Collections;
|
||||
@@ -44,6 +44,7 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Zhanwei Wang
|
||||
*/
|
||||
public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
@@ -59,17 +60,15 @@ public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
|
||||
@Test
|
||||
public void onWhenRequested() throws Exception {
|
||||
setup("server.port=7000", "spring.cloud.config.discovery.enabled=true",
|
||||
"spring.cloud.kubernetes.discovery.enabled:true",
|
||||
"spring.cloud.kubernetes.enabled:true",
|
||||
"spring.application.name:test",
|
||||
"spring.cloud.config.discovery.service-id:configserver");
|
||||
assertEquals( 1, this.context.getParent()
|
||||
.getBeanNamesForType(DiscoveryClient.class).length);
|
||||
DiscoveryClient client = this.context.getParent().getBean(
|
||||
DiscoveryClient.class);
|
||||
"spring.cloud.kubernetes.discovery.enabled:true",
|
||||
"spring.cloud.kubernetes.enabled:true", "spring.application.name:test",
|
||||
"spring.cloud.config.discovery.service-id:configserver");
|
||||
assertEquals(1, this.context.getParent()
|
||||
.getBeanNamesForType(DiscoveryClient.class).length);
|
||||
DiscoveryClient client = this.context.getParent().getBean(DiscoveryClient.class);
|
||||
verify(client, atLeast(2)).getInstances("configserver");
|
||||
ConfigClientProperties locator = this.context
|
||||
.getBean(ConfigClientProperties.class);
|
||||
.getBean(ConfigClientProperties.class);
|
||||
assertEquals("http://fake:8888/", locator.getUri()[0]);
|
||||
}
|
||||
|
||||
@@ -77,16 +76,16 @@ public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
TestPropertyValues.of(env).applyTo(parent);
|
||||
parent.register(UtilAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, EnvironmentKnobbler.class,
|
||||
KubernetesDiscoveryClientConfigClientBootstrapConfiguration.class,
|
||||
DiscoveryClientConfigServiceBootstrapConfiguration.class,
|
||||
ConfigClientProperties.class);
|
||||
PropertyPlaceholderAutoConfiguration.class, EnvironmentKnobbler.class,
|
||||
KubernetesDiscoveryClientConfigClientBootstrapConfiguration.class,
|
||||
DiscoveryClientConfigServiceBootstrapConfiguration.class,
|
||||
ConfigClientProperties.class);
|
||||
parent.refresh();
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.setParent(parent);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesAutoConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class);
|
||||
KubernetesAutoConfiguration.class,
|
||||
KubernetesDiscoveryClientAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
@@ -97,10 +96,12 @@ public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
|
||||
public KubernetesDiscoveryClient kubernetesDiscoveryClient() {
|
||||
KubernetesDiscoveryClient client = mock(KubernetesDiscoveryClient.class);
|
||||
ServiceInstance instance = new DefaultServiceInstance("configserver1",
|
||||
"configserver", "fake", 8888, false);
|
||||
"configserver", "fake", 8888, false);
|
||||
given(client.getInstances("configserver"))
|
||||
.willReturn(Collections.singletonList(instance));
|
||||
.willReturn(Collections.singletonList(instance));
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,10 +12,14 @@
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.DoneableEndpoints;
|
||||
import io.fabric8.kubernetes.api.model.DoneableService;
|
||||
import io.fabric8.kubernetes.api.model.EndpointPort;
|
||||
@@ -38,11 +42,8 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -83,26 +84,28 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
public void testAllExtraMetadataDisabled() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(false);
|
||||
when(metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(metadata.isAddPorts()).thenReturn(false);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(false);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "lab");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "lab");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "lab");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "lab");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).isEmpty();
|
||||
}
|
||||
@@ -111,144 +114,159 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
public void testLabelsEnabled() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(true);
|
||||
when(metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(metadata.isAddPorts()).thenReturn(false);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(true);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
put("l2", "v2");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "lab");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
put("l2", "v2");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "lab");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("l1", "v1"), entry("l2", "v2"));
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("l1", "v1"),
|
||||
entry("l2", "v2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelsEnabledWithPrefix() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(true);
|
||||
when(metadata.getLabelsPrefix()).thenReturn("l_");
|
||||
when(metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(metadata.isAddPorts()).thenReturn(false);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(true);
|
||||
when(this.metadata.getLabelsPrefix()).thenReturn("l_");
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
put("l2", "v2");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "lab");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}});
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
put("l2", "v2");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "lab");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("l_l1", "v1"), entry("l_l2", "v2"));
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("l_l1", "v1"),
|
||||
entry("l_l2", "v2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationsEnabled() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(false);
|
||||
when(metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(metadata.isAddPorts()).thenReturn(false);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(false);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("a1", "v1"), entry("a2", "v2"));
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("a1", "v1"),
|
||||
entry("a2", "v2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationsEnabledWithPrefix() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(false);
|
||||
when(metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(metadata.getAnnotationsPrefix()).thenReturn("a_");
|
||||
when(metadata.isAddPorts()).thenReturn(false);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(false);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(this.metadata.getAnnotationsPrefix()).thenReturn("a_");
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("a_a1", "v1"), entry("a_a2", "v2"));
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("a_a1", "v1"),
|
||||
entry("a_a2", "v2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPortsEnabled() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(false);
|
||||
when(metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(metadata.isAddPorts()).thenReturn(true);
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(false);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("http", "80"));
|
||||
}
|
||||
@@ -257,28 +275,30 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
public void testPortsEnabledWithPrefix() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(false);
|
||||
when(metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(metadata.isAddPorts()).thenReturn(true);
|
||||
when(metadata.getPortsPrefix()).thenReturn("p_");
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(false);
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
when(this.metadata.getPortsPrefix()).thenReturn("p_");
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "v1");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("a1", "v1");
|
||||
put("a2", "v2");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("p_http", "80"));
|
||||
}
|
||||
@@ -287,90 +307,77 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
public void testLabelsAndAnnotationsAndPortsEnabledWithPrefix() {
|
||||
final String serviceId = "s";
|
||||
|
||||
when(properties.getMetadata()).thenReturn(metadata);
|
||||
when(metadata.isAddLabels()).thenReturn(true);
|
||||
when(metadata.getLabelsPrefix()).thenReturn("l_");
|
||||
when(metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(metadata.getAnnotationsPrefix()).thenReturn("a_");
|
||||
when(metadata.isAddPorts()).thenReturn(true);
|
||||
when(metadata.getPortsPrefix()).thenReturn("p_");
|
||||
when(this.properties.getMetadata()).thenReturn(this.metadata);
|
||||
when(this.metadata.isAddLabels()).thenReturn(true);
|
||||
when(this.metadata.getLabelsPrefix()).thenReturn("l_");
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(this.metadata.getAnnotationsPrefix()).thenReturn("a_");
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
when(this.metadata.getPortsPrefix()).thenReturn("p_");
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(
|
||||
serviceId,
|
||||
new HashMap<String, String>() {{
|
||||
put("l1", "la1");
|
||||
}},
|
||||
new HashMap<String, String>() {{
|
||||
put("a1", "an1");
|
||||
put("a2", "an2");
|
||||
}},
|
||||
new HashMap<Integer, String>() {{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}}
|
||||
);
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "la1");
|
||||
}
|
||||
}, new HashMap<String, String>() {
|
||||
{
|
||||
put("a1", "an1");
|
||||
put("a2", "an2");
|
||||
}
|
||||
}, new HashMap<Integer, String>() {
|
||||
{
|
||||
put(80, "http");
|
||||
put(5555, "");
|
||||
}
|
||||
});
|
||||
|
||||
final List<ServiceInstance> instances = underTest.getInstances(serviceId);
|
||||
final List<ServiceInstance> instances = this.underTest.getInstances(serviceId);
|
||||
assertThat(instances).hasSize(1);
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(
|
||||
entry("a_a1", "an1"), entry("a_a2", "an2"), entry("l_l1", "la1"), entry("p_http", "80"));
|
||||
assertThat(instances.get(0).getMetadata()).containsOnly(entry("a_a1", "an1"),
|
||||
entry("a_a2", "an2"), entry("l_l1", "la1"), entry("p_http", "80"));
|
||||
}
|
||||
|
||||
private void setupServiceWithLabelsAndAnnotationsAndPorts(String serviceId,
|
||||
Map<String, String> labels, Map<String, String> annotations, Map<Integer, String> ports) {
|
||||
final Service service =
|
||||
new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withLabels(labels)
|
||||
.withAnnotations(annotations)
|
||||
.endMetadata()
|
||||
.withNewSpec()
|
||||
.withPorts(getServicePorts(ports))
|
||||
.endSpec()
|
||||
.build();
|
||||
when(serviceOperation.withName(serviceId)).thenReturn(serviceResource);
|
||||
when(serviceResource.get()).thenReturn(service);
|
||||
when(kubernetesClient.services()).thenReturn(serviceOperation);
|
||||
Map<String, String> labels, Map<String, String> annotations,
|
||||
Map<Integer, String> ports) {
|
||||
final Service service = new ServiceBuilder().withNewMetadata().withLabels(labels)
|
||||
.withAnnotations(annotations).endMetadata().withNewSpec()
|
||||
.withPorts(getServicePorts(ports)).endSpec().build();
|
||||
when(this.serviceOperation.withName(serviceId)).thenReturn(this.serviceResource);
|
||||
when(this.serviceResource.get()).thenReturn(service);
|
||||
when(this.kubernetesClient.services()).thenReturn(this.serviceOperation);
|
||||
|
||||
final Endpoints endpoints =
|
||||
new EndpointsBuilder()
|
||||
.addNewSubset()
|
||||
.addAllToPorts(getEndpointPorts(ports))
|
||||
.addNewAddress()
|
||||
.endAddress()
|
||||
.endSubset()
|
||||
.build();
|
||||
final Endpoints endpoints = new EndpointsBuilder().addNewSubset()
|
||||
.addAllToPorts(getEndpointPorts(ports)).addNewAddress().endAddress()
|
||||
.endSubset().build();
|
||||
|
||||
when(endpointsResource.get()).thenReturn(endpoints);
|
||||
when(endpointsOperation.withName(serviceId)).thenReturn(endpointsResource);
|
||||
when(kubernetesClient.endpoints()).thenReturn(endpointsOperation);
|
||||
when(this.endpointsResource.get()).thenReturn(endpoints);
|
||||
when(this.endpointsOperation.withName(serviceId))
|
||||
.thenReturn(this.endpointsResource);
|
||||
when(this.kubernetesClient.endpoints()).thenReturn(this.endpointsOperation);
|
||||
}
|
||||
|
||||
private List<ServicePort> getServicePorts(Map<Integer, String> ports) {
|
||||
return ports.entrySet().stream()
|
||||
.map(e -> {
|
||||
ServicePortBuilder servicePortBuilder = new ServicePortBuilder();
|
||||
servicePortBuilder.withPort(e.getKey());
|
||||
if (!Strings.isNullOrEmpty(e.getValue())) {
|
||||
servicePortBuilder.withName(e.getValue());
|
||||
}
|
||||
return servicePortBuilder.build();
|
||||
})
|
||||
.collect(toList());
|
||||
return ports.entrySet().stream().map(e -> {
|
||||
ServicePortBuilder servicePortBuilder = new ServicePortBuilder();
|
||||
servicePortBuilder.withPort(e.getKey());
|
||||
if (!Strings.isNullOrEmpty(e.getValue())) {
|
||||
servicePortBuilder.withName(e.getValue());
|
||||
}
|
||||
return servicePortBuilder.build();
|
||||
}).collect(toList());
|
||||
}
|
||||
|
||||
private List<EndpointPort> getEndpointPorts(Map<Integer, String> ports) {
|
||||
return ports.entrySet().stream()
|
||||
.map(e -> {
|
||||
EndpointPortBuilder endpointPortBuilder = new EndpointPortBuilder();
|
||||
endpointPortBuilder.withPort(e.getKey());
|
||||
if (!Strings.isNullOrEmpty(e.getValue())) {
|
||||
endpointPortBuilder.withName(e.getValue());
|
||||
}
|
||||
return endpointPortBuilder.build();
|
||||
})
|
||||
.collect(toList());
|
||||
return ports.entrySet().stream().map(e -> {
|
||||
EndpointPortBuilder endpointPortBuilder = new EndpointPortBuilder();
|
||||
endpointPortBuilder.withPort(e.getKey());
|
||||
if (!Strings.isNullOrEmpty(e.getValue())) {
|
||||
endpointPortBuilder.withName(e.getValue());
|
||||
}
|
||||
return endpointPortBuilder.build();
|
||||
}).collect(toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* Copyright 2013-2019 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.
|
||||
@@ -12,8 +12,8 @@
|
||||
* 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 java.util.ArrayList;
|
||||
@@ -30,13 +30,10 @@ import io.fabric8.kubernetes.client.dsl.ServiceResource;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -57,7 +54,8 @@ public class KubernetesDiscoveryClientFilterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
underTest = new KubernetesDiscoveryClient(kubernetesClient, properties, kubernetesClientServicesFunction);
|
||||
this.underTest = new KubernetesDiscoveryClient(this.kubernetesClient,
|
||||
this.properties, this.kubernetesClientServicesFunction);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,22 +72,23 @@ public class KubernetesDiscoveryClientFilterTest {
|
||||
|
||||
ServiceList serviceList = new ServiceList();
|
||||
serviceList.setItems(services);
|
||||
when(serviceOperation.list())
|
||||
.thenReturn(serviceList);
|
||||
when(kubernetesClient.services()).thenReturn(serviceOperation);
|
||||
when(this.serviceOperation.list()).thenReturn(serviceList);
|
||||
when(this.kubernetesClient.services()).thenReturn(this.serviceOperation);
|
||||
|
||||
when(properties.getFilter()).thenReturn("metadata.additionalProperties['spring-boot']");
|
||||
when(this.properties.getFilter())
|
||||
.thenReturn("metadata.additionalProperties['spring-boot']");
|
||||
|
||||
List<String> filteredServices = underTest.getServices();
|
||||
List<String> filteredServices = this.underTest.getServices();
|
||||
|
||||
System.out.println("Filtered Services: " + filteredServices);
|
||||
assertEquals(springBootServiceNames, filteredServices);
|
||||
assertThat(filteredServices).isEqualTo(springBootServiceNames);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilteredServicesByPrefix() {
|
||||
List<String> springBootServiceNames = Arrays.asList("serviceA", "serviceB", "serviceC");
|
||||
List<String> springBootServiceNames = Arrays.asList("serviceA", "serviceB",
|
||||
"serviceC");
|
||||
List<Service> services = createSpringBootServiceByName(springBootServiceNames);
|
||||
|
||||
// Add non spring boot service
|
||||
@@ -101,36 +100,36 @@ public class KubernetesDiscoveryClientFilterTest {
|
||||
|
||||
ServiceList serviceList = new ServiceList();
|
||||
serviceList.setItems(services);
|
||||
when(serviceOperation.list())
|
||||
.thenReturn(serviceList);
|
||||
when(kubernetesClient.services()).thenReturn(serviceOperation);
|
||||
when(this.serviceOperation.list()).thenReturn(serviceList);
|
||||
when(this.kubernetesClient.services()).thenReturn(this.serviceOperation);
|
||||
|
||||
when(properties.getFilter()).thenReturn("metadata.name.startsWith('service')");
|
||||
when(this.properties.getFilter())
|
||||
.thenReturn("metadata.name.startsWith('service')");
|
||||
|
||||
List<String> filteredServices = underTest.getServices();
|
||||
List<String> filteredServices = this.underTest.getServices();
|
||||
|
||||
System.out.println("Filtered Services: " + filteredServices);
|
||||
assertEquals(springBootServiceNames, filteredServices);
|
||||
assertThat(filteredServices).isEqualTo(springBootServiceNames);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoExpression() {
|
||||
List<String> springBootServiceNames = Arrays.asList("serviceA", "serviceB", "serviceC");
|
||||
List<String> springBootServiceNames = Arrays.asList("serviceA", "serviceB",
|
||||
"serviceC");
|
||||
List<Service> services = createSpringBootServiceByName(springBootServiceNames);
|
||||
|
||||
ServiceList serviceList = new ServiceList();
|
||||
serviceList.setItems(services);
|
||||
when(serviceOperation.list())
|
||||
.thenReturn(serviceList);
|
||||
when(kubernetesClient.services()).thenReturn(serviceOperation);
|
||||
when(this.serviceOperation.list()).thenReturn(serviceList);
|
||||
when(this.kubernetesClient.services()).thenReturn(this.serviceOperation);
|
||||
|
||||
when(properties.getFilter()).thenReturn("");
|
||||
when(this.properties.getFilter()).thenReturn("");
|
||||
|
||||
List<String> filteredServices = underTest.getServices();
|
||||
List<String> filteredServices = this.underTest.getServices();
|
||||
|
||||
System.out.println("Filtered Services: " + filteredServices);
|
||||
assertEquals(springBootServiceNames, filteredServices);
|
||||
assertThat(filteredServices).isEqualTo(springBootServiceNames);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,58 +16,58 @@
|
||||
~
|
||||
-->
|
||||
|
||||
<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>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>kubernetes-circuitbreaker-ribbon-example</artifactId>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>kubernetes-circuitbreaker-ribbon-example</artifactId>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>greeting-service</artifactId>
|
||||
<name>Circuit Breaker & Load Balancer :: Greeting Service</name>
|
||||
<description>Circuit Breaker & Load Balancer :: Greeting Service</description>
|
||||
<artifactId>greeting-service</artifactId>
|
||||
<name>Circuit Breaker & Load Balancer :: Greeting Service</name>
|
||||
<description>Circuit Breaker & Load Balancer :: Greeting Service</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -35,18 +35,20 @@ public class GreetingController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint to get a greeting. This endpoint uses a name server to get a name for the greeting.
|
||||
* Endpoint to get a greeting. This endpoint uses a name server to get a name for the
|
||||
* greeting.
|
||||
*
|
||||
* Request to the name service is guarded with a circuit breaker. Therefore if a name service is not available or is too
|
||||
* slow to response fallback name is used.
|
||||
* Request to the name service is guarded with a circuit breaker. Therefore if a name
|
||||
* service is not available or is too slow to response fallback name is used.
|
||||
*
|
||||
* Delay parameter can me used to make name service response slower.
|
||||
*
|
||||
* @param delay Milliseconds for how long the response from name service should be delayed.
|
||||
* @param delay Milliseconds for how long the response from name service should be
|
||||
* delayed.
|
||||
* @return Greeting string.
|
||||
*/
|
||||
@RequestMapping("/greeting")
|
||||
public String getGreeting(@RequestParam(value = "delay", defaultValue = "0") int delay) {
|
||||
public String getGreeting(
|
||||
@RequestParam(value = "delay", defaultValue = "0") int delay) {
|
||||
return String.format("Hello from %s!", this.nameService.getName(delay));
|
||||
}
|
||||
|
||||
|
||||
@@ -47,4 +47,3 @@ public class GreetingServiceApplication {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ public class NameService {
|
||||
}
|
||||
|
||||
@HystrixCommand(fallbackMethod = "getFallbackName", commandProperties = {
|
||||
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
|
||||
})
|
||||
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") })
|
||||
public String getName(int delay) {
|
||||
return this.restTemplate.getForObject(String.format("http://name-service/name?delay=%d", delay), String.class);
|
||||
return this.restTemplate.getForObject(
|
||||
String.format("http://name-service/name?delay=%d", delay), String.class);
|
||||
}
|
||||
|
||||
private String getFallbackName(int delay) {
|
||||
|
||||
@@ -36,10 +36,10 @@ public class RibbonConfiguration {
|
||||
IClientConfig ribbonClientConfig;
|
||||
|
||||
/**
|
||||
* PingUrl will ping a URL to check the status of each server.
|
||||
* Say Hello has, as you’ll recall, a method mapped to the /path; that means that Ribbon will get an HTTP 200 response when it pings a running Backend Server
|
||||
*
|
||||
* @param config Client configuration
|
||||
* PingUrl will ping a URL to check the status of each server. Say Hello has, as
|
||||
* you’ll recall, a method mapped to the /path; that means that Ribbon will get an
|
||||
* HTTP 200 response when it pings a running Backend Server
|
||||
* @param config Client configuration
|
||||
* @return The URL to be used for the Ping
|
||||
*/
|
||||
@Bean
|
||||
@@ -48,14 +48,16 @@ public class RibbonConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* AvailabilityFilteringRule will use Ribbon’s built-in circuit breaker functionality to filter out any servers in an “open-circuit” state:
|
||||
* if a ping fails to connect to a given server, or if it gets a read failure for the server, Ribbon will consider that server “dead” until it begins to respond normally.
|
||||
*
|
||||
* @param config Client configuration
|
||||
* AvailabilityFilteringRule will use Ribbon’s built-in circuit breaker functionality
|
||||
* to filter out any servers in an “open-circuit” state: if a ping fails to connect to
|
||||
* a given server, or if it gets a read failure for the server, Ribbon will consider
|
||||
* that server “dead” until it begins to respond normally.
|
||||
* @param config Client configuration
|
||||
* @return The Load Balancer rule
|
||||
*/
|
||||
@Bean
|
||||
public IRule ribbonRule(IClientConfig config) {
|
||||
return new AvailabilityFilteringRule();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ backend:
|
||||
eureka:
|
||||
enabled: false
|
||||
client:
|
||||
enabled: true
|
||||
enabled: true
|
||||
ServerListRefreshInterval: 5000
|
||||
|
||||
hystrix.command.BackendCall.execution.isolation.thread.timeoutInMilliseconds: 5000
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user