Initial commit
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = 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
|
||||
138
.flattened-pom.xml
Normal file
138
.flattened-pom.xml
Normal file
@@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2020 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
|
||||
~
|
||||
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.0.4-SNAPSHOT</version>
|
||||
<relativePath></relativePath>
|
||||
</parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Kubernetes</name>
|
||||
<description>Spring Cloud parent pom, managing plugins and dependencies for Spring
|
||||
Cloud projects</description>
|
||||
<url>https://cloud.spring.io</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dsyer</id>
|
||||
<name>Dave Syer</name>
|
||||
<email>dsyer at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sgibb</id>
|
||||
<name>Spencer Gibb</name>
|
||||
<email>sgibb at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mgrzejszczak</id>
|
||||
<name>Marcin Grzejszczak</name>
|
||||
<email>mgrzejszczak at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rbaxter</id>
|
||||
<name>Ryan Baxter</name>
|
||||
<email>rbaxter at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>omaciaszeksharma</id>
|
||||
<name>Olga Maciaszek-Sharma</name>
|
||||
<email>omaciaszeksharma at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes</url>
|
||||
</scm>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
17
.github/ISSUE_TEMPLATE/bug_report.md
vendored
17
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,17 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
Please provide details of the problem, including the version of Spring Cloud that you
|
||||
are using.
|
||||
|
||||
**Sample**
|
||||
If possible, please provide a test case or sample application that reproduces
|
||||
the problem. This makes it much easier for us to diagnose the problem and to verify that
|
||||
we have fixed it.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,11 +0,0 @@
|
||||
name: build controllers project
|
||||
description: build controllers project
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: build controllers project
|
||||
shell: bash
|
||||
run: |
|
||||
cd spring-cloud-kubernetes-controllers
|
||||
.././mvnw -T 1C -U clean install
|
||||
cd ..
|
||||
@@ -1,17 +0,0 @@
|
||||
name: build integration tests project without tests
|
||||
description: build integration tests project without tests
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: build integration tests project without tests
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
cd spring-cloud-kubernetes-test-support
|
||||
.././mvnw clean install -U
|
||||
cd ..
|
||||
|
||||
cd spring-cloud-kubernetes-integration-tests
|
||||
# build the images, but dont run the tests
|
||||
.././mvnw -T 1C clean install -DskipTests
|
||||
cd ..
|
||||
15
.github/workflows/composites/cache/action.yaml
vendored
15
.github/workflows/composites/cache/action.yaml
vendored
@@ -1,15 +0,0 @@
|
||||
name: cache
|
||||
description: cache
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
|
||||
- uses: Wandalen/wretry.action@master
|
||||
with:
|
||||
attempt_limit: 3
|
||||
action: buildjet/cache@v3
|
||||
with: |
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-cache-${{ env.BRANCH_NAME }}-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-cache-${{ env.BRANCH_NAME }}-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
name: clean space
|
||||
description: clean space
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: apt-update
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
- name: Free Disk Space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: true
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
swap-storage: true
|
||||
@@ -1,24 +0,0 @@
|
||||
name: sets environment variables
|
||||
description: sets environment variables
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: set env variables
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
baseRef=$GITHUB_BASE_REF
|
||||
if [[ ! -z $baseRef ]]; then
|
||||
echo "This is a PR to branch : $baseRef"
|
||||
echo "BASE_BRANCH=$(echo $baseRef)" >> $GITHUB_ENV
|
||||
else
|
||||
raw=${{ github.ref }}
|
||||
echo "${raw}"
|
||||
branch=${raw##*/}
|
||||
echo "This is a merge to branch : ${branch}"
|
||||
echo "BASE_BRANCH=$(echo ${branch})" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
echo "BRANCH_NAME=$(echo $GITHUB_HEAD_REF)" >> $GITHUB_ENV
|
||||
echo "BASE_BRANCH_NAME=$(echo $GITHUB_BASE_REF)" >> $GITHUB_ENV
|
||||
echo "DOCKER_IMAGES_KEY=$(echo $GITHUB_RUN_ID)" >> $GITHUB_ENV
|
||||
@@ -1,129 +0,0 @@
|
||||
########################################### find test times #######################################
|
||||
# when cache of test times is present, compute matrix steps
|
||||
# we do this because the number of steps required in a matrix is not stable
|
||||
# it is computed as sum_of_times_of_all_tests / max_time_of_a_single_test
|
||||
# For example if there is no test times cache, we will be using 32 steps in the matrix
|
||||
# on the other hand if cache is present, we might need less steps:
|
||||
|
||||
# sum_of_times_of_all_tests = 8000 seconds
|
||||
# max_time_of_a_single_test = 400
|
||||
# we would require 20 steps in the matrix, as having 32 would make no sense
|
||||
# because one step will run around 400 seconds and others will wait for this one to finish
|
||||
# as they finish earlier
|
||||
|
||||
name: matrix bounds on test times cache hit
|
||||
description: matrix bounds on test times cache hit
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
|
||||
- name: restore test times cache
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: /tmp/sorted.txt
|
||||
key: ${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-
|
||||
|
||||
- name: show cached test times
|
||||
shell: bash
|
||||
run: cat /tmp/sorted.txt
|
||||
|
||||
- name: compute matrix steps
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
PLAIN_TEST_CLASSNAMES=($(cat /tmp/tests.txt | grep -o 'spring.cloud.k8s.test.to.run -> org.*' | awk '{print $3}'))
|
||||
|
||||
#######################################################################################################
|
||||
### split into tests that we know the running times for and in tests that we do not know the times for.
|
||||
#######################################################################################################
|
||||
for test in "${PLAIN_TEST_CLASSNAMES[@]}"; do
|
||||
|
||||
find_test_in_sorted=$(grep "$test " /tmp/sorted.txt || true)
|
||||
if [[ -z "$find_test_in_sorted" ]]; then
|
||||
echo $test >> /tmp/tests-without-times.txt
|
||||
else
|
||||
echo $find_test_in_sorted >> /tmp/tests-with-times.txt
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
sort -t' ' -nk2 /tmp/tests-with-times.txt >> /tmp/tests-with-times-sorted.txt
|
||||
|
||||
# this is a work-around for the fact that 'actions/download-artifact@v3' does not support
|
||||
# something like: 'ignore if downloaded file is missing'.
|
||||
# so unless we create a dummy file for upload, download will fail
|
||||
if [[ ! -f /tmp/tests-without-times.txt ]]; then touch /tmp/tests-without-times.txt; fi
|
||||
|
||||
echo '--------------------------------------------------------------'
|
||||
cat /tmp/tests-with-times-sorted.txt
|
||||
echo '--------------------------------------------------------------'
|
||||
cat /tmp/tests-without-times.txt
|
||||
echo '--------------------------------------------------------------'
|
||||
|
||||
|
||||
sum_of_all_tests=$(awk -F' ' '{sum+=$2;} END{print sum;}' /tmp/tests-with-times-sorted.txt)
|
||||
sum_of_all_tests_as_int=$(printf "%.0f\n" "$sum_of_all_tests")
|
||||
echo "sum of all tests : $sum_of_all_tests_as_int"
|
||||
|
||||
max_test_time=$(tail -1 /tmp/tests-with-times-sorted.txt | awk '{print $2}')
|
||||
max_test_time_as_int=$(printf "%.0f\n" "$max_test_time")
|
||||
echo "max test time : $max_test_time_as_int"
|
||||
|
||||
number_of_instances=$(( $sum_of_all_tests_as_int / $max_test_time_as_int ))
|
||||
|
||||
number_of_instances_as_array=()
|
||||
number_of_instances_as_array+='['
|
||||
number_of_instances_as_array+=$number_of_instances
|
||||
number_of_instances_as_array+=']'
|
||||
|
||||
average_time_per_instance=$(( sum_of_all_tests_as_int / $number_of_instances ))
|
||||
average_time_per_instance_array=()
|
||||
average_time_per_instance_array+='['
|
||||
average_time_per_instance_array+=$average_time_per_instance
|
||||
average_time_per_instance_array+=']'
|
||||
|
||||
matrix_array=()
|
||||
matrix_array+='['
|
||||
for ((i=0; i<=${number_of_instances}; i++)); do
|
||||
if (( $i == $(( $number_of_instances )) )); then
|
||||
matrix_array+=$i
|
||||
else
|
||||
matrix_array+=$i,
|
||||
fi
|
||||
done
|
||||
|
||||
matrix_array+=']'
|
||||
|
||||
echo "********************************************************************************************************"
|
||||
echo "number of instances : $number_of_instances_as_array"
|
||||
echo "average_time_per_instance_as_array: $average_time_per_instance_as_array"
|
||||
echo "matrix_array : $matrix_array"
|
||||
echo "********************************************************************************************************"
|
||||
|
||||
number_of_instances_json=$(jq -r -c . <<< $number_of_instances_as_array)
|
||||
echo "number_of_instances_json : $number_of_instances_json"
|
||||
|
||||
matrix_array_json=$(jq -r -c . <<< $matrix_array)
|
||||
echo "matrix_array_json : $matrix_array_json"
|
||||
|
||||
average_time_per_instance_json=$(jq -r -c . <<< $average_time_per_instance_array)
|
||||
echo "average_time_per_instance_json : $average_time_per_instance_json"
|
||||
|
||||
echo "TEST_TIMES_CACHE_PRESENT=true" >> $GITHUB_ENV
|
||||
echo "NUMBER_OF_MATRIX_INSTANCES=$(echo $number_of_instances_json)" >> $GITHUB_ENV
|
||||
echo "MATRIX_ARRAY=$(echo $matrix_array_json)" >> $GITHUB_ENV
|
||||
echo "AVERAGE_TIME_PER_INSTANCE=$(echo $average_time_per_instance_json)" >> $GITHUB_ENV
|
||||
|
||||
- name: upload test with times
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tests-with-times-sorted.txt
|
||||
path: /tmp/tests-with-times-sorted.txt
|
||||
|
||||
- name: upload test without times
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tests-without-times.txt
|
||||
path: /tmp/tests-without-times.txt
|
||||
@@ -1,37 +0,0 @@
|
||||
name: maven-build-with-dry-run-for-tests
|
||||
description: maven-build-with-dry-run-for-tests
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
|
||||
- name: run 'package' on the project
|
||||
shell: bash
|
||||
run: |
|
||||
./mvnw install -B \
|
||||
-Dskip.build.image=true \
|
||||
-DskipTests -DskipITs \
|
||||
-T 1C -q
|
||||
|
||||
- name: find all classpath entries
|
||||
shell: bash
|
||||
run: |
|
||||
./mvnw -q exec:exec -Dexec.classpathScope="test" -Dexec.executable="echo" -Dexec.args="%classpath" | tr : "\n" > /tmp/deps.txt
|
||||
|
||||
- name: find all tests
|
||||
shell: bash
|
||||
run: |
|
||||
cd spring-cloud-kubernetes-test-support
|
||||
.././mvnw -q exec:java -Prun-on-github-actions -Dexec.mainClass="org.springframework.cloud.kubernetes.tests.discovery.TestsDiscovery" > /tmp/tests.txt
|
||||
cd ..
|
||||
|
||||
- name: show result
|
||||
if: always()
|
||||
shell: bash
|
||||
run: cat /tmp/tests.txt
|
||||
|
||||
- name: upload test
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tests.txt
|
||||
path: /tmp/tests.txt
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# common steps before running actula tests for both
|
||||
# when a cache of test times is presen and when it is not present
|
||||
|
||||
name: pre-test-actions
|
||||
description: pre-test-actions
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
|
||||
- name: set env variables
|
||||
uses: ./.github/workflows/composites/env-variables
|
||||
|
||||
- name: setup project jdk-17
|
||||
uses: ./.github/workflows/composites/setup-jdk17
|
||||
if: env.BASE_BRANCH == 'main'
|
||||
|
||||
- name: setup project jdk-8
|
||||
uses: ./.github/workflows/composites/setup-jdk1.8
|
||||
if: env.BASE_BRANCH == '2.1.x'
|
||||
|
||||
- name: cache local maven repository
|
||||
uses: ./.github/workflows/composites/cache
|
||||
|
||||
- name: build controllers project
|
||||
uses: ./.github/workflows/composites/build-controllers-project
|
||||
|
||||
- name: build integration tests project
|
||||
uses: ./.github/workflows/composites/build-integration-tests-project
|
||||
|
||||
- name: download tests
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tests.txt
|
||||
path: /tmp
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
########################################### find test times #######################################
|
||||
# 1. find files that look like this: 'org.springframework.xxx.txt', these files are generated
|
||||
# by surefire-plugin when tests run.
|
||||
# 2. extract the time it took to run a certain test (from the above .txt file)
|
||||
# 3. create a file that contains test times from this current matrix
|
||||
|
||||
name: run and save test times when cache missing
|
||||
description: run and save test times when cache missing
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
|
||||
- name: run and save test times
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
# take only likes that look like :
|
||||
# 'spring.cloud.k8s.test.to.run -> org.springframework.cloud.kubernetes.fabric8.discovery.ServicePortSecureResolverTest'
|
||||
PLAIN_TEST_CLASSNAMES=($(cat /tmp/tests.txt | grep -o 'spring.cloud.k8s.test.to.run -> org.*' | awk '{print $3}'))
|
||||
IFS=$'\n'
|
||||
SORTED_TEST_CLASSNAMES=( $(sort <<< "${PLAIN_TEST_CLASSNAMES[*]}") )
|
||||
unset IFS
|
||||
|
||||
start_from_name=start_from_${CURRENT_INDEX}
|
||||
how_many_name=how_many_${CURRENT_INDEX}
|
||||
|
||||
start_from=${!start_from_name}
|
||||
how_many=${!how_many_name}
|
||||
|
||||
echo "${SORTED_TEST_CLASSNAMES[@]}"
|
||||
echo "$start_from_name : ${start_from}"
|
||||
echo "$how_many_name : ${how_many}"
|
||||
|
||||
sliced_array=(${SORTED_TEST_CLASSNAMES[@]:$start_from:$how_many})
|
||||
|
||||
TEST_ARG=$(echo ${sliced_array[@]} | sed 's/ /,/g')
|
||||
echo "$TEST_ARG"
|
||||
|
||||
if [[ $baseBranch == "2.1.x" ]]; then
|
||||
|
||||
./mvnw -s .settings.xml -pl '-:kubernetes-leader-election-example' -pl '-:kubernetes-hello-world-example' \
|
||||
-pl '-:kubernetes-reload-example' -pl '-:kubernetes-loadbalancer-example' \
|
||||
-pl '-:spring-cloud-kubernetes-configserver' -pl '-:spring-cloud-kubernetes-configuration-watcher' \
|
||||
-pl '-:spring-cloud-kubernetes-discoveryserver' \
|
||||
-DtestsToRun=${TEST_ARG[@]} \
|
||||
-e clean install \
|
||||
-U -P sonar -nsu --batch-mode \
|
||||
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
|
||||
-Dhttp.keepAlive=false \
|
||||
-Dmaven.wagon.http.pool=false \
|
||||
-Dmaven.wagon.http.retryHandler.class=standard \
|
||||
-Dmaven.wagon.http.retryHandler.count=3 \
|
||||
-Dskip.build.image=true
|
||||
|
||||
else
|
||||
|
||||
version=$(java -version)
|
||||
echo "version of java: $version"
|
||||
|
||||
./mvnw -s .settings.xml \
|
||||
-DtestsToRun=${TEST_ARG[@]} \
|
||||
-e clean install \
|
||||
-U -P sonar -nsu --batch-mode \
|
||||
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
|
||||
-Dhttp.keepAlive=false \
|
||||
-Dmaven.wagon.http.pool=false \
|
||||
-Dmaven.wagon.http.retryHandler.class=standard \
|
||||
-Dmaven.wagon.http.retryHandler.count=3 \
|
||||
-Dskip.build.image=true
|
||||
fi
|
||||
|
||||
touch /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
|
||||
for i in "${sliced_array[@]}"; do
|
||||
filename="${i}.txt"
|
||||
echo "searching for filename: ${filename}"
|
||||
file=$(find . -name "${filename}")
|
||||
echo "found file: ${file}"
|
||||
result=$(cat "${file}" | grep 'elapsed' | awk '{print $12, $13}')
|
||||
|
||||
echo "run test: ${i} in : ${result}" >> /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
done
|
||||
|
||||
- name: show individual test times
|
||||
shell: bash
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
run: cat /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
|
||||
- name: upload individual tests
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
path: /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
name: run and save test times when cache present
|
||||
description: run and save test times when cache present
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
|
||||
- name: download tests with times
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tests-with-times-sorted.txt
|
||||
path: /tmp/
|
||||
|
||||
- name: download tests without times
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: tests-without-times.txt
|
||||
path: /tmp/
|
||||
|
||||
- name: split tests into known times and un-known times
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
echo "------------------------------------------------------------------------------"
|
||||
cat /tmp/tests-with-times-sorted.txt
|
||||
echo "------------------------------------------------------------------------------"
|
||||
if [[ -f /tmp/tests-without-times.txt ]]; then cat /tmp/tests-without-times.txt; fi
|
||||
echo "------------------------------------------------------------------------------"
|
||||
|
||||
############################################################################################################
|
||||
############################################################################################################
|
||||
############################################################################################################
|
||||
# For each number_of_instances, iterate from bottom to top ('for ((j=$number_of_lines_in_file; j>0; j--))')
|
||||
# (starting from the test that has the max time). Easier to understand is via an example.
|
||||
# Suppose our /tmp/sorted.txt looks like this (very artificial):
|
||||
# testA 1 sec
|
||||
# testB 2 sec
|
||||
# testC 3 sec
|
||||
|
||||
# average_time_per_instance = 3.1 sec
|
||||
# number_of_lines_in_file = 3
|
||||
|
||||
# we start iterating from bottom to top and first get 'testC' that has a running time of 3 sec
|
||||
# since 3 sec < 3.1 sec ('if [[ $next_sum -lt $average_time_per_instance ]];')
|
||||
# this test needs to be taken in 'tests_to_take_in_current_iteration', thus:
|
||||
# tests_to_take_in_current_iteration=testC; also next_sum becomes 3sec
|
||||
# we then drop this line from /tmp/sorted.txt because we have already processed it
|
||||
# ('sed -i "" "${j}d" /tmp/tests-with-times-sorted.txt')
|
||||
# we also decrement j, since we removed one line from the file
|
||||
|
||||
# we then take testB, add its time to next_sum, thus next_sum = 5 sec, but now the time is NOT < 3.1 sec
|
||||
# This means we do not take testB in current iteration and skip it.
|
||||
|
||||
# Same goes for testA, next_sum = 4 sec, and it is NOT < 3.1 sec
|
||||
# There are no more lines in file to iterate, thus tests_to_take_in_current_iteration=testC
|
||||
|
||||
# we repeat the process again and now tests_to_take_in_current_iteration=testB,testA because their cumulative
|
||||
# sum will be 3 sec and it's < 3.1 sec.
|
||||
|
||||
number_of_instances=${NUMBER_OF_JOBS}
|
||||
echo "number of instances $number_of_instances"
|
||||
|
||||
average_time_per_instance=${AVERAGE_TIME_PER_INSTANCE}
|
||||
echo "average time per instance $average_time_per_instance"
|
||||
|
||||
number_of_lines_in_file=$(grep -c ^ /tmp/tests-with-times-sorted.txt)
|
||||
echo "number of lines in fine : $number_of_lines_in_file"
|
||||
tests_to_run_in_current_index=''
|
||||
|
||||
for ((i=0; i<=${number_of_instances}; i++)) ; do
|
||||
|
||||
sum=0
|
||||
tests_to_take_in_current_iteration=''
|
||||
for ((j=$number_of_lines_in_file; j>0; j--)) ; do
|
||||
|
||||
current_line_in_file=$(awk "NR == ${j}" /tmp/tests-with-times-sorted.txt)
|
||||
current_test_time=$(echo $current_line_in_file | awk '{print $2}')
|
||||
current_test_time=$(printf "%.0f\n" "$current_test_time")
|
||||
current_test_name=$(echo $current_line_in_file | awk '{print $1}')
|
||||
next_sum=$(( $sum + $current_test_time ))
|
||||
|
||||
if [[ $next_sum -lt $average_time_per_instance ]]; then
|
||||
|
||||
sum=$(( $sum + $current_test_time ))
|
||||
|
||||
if [[ -z $tests_to_take_in_current_iteration ]]; then
|
||||
tests_to_take_in_current_iteration="$current_test_name"
|
||||
else
|
||||
tests_to_take_in_current_iteration="$tests_to_take_in_current_iteration,$current_test_name"
|
||||
fi
|
||||
|
||||
sed -i "${j}d" /tmp/tests-with-times-sorted.txt
|
||||
number_of_lines_in_file=$(( $number_of_lines_in_file-1 ))
|
||||
continue
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if [[ $i = ${CURRENT_INDEX} ]]; then
|
||||
echo "current index : ${CURRENT_INDEX}"
|
||||
tests_to_run_in_current_index=$tests_to_take_in_current_iteration
|
||||
echo "time of tests in current index : $sum"
|
||||
|
||||
# this can be the case when we delete some tests in some PR for example
|
||||
# the previous cache will contain more tests then we currently have, so some
|
||||
# matrix instances will have no tests to run
|
||||
if [[ "$sum" -eq "0" ]]; then
|
||||
echo "no tests (with known times) to run in current index"
|
||||
tests_to_run_in_current_index='none'
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# here we compute tests that are "new", these are tests that our cache is not aware of
|
||||
# for example these can come from a new PR where new tests are added
|
||||
# This last step can have already existing tests to run, so we need to be careful to append
|
||||
# new tests here.
|
||||
|
||||
if [[ ${CURRENT_INDEX} = ${NUMBER_OF_JOBS} ]]; then
|
||||
echo "last index spotted"
|
||||
|
||||
if [ ! -f /tmp/tests-without-times.txt ]; then
|
||||
echo "no tests outside cache found"
|
||||
|
||||
if [ -z "$tests_to_run_in_current_index" ]; then
|
||||
echo "no tests to run in the last index"
|
||||
tests_to_run_in_current_index='none'
|
||||
fi
|
||||
|
||||
else
|
||||
TESTS_WITHOUT_TIMES=($(cat /tmp/tests-without-times.txt))
|
||||
|
||||
for test in "${TESTS_WITHOUT_TIMES[@]}"; do
|
||||
if [[ -z "$tests_to_run_in_current_index" ]]; then
|
||||
tests_to_run_in_current_index="$test"
|
||||
else
|
||||
tests_to_run_in_current_index="$tests_to_run_in_current_index,$test"
|
||||
fi
|
||||
done
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "will run tests : $tests_to_run_in_current_index"
|
||||
|
||||
./mvnw -s .settings.xml \
|
||||
-DtestsToRun=${tests_to_run_in_current_index} \
|
||||
-e clean install \
|
||||
-U -P sonar -nsu --batch-mode \
|
||||
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
|
||||
-Dhttp.keepAlive=false \
|
||||
-Dmaven.wagon.http.pool=false \
|
||||
-Dmaven.wagon.http.retryHandler.class=standard \
|
||||
-Dmaven.wagon.http.retryHandler.count=3 \
|
||||
-Dskip.build.image=true
|
||||
|
||||
touch /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
|
||||
# if there are no tests to run in the last index, don't parse anything
|
||||
if [ $tests_to_run_in_current_index != "none" ]; then
|
||||
IFS=',' read -r -a sliced_array <<< "$tests_to_run_in_current_index"
|
||||
unset IFS
|
||||
|
||||
for i in "${sliced_array[@]}"; do
|
||||
|
||||
# can be present in the last index as 'none,testA,testB'
|
||||
if [[ "$i" == "none" ]]; then
|
||||
echo "skipping 'none'"
|
||||
else
|
||||
filename="${i}.txt"
|
||||
echo "searching for filename: ${filename}"
|
||||
file=$(find . -name "${filename}")
|
||||
echo "found file: ${file}"
|
||||
result=$(cat "${file}" | grep 'elapsed' | awk '{print $12, $13}')
|
||||
echo "run test: ${i} in : ${result}" >> /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
|
||||
- name: show individual test times
|
||||
shell: bash
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
run: cat /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
|
||||
- name: upload individual tests
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
path: /tmp/test_times_${{ env.CURRENT_INDEX }}.txt
|
||||
@@ -1,15 +0,0 @@
|
||||
name: save controller docker images
|
||||
description: save controller docker images
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: save controller docker images
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /tmp/docker/images
|
||||
TAG=$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||
cd spring-cloud-kubernetes-controllers
|
||||
while read controller_image; do
|
||||
docker save -o /tmp/docker/images/${controller_image}.tar docker.io/springcloud/${controller_image}:$TAG
|
||||
done < <(mvn -Dexec.executable='echo' -Dexec.args='${project.artifactId}' exec:exec -q | grep -v 'spring-cloud-kubernetes-controllers')
|
||||
cd ..
|
||||
@@ -1,20 +0,0 @@
|
||||
name: save integration tests docker images
|
||||
description: save integration tests docker images
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: save integration tests docker images
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /tmp/docker/images
|
||||
TAG=$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||
cd spring-cloud-kubernetes-integration-tests
|
||||
while read integ_test; do
|
||||
docker save -o /tmp/docker/images/${integ_test}.tar docker.io/springcloud/${integ_test}:$TAG
|
||||
done < <(mvn -Dexec.executable='echo' -Dexec.args='${project.artifactId}' exec:exec -q \
|
||||
| grep -v 'spring-cloud-kubernetes-integration-tests' \
|
||||
| grep -v 'spring-cloud-kubernetes-client-configmap-event-reload-multiple-apps' \
|
||||
| grep -v 'spring-cloud-kubernetes-client-configuration-watcher-configmap-test-app' \
|
||||
| grep -v 'spring-cloud-kubernetes-client-secrets-event-reload-multiple-apps' \
|
||||
| grep -v 'spring-cloud-kubernetes-client-configuration-watcher-secrets-test-app' )
|
||||
cd ..
|
||||
@@ -1,9 +0,0 @@
|
||||
name: setup project with jdk-8
|
||||
description: setup project with jdk-8
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '8'
|
||||
@@ -1,9 +0,0 @@
|
||||
name: setup project with jdk-17
|
||||
description: setup project with jdk-17
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
@@ -1,65 +0,0 @@
|
||||
name: test-bounds
|
||||
description: test-bounds
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: test-bounds
|
||||
shell: bash
|
||||
run: |
|
||||
PLAIN_TEST_CLASSNAMES=($(cat /tmp/tests.txt | grep -o 'spring.cloud.k8s.test.to.run -> org.*' | awk '{print $3}'))
|
||||
NUMBER_OF_TESTS=${#PLAIN_TEST_CLASSNAMES[@]}
|
||||
|
||||
echo "current index : ${CURRENT_INDEX}"
|
||||
echo "total number of tests: ${NUMBER_OF_TESTS} to be run on ${NUMBER_OF_JOBS} instances"
|
||||
|
||||
##########################################################################################################
|
||||
##########################################################################################################
|
||||
# Split tests per instance. The simplest form is when (for example), there are 100 tests and 10 instances.
|
||||
# In this case, we will run 10 tests per a single instance. This is the case when reminder == 0 (100 / 10).
|
||||
# In this case we will compute start_from as = current index * per_instance, that is: 0, 10, 20...
|
||||
# and so on. How many tests are supposed to be taken in each matrix is equal to per_instance, that is 10.
|
||||
|
||||
# Slightly more interesting is when the tests are not perfectly distributed, when reminder != 0.
|
||||
# For example 323 tests on 32 instances. In this case, we logically split this problem in two:
|
||||
# when current_index < reminder and the rest.
|
||||
# The batches in the example above are going to be [0, 11) [11, 22) [22, 33) [33, 43) [43, 53) ...
|
||||
# So when current_index < reminder, we need to start at : current_index * per_instance + current_index,
|
||||
# i.e.: 0, 11, 22
|
||||
# and how many elements to take is : per_instance + 1, i.e. : 11
|
||||
# On the other hand when current_index is not < reminder, how_many is easy, it's equal to per_instance.
|
||||
# start_from on the other hand is : per_instance * current_index + reminder, i.e. : 33, 43, 53 and so on
|
||||
##########################################################################################################
|
||||
##########################################################################################################
|
||||
|
||||
per_instance=$((${NUMBER_OF_TESTS} / ${NUMBER_OF_JOBS}))
|
||||
reminder=$((${NUMBER_OF_TESTS} - ${NUMBER_OF_JOBS} * ${per_instance}))
|
||||
|
||||
start_from=0
|
||||
how_many=0
|
||||
|
||||
if [[ $reminder -eq 0 ]]; then
|
||||
start_from=$(( ${CURRENT_INDEX} * ${per_instance} ))
|
||||
how_many=${per_instance}
|
||||
else
|
||||
if [[ $CURRENT_INDEX -eq 0 ]]; then
|
||||
start_from=0
|
||||
how_many=$(( $per_instance + 1 ))
|
||||
else
|
||||
if [[ $CURRENT_INDEX -lt $reminder ]]; then
|
||||
start_from=$(( $per_instance * $CURRENT_INDEX + $CURRENT_INDEX ))
|
||||
how_many=$(( $per_instance +1 ))
|
||||
else
|
||||
start_from=$(( $per_instance * $CURRENT_INDEX + $reminder ))
|
||||
how_many=$per_instance
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
start_from_name=start_from_${CURRENT_INDEX}
|
||||
how_many_name=how_many_${CURRENT_INDEX}
|
||||
|
||||
echo "$start_from_name : $start_from"
|
||||
echo "$how_many_name : $how_many"
|
||||
|
||||
echo "$start_from_name=$start_from" >> $GITHUB_ENV
|
||||
echo "$how_many_name=$how_many" >> $GITHUB_ENV
|
||||
@@ -1,58 +0,0 @@
|
||||
# this stage sort all tests by their timings. For that we rely on the surefire-plugin reports
|
||||
# that have the name as <TEST_NAME>.txt and inside it there is a field that holds the time it took
|
||||
# We get a hold of that field via awk '{print $12, $13} in the previous step.
|
||||
# That previous step stores only tests for one matrix step, which we uploaded.
|
||||
# In the steps below we download all artifacts (thus all test times), put them into a single file
|
||||
# called /tmp/times-of-all-tests.txt, then sort this file, thus get a histogram of all test names
|
||||
# and the time it took to run them.
|
||||
|
||||
name: test-times
|
||||
description: test-times
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
|
||||
# we omit the name, as such all artifacts are downloaded
|
||||
- name: download all artifacts
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: /tmp/all-artifacts
|
||||
|
||||
- name: show all artifacts
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
shell: bash
|
||||
run: ls -l /tmp/all-artifacts
|
||||
|
||||
- name: merge all artifacts into a single file and sort by time
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
shell: bash
|
||||
run: |
|
||||
arr=($(find /tmp/all-artifacts/ -type f -name "test_times*"))
|
||||
|
||||
for i in "${arr[@]}"; do
|
||||
echo "parsing -> ${i}"
|
||||
cat "${i}" | awk '{print $3" "$6}' >> /tmp/times-of-all-tests.txt
|
||||
done
|
||||
|
||||
sort -t' ' -nk2 /tmp/times-of-all-tests.txt >> /tmp/sorted.txt
|
||||
|
||||
cat /tmp/sorted.txt
|
||||
|
||||
- name: show all tests in a sorted manner
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
shell: bash
|
||||
run: cat /tmp/sorted.txt
|
||||
|
||||
# save with the current run_id, but restore it without it. This means two things:
|
||||
# 1) if we re-run, cache will be available
|
||||
# 2) if there is a new run, we restore as '${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-'
|
||||
# meaning there could be many of them already present and this is not an exact match
|
||||
# github in this case will pick up the latest one, exactly what we want.
|
||||
- name: save test times in cache
|
||||
uses: actions/cache/save@v3
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
with:
|
||||
path: /tmp/sorted.txt
|
||||
key: ${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-${{ github.run_id }}
|
||||
@@ -1,19 +0,0 @@
|
||||
# we are not going to use upload/download actions, since it is slower than cache usage
|
||||
# as key to the cache we are going to use DOCKER_IMAGES_KEY, which is the same as GITHUB_RUN_ID
|
||||
|
||||
name: upload docker images
|
||||
description: upload docker images
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
|
||||
- uses: Wandalen/wretry.action@master
|
||||
with:
|
||||
attempt_limit: 3
|
||||
action: buildjet/cache@v3
|
||||
with: |
|
||||
path: /tmp/docker/images
|
||||
key: docker-images-cache-${{ env.DOCKER_IMAGES_KEY }}
|
||||
restore-keys: docker-images-cache-${{ env.DOCKER_IMAGES_KEY }}
|
||||
|
||||
|
||||
53
.github/workflows/deploy-docs.yml
vendored
Normal file
53
.github/workflows/deploy-docs.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Deploy Docs
|
||||
run-name: ${{ format('{0} ({1})', github.workflow, github.event.inputs.build-refname || 'all') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-refname:
|
||||
description: Enter git refname to build (e.g., 5.7.x).
|
||||
required: false
|
||||
push:
|
||||
branches: docs-build
|
||||
env:
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository_owner == 'spring-cloud'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 5
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Set up refname build
|
||||
if: github.event.inputs.build-refname
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/$GITHUB_REPOSITORY ${{ github.event.inputs.build-refname }}
|
||||
export BUILD_REFNAME=${{ github.event.inputs.build-refname }}
|
||||
echo "BUILD_REFNAME=$BUILD_REFNAME" >> $GITHUB_ENV
|
||||
export BUILD_VERSION=$(git cat-file --textconv FETCH_HEAD:pom.xml | python3 -c "import xml.etree.ElementTree as xml; from sys import stdin; print(xml.parse(stdin).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)")
|
||||
echo BUILD_VERSION=$BUILD_VERSION >> $GITHUB_ENV
|
||||
- name: Run Antora
|
||||
run: |
|
||||
./mvnw --no-transfer-progress -B antora
|
||||
- name: Publish Docs
|
||||
uses: spring-io/spring-doc-actions/rsync-antora-reference@v0.0.11
|
||||
with:
|
||||
docs-username: ${{ secrets.DOCS_USERNAME }}
|
||||
docs-host: ${{ secrets.DOCS_HOST }}
|
||||
docs-ssh-key: ${{ secrets.DOCS_SSH_KEY }}
|
||||
docs-ssh-host-key: ${{ secrets.DOCS_SSH_HOST_KEY }}
|
||||
site-path: target/antora/site
|
||||
- name: Bust Cloudflare Cache
|
||||
uses: spring-io/spring-doc-actions/bust-cloudflare-antora-cache@v0.0.11
|
||||
with:
|
||||
context-root: spring-cloud-kubernetes
|
||||
cloudflare-zone-id: ${{ secrets.CLOUDFLARE_ZONE_ID }}
|
||||
cloudflare-cache-token: ${{ secrets.CLOUDFLARE_CACHE_TOKEN }}
|
||||
223
.github/workflows/maven.yaml
vendored
223
.github/workflows/maven.yaml
vendored
@@ -1,223 +0,0 @@
|
||||
name: github-workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, 2.1.x, 3.0.x ]
|
||||
pull_request:
|
||||
branches: [ main, 2.1.x, 3.0.x ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# this might get set to true if there is an existing cache of test times
|
||||
# this happens in 'matrix-bounds-on-test-times-cache-hit'
|
||||
TEST_TIMES_CACHE_PRESENT: false
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
|
||||
|
||||
# this job ('build') outputs a value from step 'test_times_cache_present_init', that has the name of:
|
||||
# 'test_times_cache_present'. This can later be used by other jobs. For example, we use this one
|
||||
# to skip the job responsible for running the tests, if a previous cache that has the test times is not present.
|
||||
# Same for other two variables 'number_of_matrix_instances' and 'matrix_array'.
|
||||
outputs:
|
||||
test_times_cache_present: ${{ steps.test_times_cache_present_init.outputs.test_times_cache_present }}
|
||||
number_of_matrix_instances: ${{ steps.test_times_cache_present_init.outputs.number_of_matrix_instances }}
|
||||
matrix_array: ${{ steps.test_times_cache_present_init.outputs.matrix_array }}
|
||||
average_time_per_instance: ${{ steps.test_times_cache_present_init.outputs.average_time_per_instance }}
|
||||
steps:
|
||||
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: clean space
|
||||
uses: ./.github/workflows/composites/clean-space
|
||||
|
||||
- name: set env variables
|
||||
uses: ./.github/workflows/composites/env-variables
|
||||
|
||||
- name: setup project jdk-17
|
||||
id: jdk_17
|
||||
uses: ./.github/workflows/composites/setup-jdk17
|
||||
if: env.BASE_BRANCH == 'main' || env.BASE_BRANCH == '3.0.x'
|
||||
|
||||
- name: setup project jdk-8
|
||||
uses: ./.github/workflows/composites/setup-jdk1.8
|
||||
if: env.BASE_BRANCH == '2.1.x'
|
||||
|
||||
- name: cache local maven repository
|
||||
uses: ./.github/workflows/composites/cache
|
||||
|
||||
- name: Show caches
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const caches = await github.rest.actions.getActionsCacheList({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
})
|
||||
for (const cache of caches.data.actions_caches) {
|
||||
console.log(cache)
|
||||
}
|
||||
|
||||
- name: maven build with dry-run for tests
|
||||
uses: ./.github/workflows/composites/maven-build-with-dry-run-for-tests
|
||||
|
||||
- name: restore test times cache if it exists
|
||||
id: restore_test_times_cache
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: /tmp/sorted.txt
|
||||
key: ${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-spring-cloud-k8s-existing-test-times-cache-
|
||||
|
||||
- name: check test times cache exists
|
||||
id: check_files
|
||||
uses: andstor/file-existence-action@v2
|
||||
with:
|
||||
files: /tmp/sorted.txt
|
||||
|
||||
- name: show existing cache of test times
|
||||
if: steps.check_files.outputs.files_exists == 'true'
|
||||
shell: bash
|
||||
run: cat /tmp/sorted.txt
|
||||
|
||||
- name: compute matrix related fields when cache is present
|
||||
if: steps.check_files.outputs.files_exists == 'true'
|
||||
uses: ./.github/workflows/composites/matrix-bounds-on-test-times-cache-hit
|
||||
|
||||
- name: matrix related variables when cache is present
|
||||
id: test_times_cache_present_init
|
||||
run: |
|
||||
echo "test_times_cache_present=${{ env.TEST_TIMES_CACHE_PRESENT }}" >> $GITHUB_OUTPUT
|
||||
echo "number_of_matrix_instances=${{ env.NUMBER_OF_MATRIX_INSTANCES }}" >> $GITHUB_OUTPUT
|
||||
echo "matrix_array=${{ env.MATRIX_ARRAY }}" >> $GITHUB_OUTPUT
|
||||
echo "average_time_per_instance=${{ env.AVERAGE_TIME_PER_INSTANCE }}" >> $GITHUB_OUTPUT
|
||||
|
||||
test_when_cache_present:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
|
||||
# only run this one if there is a previous cache of test times
|
||||
if: needs.build.outputs.test_times_cache_present == 'true'
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
current_index: [ "${{ fromJSON(needs.build.outputs.matrix_array) }}" ]
|
||||
number_of_jobs: [ "${{ fromJSON(needs.build.outputs.number_of_matrix_instances) }}" ]
|
||||
average_time_per_instance: [ "${{ fromJSON(needs.build.outputs.average_time_per_instance) }}" ]
|
||||
|
||||
steps:
|
||||
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: clean space
|
||||
uses: ./.github/workflows/composites/clean-space
|
||||
|
||||
- name: set env variables
|
||||
uses: ./.github/workflows/composites/env-variables
|
||||
|
||||
- name: setup project jdk-17
|
||||
uses: ./.github/workflows/composites/setup-jdk17
|
||||
if: env.BASE_BRANCH == 'main' || env.BASE_BRANCH == '3.0.x'
|
||||
|
||||
- name: setup project jdk-8
|
||||
uses: ./.github/workflows/composites/setup-jdk1.8
|
||||
if: env.BASE_BRANCH == '2.1.x'
|
||||
|
||||
- name: pre-test-actions
|
||||
uses: ./.github/workflows/composites/pre-test-actions
|
||||
|
||||
- name: testcontainers reuse support
|
||||
shell: bash
|
||||
run: echo "testcontainers.reuse.enable=true" > ~/.testcontainers.properties
|
||||
|
||||
- name: run and save test times when cache is present
|
||||
uses: ./.github/workflows/composites/run-and-save-test-times-when-cache-present
|
||||
env:
|
||||
CURRENT_INDEX: ${{ matrix.current_index }}
|
||||
NUMBER_OF_JOBS: ${{ matrix.number_of_jobs }}
|
||||
AVERAGE_TIME_PER_INSTANCE: ${{ matrix.average_time_per_instance }}
|
||||
|
||||
test_when_cache_missing:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
|
||||
timeout-minutes: 60
|
||||
# only run this one if there is no previous cache of test times
|
||||
if: needs.build.outputs.test_times_cache_present == 'false'
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
current_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
||||
number_of_jobs: [32]
|
||||
|
||||
steps:
|
||||
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: clean space
|
||||
uses: ./.github/workflows/composites/clean-space
|
||||
|
||||
- name: set env variables
|
||||
uses: ./.github/workflows/composites/env-variables
|
||||
|
||||
- name: setup project jdk-17
|
||||
uses: ./.github/workflows/composites/setup-jdk17
|
||||
if: env.BASE_BRANCH == 'main' || env.BASE_BRANCH == '3.0.x'
|
||||
|
||||
- name: setup project jdk-8
|
||||
uses: ./.github/workflows/composites/setup-jdk1.8
|
||||
if: env.BASE_BRANCH == '2.1.x'
|
||||
|
||||
- name: pre-test-actions
|
||||
uses: ./.github/workflows/composites/pre-test-actions
|
||||
|
||||
- name: compute single step test bounds
|
||||
uses: ./.github/workflows/composites/test-bounds
|
||||
env:
|
||||
CURRENT_INDEX: ${{ matrix.current_index }}
|
||||
NUMBER_OF_JOBS: ${{ matrix.number_of_jobs }}
|
||||
|
||||
- name: testcontainers reuse support
|
||||
shell: bash
|
||||
run: echo "testcontainers.reuse.enable=true" > ~/.testcontainers.properties
|
||||
|
||||
- name: run and save individual test times
|
||||
env:
|
||||
CURRENT_INDEX: ${{ matrix.current_index }}
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: ./.github/workflows/composites/run-and-save-test-times-when-cache-missing
|
||||
|
||||
save_test_times_when_cache_missing:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, test_when_cache_missing ]
|
||||
|
||||
steps:
|
||||
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: compute and save running time of tests
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: ./.github/workflows/composites/test-times
|
||||
|
||||
save_test_times_when_cache_present:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ build, test_when_cache_present ]
|
||||
|
||||
steps:
|
||||
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: compute and save running time of tests
|
||||
if: env.BASE_BRANCH != '2.1.x'
|
||||
uses: ./.github/workflows/composites/test-times
|
||||
98
.gitignore
vendored
98
.gitignore
vendored
@@ -1,86 +1,22 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Maven template
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.flattened-pom.xml
|
||||
|
||||
|
||||
### Java template
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
.DS_Store
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
# vscode + eclipse
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
||||
*.orig
|
||||
.springBeans
|
||||
.factorypath
|
||||
.attach_pid*
|
||||
.vscode/
|
||||
.java-version
|
||||
*Dockerfile
|
||||
.sts4-cache
|
||||
.ant-targets-build.xml
|
||||
src/ant/.ant-targets-upload-dist.xml
|
||||
*.sonar4clipse*
|
||||
.DS_Store
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
/.idea/
|
||||
*.graphml
|
||||
node
|
||||
node_modules
|
||||
build
|
||||
package.json
|
||||
package-lock.json
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
-DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local -P spring
|
||||
206
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Executable file → Normal file
206
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Executable file → Normal file
@@ -1,117 +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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
* Copyright 2007-present 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 java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
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";
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* 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/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".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 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";
|
||||
/**
|
||||
* 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";
|
||||
/**
|
||||
* 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());
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + 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();
|
||||
}
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
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
Executable file → Normal file
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Executable file → Normal file
Binary file not shown.
3
.mvn/wrapper/maven-wrapper.properties
vendored
Executable file → Normal file
3
.mvn/wrapper/maven-wrapper.properties
vendored
Executable file → Normal file
@@ -1 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Enable auto-env through the sdkman_auto_env config
|
||||
# Add key=value pairs of SDKs to use below
|
||||
java=17.0.1-tem
|
||||
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings>
|
||||
<servers>
|
||||
<server>
|
||||
<id>repo.spring.io</id>
|
||||
<username>${env.CI_DEPLOY_USERNAME}</username>
|
||||
<password>${env.CI_DEPLOY_PASSWORD}</password>
|
||||
</server>
|
||||
</servers>
|
||||
<profiles>
|
||||
<profile>
|
||||
<!--
|
||||
N.B. this profile is only here to support users and IDEs that do not use Maven 3.3.
|
||||
It isn't needed on the command line if you use the wrapper script (mvnw) or if you use
|
||||
a native Maven with the right version. Eclipse users should points their Maven tooling to
|
||||
this settings file, or copy the profile into their ~/.m2/settings.xml.
|
||||
-->
|
||||
<id>spring</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</settings>
|
||||
201
LICENSE
201
LICENSE
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
5
NOTICE
5
NOTICE
@@ -1,5 +0,0 @@
|
||||
|
||||
Copyright (C) 2016 to the original authors.
|
||||
|
||||
This project was originally developed by Red Hat Inc. under the Fabric8 project.
|
||||
https://github.com/fabric8io/spring-cloud-kubernetes
|
||||
2485
README.adoc
2485
README.adoc
File diff suppressed because it is too large
Load Diff
@@ -6,38 +6,39 @@ antora:
|
||||
- '@antora/collector-extension'
|
||||
- '@antora/atlas-extension'
|
||||
- require: '@springio/antora-extensions/root-component-extension'
|
||||
root_component_name: 'PROJECT_WITHOUT_SPRING'
|
||||
# FIXME: Run antora once using this extension to migrate to the Asciidoc Tabs syntax
|
||||
# and then remove this extension
|
||||
- require: '@springio/antora-extensions/tabs-migration-extension'
|
||||
unwrap_example_block: always
|
||||
save_result: true
|
||||
root_component_name: 'cloud-kubernetes'
|
||||
site:
|
||||
title: PROJECT_FULL_NAME
|
||||
url: https://docs.spring.io/PROJECT_NAME/reference/
|
||||
title: Spring Cloud Kubernetes
|
||||
url: https://docs.spring.io/spring-cloud-kubernetes/reference
|
||||
robots: allow
|
||||
git:
|
||||
ensure_git_suffix: false
|
||||
content:
|
||||
sources:
|
||||
- url: ./..
|
||||
branches: HEAD
|
||||
- url: https://github.com/spring-cloud/spring-cloud-kubernetes
|
||||
# Refname matching:
|
||||
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
|
||||
branches: [ main ]
|
||||
tags: [ '({4..9}).+({1..9}).+({0..9})?(-{RC,M}+({0..9}))', '!4.1.0-M1' ]
|
||||
start_path: docs
|
||||
worktrees: true
|
||||
asciidoc:
|
||||
attributes:
|
||||
page-stackoverflow-url: https://stackoverflow.com/tags/spring-cloud
|
||||
page-pagination: ''
|
||||
hide-uri-scheme: '@'
|
||||
tabs-sync-option: '@'
|
||||
chomp: 'all'
|
||||
extensions:
|
||||
- '@asciidoctor/tabs'
|
||||
- '@springio/asciidoctor-extensions'
|
||||
sourcemap: true
|
||||
urls:
|
||||
latest_version_segment_strategy: redirect:to
|
||||
latest_version_segment: ''
|
||||
redirect_facility: httpd
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.5/ui-bundle.zip
|
||||
snapshot: true
|
||||
runtime:
|
||||
log:
|
||||
failure_level: warn
|
||||
format: pretty
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.5/ui-bundle.zip
|
||||
@@ -1,2 +0,0 @@
|
||||
releaser.maven.build-command: ./scripts/integration-tests.sh
|
||||
releaser.maven.deploy-command: ./scripts/deploy.sh {{systemProps}}
|
||||
105
docs/.flattened-pom.xml
Normal file
105
docs/.flattened-pom.xml
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-docs</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<name>Spring Cloud Kubernetes Docs</name>
|
||||
<description>Spring Cloud Kubernetes Docs</description>
|
||||
<url>https://cloud.spring.io/spring-cloud-kubernetes-docs</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dsyer</id>
|
||||
<name>Dave Syer</name>
|
||||
<email>dsyer at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sgibb</id>
|
||||
<name>Spencer Gibb</name>
|
||||
<email>sgibb at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mgrzejszczak</id>
|
||||
<name>Marcin Grzejszczak</name>
|
||||
<email>mgrzejszczak at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rbaxter</id>
|
||||
<name>Ryan Baxter</name>
|
||||
<email>rbaxter at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>omaciaszeksharma</id>
|
||||
<name>Olga Maciaszek-Sharma</name>
|
||||
<email>omaciaszeksharma at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-docs</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-docs</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-docs</url>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
32
docs/.github/workflows/deploy-docs.yml
vendored
32
docs/.github/workflows/deploy-docs.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: Deploy Docs
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ gh-pages ]
|
||||
tags: '**'
|
||||
repository_dispatch:
|
||||
types: request-build-reference # legacy
|
||||
#schedule:
|
||||
#- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
actions: write
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
# if: github.repository_owner == 'spring-cloud'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: docs-build
|
||||
fetch-depth: 1
|
||||
- name: Dispatch (partial build)
|
||||
if: github.ref_type == 'branch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
|
||||
- name: Dispatch (full build)
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
|
||||
@@ -1,12 +0,0 @@
|
||||
name: PROJECT_WITHOUT_SPRING
|
||||
version: true
|
||||
title: PROJECT_NAME
|
||||
nav:
|
||||
- modules/ROOT/nav.adoc
|
||||
ext:
|
||||
collector:
|
||||
run:
|
||||
command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests
|
||||
local: true
|
||||
scan:
|
||||
dir: ./target/classes/antora-resources/
|
||||
@@ -1,30 +0,0 @@
|
||||
* xref:index.adoc[]
|
||||
* xref:spring-cloud-kubernetes.adoc[]
|
||||
* xref:_attributes.adoc[]
|
||||
* xref:getting-started.adoc[]
|
||||
* xref:discovery-client.adoc[]
|
||||
* xref:discovery-kubernetes-native.adoc[]
|
||||
* xref:property-source-config.adoc[]
|
||||
** xref:property-source-config/configmap-propertysource.adoc[]
|
||||
** xref:property-source-config/secrets-propertysource.adoc[]
|
||||
** xref:property-source-config/namespace-resolution.adoc[]
|
||||
** xref:property-source-config/order_of_configMaps_and_secrets.adoc[]
|
||||
** xref:property-source-config/propertysource-reload.adoc[]
|
||||
** xref:property-source-config/namespace-label-filtering.adoc[]
|
||||
* xref:kubernetes-awareness.adoc[]
|
||||
* xref:pod-health-indicator.adoc[]
|
||||
* xref:info-contributor.adoc[]
|
||||
* xref:leader-election.adoc[]
|
||||
* xref:load-balancer.adoc[]
|
||||
* xref:security-service-accounts.adoc[]
|
||||
* xref:service-registry.adoc[]
|
||||
* xref:spring-cloud-kubernetes-configuration-watcher.adoc[]
|
||||
* xref:spring-cloud-kubernetes-configserver.adoc[]
|
||||
* xref:spring-cloud-kubernetes-discoveryserver.adoc[]
|
||||
* xref:examples.adoc[]
|
||||
* xref:other-resources.adoc[]
|
||||
* xref:README.adoc[]
|
||||
* xref:_configprops.adoc[]
|
||||
* xref:appendix.adoc[]
|
||||
* xref:sagan-boot.adoc[]
|
||||
* xref:sagan-index.adoc[]
|
||||
@@ -1,14 +0,0 @@
|
||||
:doctype: book
|
||||
:idprefix:
|
||||
:idseparator: -
|
||||
:tabsize: 4
|
||||
:numbered:
|
||||
:sectanchors:
|
||||
:sectnums:
|
||||
:icons: font
|
||||
:hide-uri-scheme:
|
||||
:docinfo: shared,private
|
||||
|
||||
:sc-ext: java
|
||||
:project-full-name: Spring Cloud Kubernetes
|
||||
:all: {asterisk}{asterisk}
|
||||
@@ -1,116 +0,0 @@
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|spring.cloud.kubernetes.client.api-version | |
|
||||
|spring.cloud.kubernetes.client.apiVersion | `+++v1+++` | Kubernetes API Version
|
||||
|spring.cloud.kubernetes.client.ca-cert-data | |
|
||||
|spring.cloud.kubernetes.client.ca-cert-file | |
|
||||
|spring.cloud.kubernetes.client.caCertData | | Kubernetes API CACertData
|
||||
|spring.cloud.kubernetes.client.caCertFile | | Kubernetes API CACertFile
|
||||
|spring.cloud.kubernetes.client.client-cert-data | |
|
||||
|spring.cloud.kubernetes.client.client-cert-file | |
|
||||
|spring.cloud.kubernetes.client.client-key-algo | |
|
||||
|spring.cloud.kubernetes.client.client-key-data | |
|
||||
|spring.cloud.kubernetes.client.client-key-file | |
|
||||
|spring.cloud.kubernetes.client.client-key-passphrase | |
|
||||
|spring.cloud.kubernetes.client.clientCertData | | Kubernetes API ClientCertData
|
||||
|spring.cloud.kubernetes.client.clientCertFile | | Kubernetes API ClientCertFile
|
||||
|spring.cloud.kubernetes.client.clientKeyAlgo | `+++RSA+++` | Kubernetes API ClientKeyAlgo
|
||||
|spring.cloud.kubernetes.client.clientKeyData | | Kubernetes API ClientKeyData
|
||||
|spring.cloud.kubernetes.client.clientKeyFile | | Kubernetes API ClientKeyFile
|
||||
|spring.cloud.kubernetes.client.clientKeyPassphrase | `+++changeit+++` | Kubernetes API ClientKeyPassphrase
|
||||
|spring.cloud.kubernetes.client.connection-timeout | |
|
||||
|spring.cloud.kubernetes.client.connectionTimeout | `+++10s+++` | Connection timeout
|
||||
|spring.cloud.kubernetes.client.http-proxy | |
|
||||
|spring.cloud.kubernetes.client.https-proxy | |
|
||||
|spring.cloud.kubernetes.client.logging-interval | |
|
||||
|spring.cloud.kubernetes.client.loggingInterval | `+++20s+++` | Logging interval
|
||||
|spring.cloud.kubernetes.client.master-url | |
|
||||
|spring.cloud.kubernetes.client.masterUrl | `+++https://kubernetes.default.svc+++` | Kubernetes API Master Node URL
|
||||
|spring.cloud.kubernetes.client.namespace | `+++true+++` | Kubernetes Namespace
|
||||
|spring.cloud.kubernetes.client.no-proxy | |
|
||||
|spring.cloud.kubernetes.client.oauth-token | |
|
||||
|spring.cloud.kubernetes.client.oauthToken | | Kubernetes API Oauth Token
|
||||
|spring.cloud.kubernetes.client.password | | Kubernetes API Password
|
||||
|spring.cloud.kubernetes.client.proxy-password | |
|
||||
|spring.cloud.kubernetes.client.proxy-username | |
|
||||
|spring.cloud.kubernetes.client.request-timeout | |
|
||||
|spring.cloud.kubernetes.client.requestTimeout | `+++10s+++` | Request timeout
|
||||
|spring.cloud.kubernetes.client.rolling-timeout | |
|
||||
|spring.cloud.kubernetes.client.rollingTimeout | `+++900s+++` | Rolling timeout
|
||||
|spring.cloud.kubernetes.client.service-account-namespace-path | `+++/var/run/secrets/kubernetes.io/serviceaccount/namespace+++` |
|
||||
|spring.cloud.kubernetes.client.trust-certs | |
|
||||
|spring.cloud.kubernetes.client.trustCerts | `+++false+++` | Kubernetes API Trust Certificates
|
||||
|spring.cloud.kubernetes.client.user-agent | `+++Spring-Cloud-Kubernetes-Application+++` |
|
||||
|spring.cloud.kubernetes.client.username | | Kubernetes API Username
|
||||
|spring.cloud.kubernetes.client.watch-reconnect-interval | |
|
||||
|spring.cloud.kubernetes.client.watch-reconnect-limit | |
|
||||
|spring.cloud.kubernetes.client.watchReconnectInterval | `+++1s+++` | Reconnect Interval
|
||||
|spring.cloud.kubernetes.client.watchReconnectLimit | `+++-1+++` | Reconnect Interval limit retries
|
||||
|spring.cloud.kubernetes.config.enable-api | `+++true+++` |
|
||||
|spring.cloud.kubernetes.config.enabled | `+++true+++` | Enable the ConfigMap property source locator.
|
||||
|spring.cloud.kubernetes.config.fail-fast | `+++false+++` |
|
||||
|spring.cloud.kubernetes.config.include-profile-specific-sources | `+++true+++` |
|
||||
|spring.cloud.kubernetes.config.labels | |
|
||||
|spring.cloud.kubernetes.config.name | |
|
||||
|spring.cloud.kubernetes.config.namespace | |
|
||||
|spring.cloud.kubernetes.config.paths | |
|
||||
|spring.cloud.kubernetes.config.retry | |
|
||||
|spring.cloud.kubernetes.config.sources | |
|
||||
|spring.cloud.kubernetes.config.use-name-as-prefix | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.all-namespaces | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.cache-loading-timeout-seconds | `+++60+++` |
|
||||
|spring.cloud.kubernetes.discovery.enabled | `+++true+++` |
|
||||
|spring.cloud.kubernetes.discovery.filter | |
|
||||
|spring.cloud.kubernetes.discovery.include-external-name-services | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.include-not-ready-addresses | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.known-secure-ports | `+++[443, 8443]+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.add-annotations | `+++true+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.add-labels | `+++true+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.add-pod-annotations | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.add-pod-labels | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.add-ports | `+++true+++` |
|
||||
|spring.cloud.kubernetes.discovery.metadata.annotations-prefix | |
|
||||
|spring.cloud.kubernetes.discovery.metadata.labels-prefix | |
|
||||
|spring.cloud.kubernetes.discovery.metadata.ports-prefix | `+++port.+++` |
|
||||
|spring.cloud.kubernetes.discovery.namespaces | |
|
||||
|spring.cloud.kubernetes.discovery.order | `+++0+++` |
|
||||
|spring.cloud.kubernetes.discovery.primary-port-name | |
|
||||
|spring.cloud.kubernetes.discovery.service-labels | |
|
||||
|spring.cloud.kubernetes.discovery.use-endpoint-slices | `+++false+++` |
|
||||
|spring.cloud.kubernetes.discovery.wait-cache-ready | `+++true+++` |
|
||||
|spring.cloud.kubernetes.leader.auto-startup | `+++true+++` | Should leader election be started automatically on startup. Default: true
|
||||
|spring.cloud.kubernetes.leader.config-map-name | `+++leaders+++` | Kubernetes ConfigMap where leaders information will be stored. Default: leaders
|
||||
|spring.cloud.kubernetes.leader.create-config-map | `+++true+++` | Enable/disable creating ConfigMap if it does not exist. Default: true
|
||||
|spring.cloud.kubernetes.leader.enabled | `+++true+++` | Should leader election be enabled. Default: true
|
||||
|spring.cloud.kubernetes.leader.leader-id-prefix | `+++leader.id.+++` | Leader id property prefix for the ConfigMap. Default: leader.id.
|
||||
|spring.cloud.kubernetes.leader.namespace | | Kubernetes namespace where the leaders ConfigMap and candidates are located.
|
||||
|spring.cloud.kubernetes.leader.publish-failed-events | `+++false+++` | Enable/disable publishing events in case leadership acquisition fails. Default: false
|
||||
|spring.cloud.kubernetes.leader.role | | Role for which leadership this candidate will compete.
|
||||
|spring.cloud.kubernetes.leader.update-period | `+++60000ms+++` | Leadership status check period. Default: 60s
|
||||
|spring.cloud.kubernetes.loadbalancer.cluster-domain | `+++cluster.local+++` | cluster domain.
|
||||
|spring.cloud.kubernetes.loadbalancer.enabled | `+++true+++` | Load balancer enabled,default true.
|
||||
|spring.cloud.kubernetes.loadbalancer.mode | | {@link KubernetesLoadBalancerMode} setting load balancer server list with ip of pod or service name. default value is POD.
|
||||
|spring.cloud.kubernetes.loadbalancer.port-name | `+++http+++` | service port name.
|
||||
|spring.cloud.kubernetes.reload.enable-reload-filtering | `+++false+++` |
|
||||
|spring.cloud.kubernetes.reload.enabled | `+++false+++` |
|
||||
|spring.cloud.kubernetes.reload.max-wait-for-restart | `+++2s+++` |
|
||||
|spring.cloud.kubernetes.reload.mode | `+++EVENT+++` |
|
||||
|spring.cloud.kubernetes.reload.monitoring-config-maps | `+++true+++` |
|
||||
|spring.cloud.kubernetes.reload.monitoring-secrets | `+++false+++` |
|
||||
|spring.cloud.kubernetes.reload.namespaces | |
|
||||
|spring.cloud.kubernetes.reload.period | `+++15000ms+++` |
|
||||
|spring.cloud.kubernetes.reload.strategy | `+++REFRESH+++` |
|
||||
|spring.cloud.kubernetes.secrets.enable-api | `+++false+++` |
|
||||
|spring.cloud.kubernetes.secrets.enabled | `+++true+++` | Enable the Secrets property source locator.
|
||||
|spring.cloud.kubernetes.secrets.fail-fast | `+++false+++` |
|
||||
|spring.cloud.kubernetes.secrets.include-profile-specific-sources | `+++true+++` |
|
||||
|spring.cloud.kubernetes.secrets.labels | |
|
||||
|spring.cloud.kubernetes.secrets.name | |
|
||||
|spring.cloud.kubernetes.secrets.namespace | |
|
||||
|spring.cloud.kubernetes.secrets.paths | |
|
||||
|spring.cloud.kubernetes.secrets.retry | |
|
||||
|spring.cloud.kubernetes.secrets.sources | |
|
||||
|spring.cloud.kubernetes.secrets.use-name-as-prefix | `+++false+++` |
|
||||
|
||||
|===
|
||||
@@ -1,13 +0,0 @@
|
||||
:numbered!:
|
||||
[appendix]
|
||||
[[common-application-properties]]
|
||||
= Common application properties
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches.
|
||||
This appendix provides a list of common {project-full-name} properties and references to the underlying classes that consume them.
|
||||
|
||||
NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
|
||||
Also, you can define your own properties.
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
[[discoveryclient-for-kubernetes]]
|
||||
= DiscoveryClient for Kubernetes
|
||||
|
||||
This project provides an implementation of https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java[Discovery Client]
|
||||
for https://kubernetes.io[Kubernetes].
|
||||
This client lets you query Kubernetes endpoints (see https://kubernetes.io/docs/user-guide/services/[services]) by name.
|
||||
A service is typically exposed by the Kubernetes API server as a collection of endpoints that represent `http` and `https` addresses and that a client can
|
||||
access from a Spring Boot application running as a pod.
|
||||
|
||||
DiscoveryClient can also find services of type `ExternalName` (see https://kubernetes.io/docs/concepts/services-networking/service/#externalname[ExternalName services]). At the moment, external name support type of services is only available if the following property `spring.cloud.kubernetes.discovery.include-external-name-services` is set to `true` and only in the `fabric8` implementation. In a later release, support will be added for the kubernetes native client also.
|
||||
|
||||
This is something that you get for free by adding the following dependency inside your project:
|
||||
|
||||
====
|
||||
HTTP Based `DiscoveryClient`
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-discoveryclient</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: `spring-cloud-starter-kubernetes-discoveryclient` is designed to be used with the
|
||||
xref:spring-cloud-kubernetes-discoveryserver.adoc#spring-cloud-kubernetes-discoveryserver[Spring Cloud Kubernetes DiscoveryServer].
|
||||
|
||||
====
|
||||
Fabric8 Kubernetes Client
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
Kubernetes Java Client
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
To enable loading of the `DiscoveryClient`, add `@EnableDiscoveryClient` to the according configuration or application class, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Then you can inject the client in your code simply by autowiring it, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Autowired
|
||||
private DiscoveryClient discoveryClient;
|
||||
----
|
||||
====
|
||||
|
||||
You can choose to enable `DiscoveryClient` from all namespaces by setting the following property in `application.properties`:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.discovery.all-namespaces=true
|
||||
----
|
||||
====
|
||||
|
||||
To discover services and endpoints only from specified namespaces you should set property `all-namespaces` to `false` and set the following property in `application.properties` (in this example namespaces are: `ns1` and `ns2`).
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.discovery.namespaces[0]=ns1
|
||||
spring.cloud.kubernetes.discovery.namespaces[1]=ns2
|
||||
----
|
||||
====
|
||||
|
||||
To discover service endpoint addresses that are not marked as "ready" by the kubernetes api server, you can set the following property in `application.properties` (default: false):
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.discovery.include-not-ready-addresses=true
|
||||
----
|
||||
NOTE: This might be useful when discovering services for monitoring purposes, and would enable inspecting the `/health` endpoint of not-ready service instances.
|
||||
====
|
||||
|
||||
If your service exposes multiple ports, you will need to specify which port the `DiscoveryClient` should use.
|
||||
The `DiscoveryClient` will choose the port using the following logic.
|
||||
|
||||
1. If the service has a label `primary-port-name` it will use the port with the name specified in the label's value.
|
||||
2. If no label is present, then the port name specified in `spring.cloud.kubernetes.discovery.primary-port-name` will be used.
|
||||
3. If neither of the above are specified it will use the port named `https`.
|
||||
4. If none of the above conditions are met it will use the port named `http`.
|
||||
5. As a last resort it wil pick the first port in the list of ports.
|
||||
|
||||
WARNING: The last option may result in non-deterministic behaviour.
|
||||
Please make sure to configure your service and/or application accordingly.
|
||||
|
||||
By default all of the ports and their names will be added to the metadata of the `ServiceInstance`.
|
||||
|
||||
As said before, if you want to get the list of `ServiceInstance` to also include the `ExternalName` type services, you need to enable that support via: `spring.cloud.kubernetes.discovery.include-external-name-services=true`. As such, when calling `DiscoveryClient::getInstances` those will be returned also. You can distinguish between `ExternalName` and any other types by inspecting `ServiceInstance::getMetadata` and lookup for a field called `type`. This will be the type of the service returned : `ExternalName`/`ClusterIP`, etc.
|
||||
|
||||
`ServiceInstance` can include the labels and annotations of specific pods from the underlying service instance. To obtain such information, you need to also enable:
|
||||
|
||||
`spring.cloud.kubernetes.discovery.metadata.add-pod-labels=true` and/or `spring.cloud.kubernetes.discovery.metadata.add-pod-annotations=true`. At the moment, such functionality is present only in the fabric8 client implementation, but will be added to the kubernetes native client in a later release.
|
||||
|
||||
If, for any reason, you need to disable the `DiscoveryClient`, you can set the following property in `application.properties`:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.discovery.enabled=false
|
||||
----
|
||||
====
|
||||
|
||||
Some Spring Cloud components use the `DiscoveryClient` in order to obtain information about the local service instance. For
|
||||
this to work, you need to align the Kubernetes service name with the `spring.application.name` property.
|
||||
|
||||
NOTE: `spring.application.name` has no effect as far as the name registered for the application within Kubernetes
|
||||
|
||||
Spring Cloud Kubernetes can also watch the Kubernetes service catalog for changes and update the
|
||||
`DiscoveryClient` implementation accordingly. By "watch" we mean that we will publish a heartbeat event every `spring.cloud.kubernetes.discovery.catalog-services-watch-delay`
|
||||
milliseconds (by default it is `30000`). The heartbeat event will contain the target references (and their namespaces of the addresses of all endpoints
|
||||
(for the exact details of what will get returned you can take a look inside `KubernetesCatalogWatch`). This is an implementation detail, and listeners of the heartbeat event
|
||||
should not rely on the details. Instead, they should see if there are differences between two subsequent heartbeats via `equals` method. We will take care to return a correct implementation that adheres to the equals contract.
|
||||
The endpoints will be queried in either :
|
||||
|
||||
- all namespaces (enabled via `spring.cloud.kubernetes.discovery.all-namespaces=true`)
|
||||
|
||||
- specific namespaces (enabled via `spring.cloud.kubernetes.discovery.namespaces`), for example:
|
||||
|
||||
```
|
||||
spring:
|
||||
cloud:
|
||||
kubernetes:
|
||||
discovery:
|
||||
namespaces:
|
||||
- namespace-a
|
||||
- namespace-b
|
||||
```
|
||||
|
||||
- we will use: xref:property-source-config/namespace-resolution.adoc[Namespace Resolution] if the above two paths are not taken.
|
||||
|
||||
In order to enable this functionality you need to add
|
||||
`@EnableScheduling` on a configuration class in your application.
|
||||
|
||||
By default, we use the `Endpoints`(see https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) API to find out the current state of services. There is another way though, via `EndpointSlices` (https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/). Such support can be enabled via a property: `spring.cloud.kubernetes.discovery.use-endpoint-slices=true` (by default it is `false`). Of course, your cluster has to support it also. As a matter of fact, if you enable this property, but your cluster does not support it, we will fail starting the application. If you decide to enable such support, you also need proper Role/ClusterRole set-up. For example:
|
||||
|
||||
```
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
namespace: default
|
||||
name: namespace-reader
|
||||
rules:
|
||||
- apiGroups: ["discovery.k8s.io"]
|
||||
resources: ["endpointslices"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
@@ -1,13 +0,0 @@
|
||||
[[kubernetes-native-service-discovery]]
|
||||
= Kubernetes native service discovery
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
Kubernetes itself is capable of (server side) service discovery (see: https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services).
|
||||
Using native kubernetes service discovery ensures compatibility with additional tooling, such as Istio (https://istio.io), a service mesh that is capable of load balancing, circuit breaker, failover, and much more.
|
||||
|
||||
The caller service then need only refer to names resolvable in a particular Kubernetes cluster. A simple implementation might use a spring `RestTemplate` that refers to a fully qualified domain name (FQDN), such as `https://{service-name}.{namespace}.svc.{cluster}.local:{service-port}`.
|
||||
|
||||
Additionally, you can use Hystrix for:
|
||||
|
||||
* Circuit breaker implementation on the caller side, by annotating the spring boot application class with `@EnableCircuitBreaker`
|
||||
* Fallback functionality, by annotating the respective method with `@HystrixCommand(fallbackMethod=`
|
||||
@@ -1,19 +0,0 @@
|
||||
[[examples]]
|
||||
= Examples
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
Spring Cloud Kubernetes tries to make it transparent for your applications to consume Kubernetes Native Services by
|
||||
following the Spring Cloud interfaces.
|
||||
|
||||
In your applications, you need to add the `spring-cloud-kubernetes-discovery` dependency to your classpath and remove any other dependency that contains a `DiscoveryClient` implementation (that is, a Eureka discovery client).
|
||||
The same applies for `PropertySourceLocator`, where you need to add to the classpath the `spring-cloud-kubernetes-config` and remove any other dependency that contains a `PropertySourceLocator` implementation (that is, a configuration server client).
|
||||
|
||||
The following projects highlight the usage of these dependencies and demonstrate how you can use these libraries from any Spring Boot application:
|
||||
|
||||
* https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples[Spring Cloud Kubernetes Examples]: the ones located inside this repository.
|
||||
* Spring Cloud Kubernetes Full Example: Minions and Boss
|
||||
** https://github.com/salaboy/spring-cloud-k8s-minion[Minion]
|
||||
** https://github.com/salaboy/spring-cloud-k8s-boss[Boss]
|
||||
* Spring Cloud Kubernetes Full Example: https://github.com/salaboy/s1p_docs[SpringOne Platform Tickets Service]
|
||||
* https://github.com/salaboy/s1p_gateway[Spring Cloud Gateway with Spring Cloud Kubernetes Discovery and Config]
|
||||
* https://github.com/salaboy/showcase-admin-tool[Spring Boot Admin with Spring Cloud Kubernetes Discovery and Config]
|
||||
@@ -1,75 +0,0 @@
|
||||
[[starters]]
|
||||
= Starters
|
||||
|
||||
Starters are convenient dependency descriptors you can include in your
|
||||
application. Include a starter to get the dependencies and Spring Boot
|
||||
auto-configuration for a feature set. Starters that begin with `spring-cloud-starter-kubernetes-fabric8`
|
||||
provide implementations using the https://github.com/fabric8io/kubernetes-client[Fabric8 Kubernetes Java Client].
|
||||
Starters that begin with
|
||||
`spring-cloud-starter-kubernetes-client` provide implementations using the https://github.com/kubernetes-client/java[Kubernetes Java Client].
|
||||
|
||||
[cols="a,d"]
|
||||
|===
|
||||
| Starter | Features
|
||||
|
||||
| [source,xml]
|
||||
.Fabric8 Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,xml]
|
||||
.Kubernetes Client Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
| <<DiscoveryClient for Kubernetes,Discovery Client>> implementation that
|
||||
resolves service names to Kubernetes Services.
|
||||
|
||||
| [source,xml]
|
||||
.Fabric8 Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,xml]
|
||||
.Kubernetes Client Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
| Load application properties from Kubernetes
|
||||
xref:property-source-config/configmap-propertysource.adoc[ConfigMaps] and <<Secrets PropertySource,Secrets>>.
|
||||
xref:property-source-config/propertysource-reload.adoc[Reload] application properties when a ConfigMap or
|
||||
Secret changes.
|
||||
|
||||
| [source,xml]
|
||||
.Fabric8 Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,xml]
|
||||
.Kubernetes Client Dependency
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
| All Spring Cloud Kubernetes features.
|
||||
|===
|
||||
@@ -1,9 +0,0 @@
|
||||
[[info-contributor]]
|
||||
= Info Contributor
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
Spring Cloud Kubernetes includes an `InfoContributor` which adds Pod information to
|
||||
Spring Boot's `/info` Acturator endpoint.
|
||||
|
||||
You can disable this `InfoContributor` by setting `management.info.kubernetes.enabled`
|
||||
to `false` in `application.[properties | yaml]`.
|
||||
@@ -1,46 +0,0 @@
|
||||
[[kubernetes-ecosystem-awareness]]
|
||||
= Kubernetes Ecosystem Awareness
|
||||
|
||||
All features described earlier in this guide work equally well, regardless of whether your application is running inside
|
||||
Kubernetes. This is really helpful for development and troubleshooting.
|
||||
From a development point of view, this lets you start your Spring Boot application and debug one
|
||||
of the modules that is part of this project. You need not deploy it in Kubernetes,
|
||||
as the code of the project relies on the
|
||||
https://github.com/fabric8io/kubernetes-client[Fabric8 Kubernetes Java client], which is a fluent DSL that can
|
||||
communicate by using `http` protocol to the REST API of the Kubernetes Server.
|
||||
|
||||
Kubernetes awareness is based on Spring Boot API, specifically on https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatform.html[ConditionalOnCloudPlatform].
|
||||
That property will auto-detect if your application is currently deployed in kubernetes or not. It is possible to override
|
||||
that setting via `spring.main.cloud-platform`.
|
||||
|
||||
For example, if you need to test some features, but do not want to deploy to a cluster, it is enough to set the:
|
||||
`spring.main.cloud-platform=KUBERNETES`. This will make `spring-cloud-kubernetes` act as-if it is deployed in a real cluster.
|
||||
|
||||
NOTE: If you have `spring-cloud-starter-bootstrap` on your classpath or are setting `spring.cloud.bootstrap.enabled=true` then
|
||||
you will have to set `spring.main.cloud-platform` should be set in `bootstrap.{properties|yml}`
|
||||
(or the profile specific one). Also note that these properties: `spring.cloud.kubernetes.config.enabled` and `spring.cloud.kubernetes.secrets.enabled`
|
||||
will only take effect when set in `bootstrap.{properties|yml}` when you have `spring-cloud-starter-bootstrap` on your classpath or are setting `spring.cloud.bootstrap.enabled=true`.
|
||||
|
||||
[[breaking-changes-in-3-0-x]]
|
||||
== Breaking Changes In 3.0.x
|
||||
|
||||
In versions of Spring Cloud Kubernetes prior to `3.0.x`, Kubernetes awareness was implemented using `spring.cloud.kubernetes.enabled` property. This
|
||||
property was removed and is un-supported. Instead, we use Spring Boot API: https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatform.html[ConditionalOnCloudPlatform].
|
||||
If it is needed to explicitly enable or disable this awareness, use `spring.main.cloud-platform=NONE/KUBERNETES`.
|
||||
|
||||
[[kubernetes-profile-autoconfiguration]]
|
||||
== Kubernetes Profile Autoconfiguration
|
||||
|
||||
When the application runs as a pod inside Kubernetes, a Spring profile named `kubernetes` automatically gets activated.
|
||||
This lets you customize the configuration, to define beans that are applied when the Spring Boot application is deployed
|
||||
within the Kubernetes platform (for example, different development and production configuration).
|
||||
|
||||
[[istio-awareness]]
|
||||
== Istio Awareness
|
||||
|
||||
When you include the `spring-cloud-kubernetes-fabric8-istio` module in the application classpath, a new profile is added to the application,
|
||||
provided the application is running inside a Kubernetes Cluster with https://istio.io[Istio] installed. You can then use
|
||||
spring `@Profile("istio")` annotations in your Beans and `@Configuration` classes.
|
||||
|
||||
The Istio awareness module uses `me.snowdrop:istio-client` to interact with Istio APIs, letting us discover traffic rules, circuit breakers, and so on,
|
||||
making it easy for our Spring Boot applications to consume this data to dynamically configure themselves according to the environment.
|
||||
@@ -1,31 +0,0 @@
|
||||
[[leader-election]]
|
||||
= Leader Election
|
||||
|
||||
The Spring Cloud Kubernetes leader election mechanism implements the leader election API of Spring Integration using a Kubernetes ConfigMap.
|
||||
|
||||
Multiple application instances compete for leadership, but leadership will only be granted to one.
|
||||
When granted leadership, a leader application receives an `OnGrantedEvent` application event with leadership `Context`.
|
||||
Applications periodically attempt to gain leadership, with leadership granted to the first caller.
|
||||
A leader will remain a leader until either it is removed from the cluster, or it yields its leadership.
|
||||
When leadership removal occurs, the previous leader receives `OnRevokedEvent` application event.
|
||||
After removal, any instances in the cluster may become the new leader, including the old leader.
|
||||
|
||||
To include it in your project, add the following dependency.
|
||||
====
|
||||
Fabric8 Leader Implementation
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-fabric8-leader</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
To specify the name of the configmap used for leader election use the following property.
|
||||
====
|
||||
[source,properties]
|
||||
----
|
||||
spring.cloud.kubernetes.leader.config-map-name=leader
|
||||
----
|
||||
====
|
||||
@@ -1,44 +0,0 @@
|
||||
[[loadbalancer-for-kubernetes]]
|
||||
= LoadBalancer for Kubernetes
|
||||
|
||||
This project includes Spring Cloud Load Balancer for load balancing based on Kubernetes Endpoints and provides implementation of load balancer based on Kubernetes Service.
|
||||
To include it to your project add the following dependency.
|
||||
====
|
||||
Fabric8 Implementation
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
Kubernetes Java Client Implementation
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
To enable load balancing based on Kubernetes Service name use the following property. Then load balancer would try to call application using address, for example `service-a.default.svc.cluster.local`
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.loadbalancer.mode=SERVICE
|
||||
----
|
||||
====
|
||||
|
||||
To enabled load balancing across all namespaces use the following property. Property from `spring-cloud-kubernetes-discovery` module is respected.
|
||||
====
|
||||
[source]
|
||||
----
|
||||
spring.cloud.kubernetes.discovery.all-namespaces=true
|
||||
----
|
||||
====
|
||||
|
||||
If a service needs to be accessed over HTTPS you need to add a label or annotation to your service definition with the name `secured` and the value `true` and the load balancer will then use HTTPS to make requests to the service.
|
||||
@@ -1,11 +0,0 @@
|
||||
[[other-resources]]
|
||||
= Other Resources
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
This section lists other resources, such as presentations (slides) and videos about Spring Cloud Kubernetes.
|
||||
|
||||
* https://salaboy.com/2018/09/27/the-s1p-experience/[S1P Spring Cloud on PKS]
|
||||
* https://salaboy.com/2018/07/18/ljc-july-18-spring-cloud-docker-k8s/[Spring Cloud, Docker, Kubernetes -> London Java Community July 2018]
|
||||
|
||||
|
||||
Please feel free to submit other resources through pull requests to https://github.com/spring-cloud/spring-cloud-kubernetes[this repository].
|
||||
@@ -1,14 +0,0 @@
|
||||
[[pod-health-indicator]]
|
||||
= Pod Health Indicator
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
Spring Boot uses https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java[`HealthIndicator`] to expose info about the health of an application.
|
||||
That makes it really useful for exposing health-related information to the user and makes it a good fit for use as https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/[readiness probes].
|
||||
|
||||
The Kubernetes health indicator (which is part of the core module) exposes the following info:
|
||||
|
||||
* Pod name, IP address, namespace, service account, node name, and its IP address
|
||||
* A flag that indicates whether the Spring Boot application is internal or external to Kubernetes
|
||||
|
||||
You can disable this `HealthContributor` by setting `management.health.kubernetes.enabled`
|
||||
to `false` in `application.[properties | yaml]`.
|
||||
@@ -1,18 +0,0 @@
|
||||
[[kubernetes-propertysource-implementations]]
|
||||
= Kubernetes PropertySource implementations
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
The most common approach to configuring your Spring Boot application is to create an `application.properties` or `application.yaml` or
|
||||
an `application-profile.properties` or `application-profile.yaml` file that contains key-value pairs that provide customization values to your
|
||||
application or Spring Boot starters. You can override these properties by specifying system properties or environment
|
||||
variables.
|
||||
|
||||
To enable this functionality you need to set `spring.config.import=kubernetes:` in your application's configuration properties.
|
||||
Currently you can not specify a ConfigMap or Secret to load using `spring.config.import`, by default Spring Cloud Kubernetes
|
||||
will load a ConfigMap and/or Secret based on the `spring.application.name` property. If `spring.application.name` is not set it will
|
||||
load a ConfigMap and/or Secret with the name `application`.
|
||||
|
||||
If you would like to load Kubernetes ``PropertySource``s during the bootstrap phase like it worked prior to the 3.0.x release
|
||||
you can either add `spring-cloud-starter-bootstrap` to your application's classpath or set `spring.cloud.bootstrap.enabled=true`
|
||||
as an environment variable.
|
||||
|
||||
@@ -1,620 +0,0 @@
|
||||
[[configmap-propertysource]]
|
||||
= Using a `ConfigMap` `PropertySource`
|
||||
|
||||
Kubernetes provides a resource named https://kubernetes.io/docs/user-guide/configmap/[`ConfigMap`] to externalize the
|
||||
parameters to pass to your application in the form of key-value pairs or embedded `application.properties` or `application.yaml` files.
|
||||
The link:https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-fabric8-config[Spring Cloud Kubernetes Config] project makes Kubernetes `ConfigMap` instances available
|
||||
during application startup and triggers hot reloading of beans or Spring context when changes are detected on
|
||||
observed `ConfigMap` instances.
|
||||
|
||||
Everything that follows is explained mainly referring to examples using ConfigMaps, but the same stands for
|
||||
Secrets, i.e.: every feature is supported for both.
|
||||
|
||||
The default behavior is to create a `Fabric8ConfigMapPropertySource` (or a `KubernetesClientConfigMapPropertySource`) based on a Kubernetes `ConfigMap` that has a `metadata.name` value of either the name of
|
||||
your Spring application (as defined by its `spring.application.name` property) or a custom name defined within the
|
||||
`application.properties` file under the following key: `spring.cloud.kubernetes.config.name`.
|
||||
|
||||
However, more advanced configuration is possible where you can use multiple `ConfigMap` instances.
|
||||
The `spring.cloud.kubernetes.config.sources` list makes this possible.
|
||||
For example, you could define the following `ConfigMap` instances:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: cloud-k8s-app
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
name: default-name
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
# Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
|
||||
- name: c1
|
||||
# Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
|
||||
- namespace: n2
|
||||
# Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
|
||||
- namespace: n3
|
||||
name: c3
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, if `spring.cloud.kubernetes.config.namespace` had not been set,
|
||||
the `ConfigMap` named `c1` would be looked up in the namespace that the application runs.
|
||||
See xref:property-source-config/namespace-resolution.adoc[Namespace resolution] to get a better understanding of how the namespace
|
||||
of the application is resolved.
|
||||
|
||||
|
||||
Any matching `ConfigMap` that is found is processed as follows:
|
||||
|
||||
* Apply individual configuration properties.
|
||||
* Apply as `yaml` (or `properties`) the content of any property that is named by the value of `spring.application.name`
|
||||
(if it's not present, by `application.yaml/properties`)
|
||||
* Apply as a properties file the content of the above name + each active profile.
|
||||
|
||||
An example should make a lot more sense. Let's suppose that `spring.application.name=my-app` and that
|
||||
we have a single active profile called `k8s`. For a configuration as below:
|
||||
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-app
|
||||
data:
|
||||
my-app.yaml: |-
|
||||
...
|
||||
my-app-k8s.yaml: |-
|
||||
..
|
||||
my-app-dev.yaml: |-
|
||||
..
|
||||
someProp: someValue
|
||||
----
|
||||
====
|
||||
|
||||
These is what we will end-up loading:
|
||||
|
||||
- `my-app.yaml` treated as a file
|
||||
- `my-app-k8s.yaml` treated as a file
|
||||
- `my-app-dev.yaml` _ignored_, since `dev` is _not_ an active profile
|
||||
- `someProp: someValue` plain property
|
||||
|
||||
The single exception to the aforementioned flow is when the `ConfigMap` contains a *single* key that indicates
|
||||
the file is a YAML or properties file. In that case, the name of the key does NOT have to be `application.yaml` or
|
||||
`application.properties` (it can be anything) and the value of the property is treated correctly.
|
||||
This features facilitates the use case where the `ConfigMap` was created by using something like the following:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
|
||||
----
|
||||
====
|
||||
|
||||
Assume that we have a Spring Boot application named `demo` that uses the following properties to read its thread pool
|
||||
configuration.
|
||||
|
||||
* `pool.size.core`
|
||||
* `pool.size.maximum`
|
||||
|
||||
This can be externalized to config map in `yaml` format as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
pool.size.core: 1
|
||||
pool.size.max: 16
|
||||
----
|
||||
====
|
||||
|
||||
Individual properties work fine for most cases. However, sometimes, embedded `yaml` is more convenient. In this case, we
|
||||
use a single property named `application.yaml` to embed our `yaml`, as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
application.yaml: |-
|
||||
pool:
|
||||
size:
|
||||
core: 1
|
||||
max:16
|
||||
----
|
||||
====
|
||||
|
||||
The following example also works:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
custom-name.yaml: |-
|
||||
pool:
|
||||
size:
|
||||
core: 1
|
||||
max:16
|
||||
----
|
||||
====
|
||||
|
||||
You can also define the search to happen based on labels, for example:
|
||||
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: labeled-configmap-with-prefix
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
enableApi: true
|
||||
useNameAsPrefix: true
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- labels:
|
||||
letter: a
|
||||
----
|
||||
====
|
||||
|
||||
This will search for every configmap in namespace `spring-k8s` that has labels `{letter : a}`. The important
|
||||
thing to notice here is that unlike reading a configmap by name, this can result in _multiple_ config maps read.
|
||||
As usual, the same feature is supported for secrets.
|
||||
|
||||
You can also configure Spring Boot applications differently depending on active profiles that are merged together
|
||||
when the `ConfigMap` is read. You can provide different property values for different profiles by using an
|
||||
`application.properties` or `application.yaml` property, specifying profile-specific values, each in their own document
|
||||
(indicated by the `---` sequence), as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
application.yml: |-
|
||||
greeting:
|
||||
message: Say Hello to the World
|
||||
farewell:
|
||||
message: Say Goodbye
|
||||
---
|
||||
spring:
|
||||
profiles: development
|
||||
greeting:
|
||||
message: Say Hello to the Developers
|
||||
farewell:
|
||||
message: Say Goodbye to the Developers
|
||||
---
|
||||
spring:
|
||||
profiles: production
|
||||
greeting:
|
||||
message: Say Hello to the Ops
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding case, the configuration loaded into your Spring Application with the `development` profile is as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
greeting:
|
||||
message: Say Hello to the Developers
|
||||
farewell:
|
||||
message: Say Goodbye to the Developers
|
||||
----
|
||||
====
|
||||
|
||||
However, if the `production` profile is active, the configuration becomes:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
greeting:
|
||||
message: Say Hello to the Ops
|
||||
farewell:
|
||||
message: Say Goodbye
|
||||
----
|
||||
====
|
||||
|
||||
If both profiles are active, the property that appears last within the `ConfigMap` overwrites any preceding values.
|
||||
|
||||
Another option is to create a different config map per profile and spring boot will automatically fetch it based
|
||||
on active profiles
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
application.yml: |-
|
||||
greeting:
|
||||
message: Say Hello to the World
|
||||
farewell:
|
||||
message: Say Goodbye
|
||||
----
|
||||
====
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo-development
|
||||
data:
|
||||
application.yml: |-
|
||||
spring:
|
||||
profiles: development
|
||||
greeting:
|
||||
message: Say Hello to the Developers
|
||||
farewell:
|
||||
message: Say Goodbye to the Developers
|
||||
----
|
||||
====
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo-production
|
||||
data:
|
||||
application.yml: |-
|
||||
spring:
|
||||
profiles: production
|
||||
greeting:
|
||||
message: Say Hello to the Ops
|
||||
farewell:
|
||||
message: Say Goodbye
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
To tell Spring Boot which `profile` should be enabled see the https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.profiles[Spring Boot documentation].
|
||||
One option for activating a specific profile when deploying to Kubernetes is to launch your Spring Boot application with an environment variable that you can define in the PodSpec at the container specification.
|
||||
Deployment resource file, as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-name
|
||||
labels:
|
||||
app: deployment-name
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: deployment-name
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: deployment-name
|
||||
spec:
|
||||
containers:
|
||||
- name: container-name
|
||||
image: your-image
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: "development"
|
||||
----
|
||||
====
|
||||
|
||||
You could run into a situation where there are multiple configs maps that have the same property names. For example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: config-map-one
|
||||
data:
|
||||
application.yml: |-
|
||||
greeting:
|
||||
message: Say Hello from one
|
||||
----
|
||||
====
|
||||
|
||||
and
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: config-map-two
|
||||
data:
|
||||
application.yml: |-
|
||||
greeting:
|
||||
message: Say Hello from two
|
||||
----
|
||||
====
|
||||
|
||||
Depending on the order in which you place these in `bootstrap.yaml|properties`, you might end up with an un-expected result (the last config map wins). For example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: cloud-k8s-app
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-two
|
||||
- name: config-map-one
|
||||
----
|
||||
====
|
||||
|
||||
will result in property `greetings.message` being `Say Hello from one`.
|
||||
|
||||
There is a way to change this default configuration by specifying `useNameAsPrefix`. For example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: with-prefix
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
useNameAsPrefix: true
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
useNameAsPrefix: false
|
||||
- name: config-map-two
|
||||
----
|
||||
====
|
||||
|
||||
Such a configuration will result in two properties being generated:
|
||||
|
||||
- `greetings.message` equal to `Say Hello from one`.
|
||||
|
||||
- `config-map-two.greetings.message` equal to `Say Hello from two`
|
||||
|
||||
Notice that `spring.cloud.kubernetes.config.useNameAsPrefix` has a _lower_ priority than `spring.cloud.kubernetes.config.sources.useNameAsPrefix`.
|
||||
This allows you to set a "default" strategy for all sources, at the same time allowing to override only a few.
|
||||
|
||||
If using the config map name is not an option, you can specify a different strategy, called : `explicitPrefix`. Since this is an _explicit_ prefix that
|
||||
you select, it can only be supplied to the `sources` level. At the same time it has a higher priority than `useNameAsPrefix`. Let's suppose we have a third config map with these entries:
|
||||
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: config-map-three
|
||||
data:
|
||||
application.yml: |-
|
||||
greeting:
|
||||
message: Say Hello from three
|
||||
----
|
||||
====
|
||||
|
||||
A configuration like the one below:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: with-prefix
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
useNameAsPrefix: true
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
useNameAsPrefix: false
|
||||
- name: config-map-two
|
||||
explicitPrefix: two
|
||||
- name: config-map-three
|
||||
----
|
||||
====
|
||||
|
||||
will result in three properties being generated:
|
||||
|
||||
- `greetings.message` equal to `Say Hello from one`.
|
||||
|
||||
- `two.greetings.message` equal to `Say Hello from two`.
|
||||
|
||||
- `config-map-three.greetings.message` equal to `Say Hello from three`.
|
||||
|
||||
The same way you configure a prefix for configmaps, you can do it for secrets also; both for secrets that are based on name
|
||||
and the ones based on labels. For example:
|
||||
|
||||
====
|
||||
[source.yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: prefix-based-secrets
|
||||
cloud:
|
||||
kubernetes:
|
||||
secrets:
|
||||
enableApi: true
|
||||
useNameAsPrefix: true
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- labels:
|
||||
letter: a
|
||||
useNameAsPrefix: false
|
||||
- labels:
|
||||
letter: b
|
||||
explicitPrefix: two
|
||||
- labels:
|
||||
letter: c
|
||||
- labels:
|
||||
letter: d
|
||||
useNameAsPrefix: true
|
||||
- name: my-secret
|
||||
----
|
||||
====
|
||||
|
||||
The same processing rules apply when generating property source as for config maps. The only difference is that
|
||||
potentially, looking up secrets by labels can mean that we find more than one source. In such a case, prefix (if specified via `useNameAsPrefix`)
|
||||
will be the names of all secrets found for those particular labels.
|
||||
|
||||
One more thing to bear in mind is that we support `prefix` per _source_, not per secret. The easiest way to explain this is via an example:
|
||||
|
||||
====
|
||||
[source.yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: prefix-based-secrets
|
||||
cloud:
|
||||
kubernetes:
|
||||
secrets:
|
||||
enableApi: true
|
||||
useNameAsPrefix: true
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- labels:
|
||||
color: blue
|
||||
useNameAsPrefix: true
|
||||
----
|
||||
====
|
||||
|
||||
Suppose that a query matching such a label will provide two secrets as a result: `secret-a` and `secret-b`.
|
||||
Both of these secrets have the same property name: `color=sea-blue` and `color=ocean-blue`. It is undefined which
|
||||
`color` will end-up as part of property sources, but the prefix for it will be `secret-a.secret-b`
|
||||
(concatenated sorted naturally, names of the secrets).
|
||||
|
||||
If you need more fine-grained results, adding more labels to identify the secret uniquely would be an option.
|
||||
|
||||
|
||||
|
||||
By default, besides reading the config map that is specified in the `sources` configuration, Spring will also try to read
|
||||
all properties from "profile aware" sources. The easiest way to explain this is via an example. Let's suppose your application
|
||||
enables a profile called "dev" and you have a configuration like the one below:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: spring-k8s
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
----
|
||||
====
|
||||
|
||||
Besides reading the `config-map-one`, Spring will also try to read `config-map-one-dev`; in this particular order. Each active profile
|
||||
generates such a profile aware config map.
|
||||
|
||||
Though your application should not be impacted by such a config map, it can be disabled if needed:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: spring-k8s
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
includeProfileSpecificSources: false
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
includeProfileSpecificSources: false
|
||||
----
|
||||
====
|
||||
|
||||
Notice that just like before, there are two levels where you can specify this property: for all config maps or
|
||||
for individual ones; the latter having a higher priority.
|
||||
|
||||
NOTE: You should check the security configuration section. To access config maps from inside a pod you need to have the correct
|
||||
Kubernetes service accounts, roles and role bindings.
|
||||
|
||||
Another option for using `ConfigMap` instances is to mount them into the Pod by running the Spring Cloud Kubernetes application
|
||||
and having Spring Cloud Kubernetes read them from the file system.
|
||||
|
||||
NOTE: This feature is deprecated and will be removed in a future release (Use `spring.config.import` instead).
|
||||
This behavior is controlled by the `spring.cloud.kubernetes.config.paths` property. You can use it in
|
||||
addition to or instead of the mechanism described earlier.
|
||||
`spring.cloud.kubernetes.config.paths` expects a List of full paths to each property file, because directories are not being recursively parsed. For example:
|
||||
|
||||
```
|
||||
spring:
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
paths:
|
||||
- /tmp/application.properties
|
||||
- /var/application.yaml
|
||||
```
|
||||
|
||||
NOTE: If you use `spring.cloud.kubernetes.config.paths` or `spring.cloud.kubernetes.secrets.path` the automatic reload
|
||||
functionality will not work. You will need to make a `POST` request to the `/actuator/refresh` endpoint or
|
||||
restart/redeploy the application.
|
||||
|
||||
[#config-map-fail-fast]
|
||||
In some cases, your application may be unable to load some of your `ConfigMaps` using the Kubernetes API.
|
||||
If you want your application to fail the start-up process in such cases, you can set
|
||||
`spring.cloud.kubernetes.config.fail-fast=true` to make the application start-up fail with an Exception.
|
||||
|
||||
[#config-map-retry]
|
||||
You can also make your application retry loading `ConfigMap` property sources on a failure. First, you need to
|
||||
set `spring.cloud.kubernetes.config.fail-fast=true`. Then you need to add `spring-retry`
|
||||
and `spring-boot-starter-aop` to your classpath. You can configure retry properties such as
|
||||
the maximum number of attempts, backoff options like initial interval, multiplier, max interval by setting the
|
||||
`spring.cloud.kubernetes.config.retry.*` properties.
|
||||
|
||||
NOTE: If you already have `spring-retry` and `spring-boot-starter-aop` on the classpath for some reason
|
||||
and want to enable fail-fast, but do not want retry to be enabled; you can disable retry for `ConfigMap` `PropertySources`
|
||||
by setting `spring.cloud.kubernetes.config.retry.enabled=false`.
|
||||
|
||||
.Properties:
|
||||
[options="header,footer"]
|
||||
|===
|
||||
| Name | Type | Default | Description
|
||||
| `spring.cloud.kubernetes.config.enabled` | `Boolean` | `true` | Enable ConfigMaps `PropertySource`
|
||||
| `spring.cloud.kubernetes.config.name` | `String` | `${spring.application.name}` | Sets the name of `ConfigMap` to look up
|
||||
| `spring.cloud.kubernetes.config.namespace` | `String` | Client namespace | Sets the Kubernetes namespace where to lookup
|
||||
| `spring.cloud.kubernetes.config.paths` | `List` | `null` | Sets the paths where `ConfigMap` instances are mounted
|
||||
| `spring.cloud.kubernetes.config.enableApi` | `Boolean` | `true` | Enable or disable consuming `ConfigMap` instances through APIs
|
||||
| `spring.cloud.kubernetes.config.fail-fast` | `Boolean` | `false` | Enable or disable failing the application start-up when an error occurred while loading a `ConfigMap`
|
||||
| `spring.cloud.kubernetes.config.retry.enabled` | `Boolean` | `true` | Enable or disable config retry.
|
||||
| `spring.cloud.kubernetes.config.retry.initial-interval` | `Long` | `1000` | Initial retry interval in milliseconds.
|
||||
| `spring.cloud.kubernetes.config.retry.max-attempts` | `Integer` | `6` | Maximum number of attempts.
|
||||
| `spring.cloud.kubernetes.config.retry.max-interval` | `Long` | `2000` | Maximum interval for backoff.
|
||||
| `spring.cloud.kubernetes.config.retry.multiplier` | `Double` | `1.1` | Multiplier for next interval.
|
||||
|===
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
[[namespace-label-filtering]]
|
||||
= Reload namespace and label filtering
|
||||
|
||||
By default, a namespace chosen using the steps outlined in xref:property-source-config/namespace-resolution.adoc[Namespace resolution] will be used to listen to changes
|
||||
in configmaps and secrets. i.e.: if you do not tell reload what namespaces and configmaps/secrets to watch for,
|
||||
it will watch all configmaps/secrets from the namespace that will be computed using the above algorithm.
|
||||
|
||||
On the other hand, you can define a more fine-grained approach. For example, you can specify the namespaces where
|
||||
changes will be monitored:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: event-reload
|
||||
cloud:
|
||||
kubernetes:
|
||||
reload:
|
||||
enabled: true
|
||||
strategy: shutdown
|
||||
mode: event
|
||||
namespaces:
|
||||
- my-namespace
|
||||
----
|
||||
====
|
||||
|
||||
Such a configuration will make the app watch changes only in the `my-namespace` namespace. Mind that this will
|
||||
watch _all_ configmaps/secrets (depending on which one you enable). If you want an even more fine-grained approach,
|
||||
you can enable "label-filtering". First we need to enable such support via : `enable-reload-filtering: true`
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: event-reload
|
||||
cloud:
|
||||
kubernetes:
|
||||
reload:
|
||||
enabled: true
|
||||
strategy: shutdown
|
||||
mode: event
|
||||
namespaces:
|
||||
- my-namespaces
|
||||
monitoring-config-maps: true
|
||||
enable-reload-filtering: true
|
||||
----
|
||||
====
|
||||
|
||||
What this will do, is watch configmaps/secrets that only have the `spring.cloud.kubernetes.config.informer.enabled: true` label.
|
||||
|
||||
.Properties:
|
||||
[options="header,footer"]
|
||||
|===
|
||||
| Name | Type | Default | Description
|
||||
| `spring.cloud.kubernetes.reload.enabled` | `Boolean` | `false` | Enables monitoring of property sources and configuration reload
|
||||
| `spring.cloud.kubernetes.reload.monitoring-config-maps` | `Boolean` | `true` | Allow monitoring changes in config maps
|
||||
| `spring.cloud.kubernetes.reload.monitoring-secrets` | `Boolean` | `false` | Allow monitoring changes in secrets
|
||||
| `spring.cloud.kubernetes.reload.strategy` | `Enum` | `refresh` | The strategy to use when firing a reload (`refresh`, `restart_context`, or `shutdown`)
|
||||
| `spring.cloud.kubernetes.reload.mode` | `Enum` | `event` | Specifies how to listen for changes in property sources (`event` or `polling`)
|
||||
| `spring.cloud.kubernetes.reload.period` | `Duration`| `15s` | The period for verifying changes when using the `polling` strategy
|
||||
| `spring.cloud.kubernetes.reload.namespaces` | `String[]`| | namespaces where we should watch for changes
|
||||
| `spring.cloud.kubernetes.reload.enable-reload-filtering` | `String` | | enabled labeled filtering for reload functionality
|
||||
|===
|
||||
|
||||
Notes:
|
||||
|
||||
* You should not use properties under `spring.cloud.kubernetes.reload` in config maps or secrets. Changing such properties at runtime may lead to unexpected results.
|
||||
* Deleting a property or the whole config map does not restore the original state of the beans when you use the `refresh` level.
|
||||
@@ -1,40 +0,0 @@
|
||||
[[namespace-resolution]]
|
||||
= Namespace resolution
|
||||
|
||||
Finding an application namespace happens on a best-effort basis. There are some steps that we iterate in order
|
||||
to find it. The easiest and most common one, is to specify it in the proper configuration, for example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: app
|
||||
cloud:
|
||||
kubernetes:
|
||||
secrets:
|
||||
name: secret
|
||||
namespace: default
|
||||
sources:
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'a' in namespace 'default'
|
||||
- name: a
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'secret' in namespace 'b'
|
||||
- namespace: b
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'd' in namespace 'c'
|
||||
- namespace: c
|
||||
name: d
|
||||
----
|
||||
====
|
||||
|
||||
Remember that the same can be done for config maps. If such a namespace is not specified, it will be read (in this order):
|
||||
|
||||
1. from property `spring.cloud.kubernetes.client.namespace`
|
||||
2. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath` property
|
||||
3. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file
|
||||
(kubernetes default namespace path)
|
||||
4. from a designated client method call (for example fabric8's : `KubernetesClient::getNamespace`), if the client provides
|
||||
such a method. This, in turn, could be configured via environment properties. For example fabric8 client can be configured via
|
||||
"KUBERNETES_NAMESPACE" property; consult the client documentation for exact details.
|
||||
|
||||
Failure to find a namespace from the above steps will result in an Exception being raised.
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[[order_of_configMaps_and_secrets]]
|
||||
= Order of ConfigMaps and Secrets
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
If, for whatever reason, you enabled both configmaps and secrets, and there is a common property between them, the value from the ConfigMap will have a higher precedence. That is: it will override whatever values are found in secrets.
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
[[propertysource-reload]]
|
||||
= `PropertySource` Reload
|
||||
|
||||
WARNING: This functionality has been deprecated in the 2020.0 release. Please see
|
||||
the xref:spring-cloud-kubernetes-configuration-watcher.adoc#spring-cloud-kubernetes-configuration-watcher[null] controller for an alternative way
|
||||
to achieve the same functionality.
|
||||
|
||||
Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration.
|
||||
The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when a related `ConfigMap` or
|
||||
`Secret` changes.
|
||||
|
||||
By default, this feature is disabled. You can enable it by using the `spring.cloud.kubernetes.reload.enabled=true` configuration property (for example, in the `application.properties` file).
|
||||
Please notice that this will enable monitoring of configmaps only (i.e.: `spring.cloud.kubernetes.reload.monitoring-config-maps` will be set to `true`).
|
||||
If you want to enable monitoring of secrets, this must be done explicitly via : `spring.cloud.kubernetes.reload.monitoring-secrets=true`.
|
||||
|
||||
The following levels of reload are supported (by setting the `spring.cloud.kubernetes.reload.strategy` property):
|
||||
|
||||
* `refresh` (default): Only configuration beans annotated with `@ConfigurationProperties` or `@RefreshScope` are reloaded.
|
||||
This reload level leverages the refresh feature of Spring Cloud Context.
|
||||
|
||||
* `restart_context`: the whole Spring `ApplicationContext` is gracefully restarted. Beans are recreated with the new configuration.
|
||||
In order for the restart context functionality to work properly you must enable and expose the restart actuator endpoint
|
||||
[source,yaml]
|
||||
====
|
||||
----
|
||||
management:
|
||||
endpoint:
|
||||
restart:
|
||||
enabled: true
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: restart
|
||||
----
|
||||
====
|
||||
|
||||
* `shutdown`: the Spring `ApplicationContext` is shut down to activate a restart of the container.
|
||||
When you use this level, make sure that the lifecycle of all non-daemon threads is bound to the `ApplicationContext`
|
||||
and that a replication controller or replica set is configured to restart the pod.
|
||||
|
||||
Assuming that the reload feature is enabled with default settings (`refresh` mode), the following bean is refreshed when the config map changes:
|
||||
|
||||
====
|
||||
[java, source]
|
||||
----
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "bean")
|
||||
public class MyConfig {
|
||||
|
||||
private String message = "a message that can be changed live";
|
||||
|
||||
// getter and setters
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
To see that changes effectively happen, you can create another bean that prints the message periodically, as follows
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyBean {
|
||||
|
||||
@Autowired
|
||||
private MyConfig config;
|
||||
|
||||
@Scheduled(fixedDelay = 5000)
|
||||
public void hello() {
|
||||
System.out.println("The message is: " + config.getMessage());
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can change the message printed by the application by using a `ConfigMap`, as follows:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: reload-example
|
||||
data:
|
||||
application.properties: |-
|
||||
bean.message=Hello World!
|
||||
----
|
||||
====
|
||||
|
||||
Any change to the property named `bean.message` in the `ConfigMap` associated with the pod is reflected in the
|
||||
output. More generally speaking, changes associated to properties prefixed with the value defined by the `prefix`
|
||||
field of the `@ConfigurationProperties` annotation are detected and reflected in the application.
|
||||
xref:property-source-config/configmap-propertysource.adoc[Associating a `ConfigMap` with a pod] is explained earlier in this chapter.
|
||||
|
||||
The reload feature supports two operating modes:
|
||||
|
||||
* Event (default): Watches for changes in config maps or secrets by using the Kubernetes API (web socket).
|
||||
Any event produces a re-check on the configuration and, in case of changes, a reload.
|
||||
The `view` role on the service account is required in order to listen for config map changes. A higher level role (such as `edit`) is required for secrets
|
||||
(by default, secrets are not monitored).
|
||||
* Polling: Periodically re-creates the configuration from config maps and secrets to see if it has changed.
|
||||
You can configure the polling period by using the `spring.cloud.kubernetes.reload.period` property and defaults to 15 seconds.
|
||||
It requires the same role as the monitored property source.
|
||||
This means, for example, that using polling on file-mounted secret sources does not require particular privileges.
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
[[secrets-propertysource]]
|
||||
= Secrets PropertySource
|
||||
|
||||
Kubernetes has the notion of https://kubernetes.io/docs/concepts/configuration/secret/[Secrets] for storing
|
||||
sensitive data such as passwords, OAuth tokens, and so on. This project provides integration with `Secrets` to make secrets
|
||||
accessible by Spring Boot applications. You can explicitly enable or disable This feature by setting the `spring.cloud.kubernetes.secrets.enabled` property.
|
||||
|
||||
When enabled, the `Fabric8SecretsPropertySource` looks up Kubernetes for `Secrets` from the following sources:
|
||||
|
||||
. Reading recursively from secrets mounts
|
||||
. Named after the application (as defined by `spring.application.name`)
|
||||
. Matching some labels
|
||||
|
||||
*Note:*
|
||||
|
||||
By default, consuming Secrets through the API (points 2 and 3 above) *is not enabled* for security reasons. The permission 'list' on secrets allows clients to inspect secrets values in the specified namespace.
|
||||
Further, we recommend that containers share secrets through mounted volumes.
|
||||
|
||||
If you enable consuming Secrets through the API, we recommend that you limit access to Secrets by using an authorization policy, such as RBAC.
|
||||
For more information about risks and best practices when consuming Secrets through the API refer to https://kubernetes.io/docs/concepts/configuration/secret/#best-practices[this doc].
|
||||
|
||||
If the secrets are found, their data is made available to the application.
|
||||
|
||||
Assume that we have a spring boot application named `demo` that uses properties to read its database
|
||||
configuration. We can create a Kubernetes secret by using the following command:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
kubectl create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd
|
||||
----
|
||||
====
|
||||
|
||||
The preceding command would create the following secret (which you can see by using `kubectl get secrets db-secret -o yaml`):
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: v1
|
||||
data:
|
||||
password: cDQ1NXcwcmQ=
|
||||
username: dXNlcg==
|
||||
kind: Secret
|
||||
metadata:
|
||||
creationTimestamp: 2017-07-04T09:15:57Z
|
||||
name: db-secret
|
||||
namespace: default
|
||||
resourceVersion: "357496"
|
||||
selfLink: /api/v1/namespaces/default/secrets/db-secret
|
||||
uid: 63c89263-6099-11e7-b3da-76d6186905a8
|
||||
type: Opaque
|
||||
----
|
||||
====
|
||||
|
||||
Note that the data contains Base64-encoded versions of the literal provided by the `create` command.
|
||||
|
||||
Your application can then use this secret -- for example, by exporting the secret's value as environment variables:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ${project.artifactId}
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: DB_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: db-secret
|
||||
key: username
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: db-secret
|
||||
key: password
|
||||
----
|
||||
====
|
||||
|
||||
You can select the Secrets to consume in a number of ways:
|
||||
|
||||
. By listing the directories where secrets are mapped:
|
||||
+
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql
|
||||
----
|
||||
====
|
||||
+
|
||||
If you have all the secrets mapped to a common root, you can set them like:
|
||||
+
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
|
||||
----
|
||||
====
|
||||
|
||||
. By setting a named secret:
|
||||
+
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
-Dspring.cloud.kubernetes.secrets.name=db-secret
|
||||
----
|
||||
====
|
||||
|
||||
. By defining a list of labels:
|
||||
+
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
-Dspring.cloud.kubernetes.secrets.labels.broker=activemq
|
||||
-Dspring.cloud.kubernetes.secrets.labels.db=postgresql
|
||||
----
|
||||
====
|
||||
|
||||
As the case with `ConfigMap`, more advanced configuration is also possible where you can use multiple `Secret`
|
||||
instances. The `spring.cloud.kubernetes.secrets.sources` list makes this possible.
|
||||
For example, you could define the following `Secret` instances:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: cloud-k8s-app
|
||||
cloud:
|
||||
kubernetes:
|
||||
secrets:
|
||||
name: default-name
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
# Spring Cloud Kubernetes looks up a Secret named s1 in namespace default-namespace
|
||||
- name: s1
|
||||
# Spring Cloud Kubernetes looks up a Secret named default-name in namespace n2
|
||||
- namespace: n2
|
||||
# Spring Cloud Kubernetes looks up a Secret named s3 in namespace n3
|
||||
- namespace: n3
|
||||
name: s3
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, if `spring.cloud.kubernetes.secrets.namespace` had not been set,
|
||||
the `Secret` named `s1` would be looked up in the namespace that the application runs.
|
||||
See xref:property-source-config/namespace-resolution.adoc[namespace-resolution] to get a better understanding of how the namespace
|
||||
of the application is resolved.
|
||||
|
||||
xref:property-source-config/configmap-propertysource.adoc#config-map-fail-fast[Similar to the `ConfigMaps`]; if you want your application to fail to start
|
||||
when it is unable to load `Secrets` property sources, you can set `spring.cloud.kubernetes.secrets.fail-fast=true`.
|
||||
|
||||
It is also possible to enable retry for `Secret` property sources xref:property-source-config/configmap-propertysource.adoc#config-map-retry[like the `ConfigMaps`].
|
||||
As with the `ConfigMap` property sources, first you need to set `spring.cloud.kubernetes.secrets.fail-fast=true`.
|
||||
Then you need to add `spring-retry` and `spring-boot-starter-aop` to your classpath.
|
||||
Retry behavior of the `Secret` property sources can be configured by setting the `spring.cloud.kubernetes.secrets.retry.*`
|
||||
properties.
|
||||
|
||||
NOTE: If you already have `spring-retry` and `spring-boot-starter-aop` on the classpath for some reason
|
||||
and want to enable fail-fast, but do not want retry to be enabled; you can disable retry for `Secrets` `PropertySources`
|
||||
by setting `spring.cloud.kubernetes.secrets.retry.enabled=false`.
|
||||
|
||||
.Properties:
|
||||
[options="header,footer"]
|
||||
|===
|
||||
| Name | Type | Default | Description
|
||||
| `spring.cloud.kubernetes.secrets.enabled` | `Boolean` | `true` | Enable Secrets `PropertySource`
|
||||
| `spring.cloud.kubernetes.secrets.name` | `String` | `${spring.application.name}` | Sets the name of the secret to look up
|
||||
| `spring.cloud.kubernetes.secrets.namespace` | `String` | Client namespace | Sets the Kubernetes namespace where to look up
|
||||
| `spring.cloud.kubernetes.secrets.labels` | `Map` | `null` | Sets the labels used to lookup secrets
|
||||
| `spring.cloud.kubernetes.secrets.paths` | `List` | `null` | Sets the paths where secrets are mounted (example 1)
|
||||
| `spring.cloud.kubernetes.secrets.enableApi` | `Boolean` | `false` | Enables or disables consuming secrets through APIs (examples 2 and 3)
|
||||
| `spring.cloud.kubernetes.secrets.fail-fast` | `Boolean` | `false` | Enable or disable failing the application start-up when an error occurred while loading a `Secret`
|
||||
| `spring.cloud.kubernetes.secrets.retry.enabled` | `Boolean` | `true` | Enable or disable secrets retry.
|
||||
| `spring.cloud.kubernetes.secrets.retry.initial-interval` | `Long` | `1000` | Initial retry interval in milliseconds.
|
||||
| `spring.cloud.kubernetes.secrets.retry.max-attempts` | `Integer` | `6` | Maximum number of attempts.
|
||||
| `spring.cloud.kubernetes.secrets.retry.max-interval` | `Long` | `2000` | Maximum interval for backoff.
|
||||
| `spring.cloud.kubernetes.secrets.retry.multiplier` | `Double` | `1.1` | Multiplier for next interval.
|
||||
|===
|
||||
|
||||
Notes:
|
||||
|
||||
* The `spring.cloud.kubernetes.secrets.labels` property behaves as defined by
|
||||
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#map-based-binding[Map-based binding].
|
||||
* The `spring.cloud.kubernetes.secrets.paths` property behaves as defined by
|
||||
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#collection-based-binding[Collection-based binding].
|
||||
* Access to secrets through the API may be restricted for security reasons. The preferred way is to mount secrets to the Pod.
|
||||
|
||||
You can find an example of an application that uses secrets (though it has not been updated to use the new `spring-cloud-kubernetes` project) at
|
||||
https://github.com/fabric8-quickstarts/spring-boot-camel-config[spring-boot-camel-config]
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
Spring Cloud Kubernetes provide Spring Cloud common interface implementations that consume Kubernetes native services.
|
||||
The main objective of the projects provided in this repository is to facilitate the integration of Spring Cloud and Spring Boot applications running inside Kubernetes.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Kubernetes awareness
|
||||
* `DiscoveryClient` implementation
|
||||
* `PropertySource` objects configured via ConfigMaps
|
||||
|
||||
## Getting Started
|
||||
The easiest way to get started is by including the Spring Cloud BOM and then adding `spring-cloud-starter-kubernetes-client-all` to your application's classpath. If you don't want to include all of the Spring Cloud Kubernetes features you can add individual starters for the features you would like. By default Spring Cloud Kubernetes will enable the `kubernetes` profile when it detects it is running inside a Kubernetes cluster. You can take advantage of this by creating a `kubernetes-application` configuration properties for anything specific to Kubernetes you might want to configure. Once the starter is on the classpath the application should behave as any other Spring Cloud application.
|
||||
@@ -1,81 +0,0 @@
|
||||
[[security-configurations-inside-kubernetes]]
|
||||
= Security Configurations Inside Kubernetes
|
||||
|
||||
|
||||
[[namespace]]
|
||||
== Namespace
|
||||
|
||||
Most of the components provided in this project need to know the namespace. For Kubernetes (1.3+), the namespace is made available to the pod as part of the service account secret and is automatically detected by the client.
|
||||
For earlier versions, it needs to be specified as an environment variable to the pod. A quick way to do this is as follows:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
env:
|
||||
- name: "KUBERNETES_NAMESPACE"
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: "metadata.namespace"
|
||||
----
|
||||
====
|
||||
|
||||
[[service-account]]
|
||||
== Service Account
|
||||
|
||||
For distributions of Kubernetes that support more fine-grained role-based access within the cluster, you need to make sure a pod that runs with `spring-cloud-kubernetes` has access to the Kubernetes API.
|
||||
For any service accounts you assign to a deployment or pod, you need to make sure they have the correct roles.
|
||||
|
||||
Depending on the requirements, you'll need `get`, `list` and `watch` permission on the following resources:
|
||||
|
||||
.Kubernetes Resource Permissions
|
||||
|===
|
||||
|Dependency | Resources
|
||||
|
||||
|
||||
|spring-cloud-starter-kubernetes-fabric8
|
||||
|pods, services, endpoints
|
||||
|
||||
|spring-cloud-starter-kubernetes-fabric8-config
|
||||
|configmaps, secrets
|
||||
|
||||
|spring-cloud-starter-kubernetes-client
|
||||
|pods, services, endpoints
|
||||
|
||||
|spring-cloud-starter-kubernetes-client-config
|
||||
|configmaps, secrets
|
||||
|===
|
||||
|
||||
For development purposes, you can add `cluster-reader` permissions to your `default` service account. On a production system you'll likely want to provide more granular permissions.
|
||||
|
||||
The following Role and RoleBinding are an example for namespaced permissions for the `default` account:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: YOUR-NAME-SPACE
|
||||
name: namespace-reader
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
|
||||
---
|
||||
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: namespace-reader-binding
|
||||
namespace: YOUR-NAME-SPACE
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: namespace-reader
|
||||
apiGroup: ""
|
||||
----
|
||||
====
|
||||
@@ -1,7 +0,0 @@
|
||||
[[service-registry-implementation]]
|
||||
= Service Registry Implementation
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
In Kubernetes service registration is controlled by the platform, the application itself does not control
|
||||
registration as it may do in other platforms. For this reason using `spring.cloud.service-registry.auto-registration.enabled`
|
||||
or setting `@EnableDiscoveryClient(autoRegister=false)` will have no effect in Spring Cloud Kubernetes.
|
||||
@@ -1,122 +0,0 @@
|
||||
[#spring-cloud-kubernetes-configserver]
|
||||
## Spring Cloud Kubernetes Config Server
|
||||
|
||||
The Spring Cloud Kubernetes Config Server, is based on https://spring.io/projects/spring-cloud-config[Spring Cloud Config Server] and adds an https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_environment_repository[environment repository] for Kubernetes
|
||||
https://kubernetes.io/docs/concepts/configuration/configmap/[Config Maps] and https://kubernetes.io/docs/concepts/configuration/secret/[Secrets].
|
||||
|
||||
This is component is completely optional. However, it allows you to continue to leverage configuration
|
||||
you may have stored in existing environment repositories (Git, SVN, Vault, etc) with applications that you are running on Kubernetes.
|
||||
|
||||
A default image is located on https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-configserver[Docker Hub] which will allow you to easily get a Config Server deployed on Kubernetes without building
|
||||
the code and image yourself. However, if you need to customize the config server behavior or prefer to build the image yourself you can easily build your own
|
||||
image from the https://github.com/spring-cloud/spring-cloud-kubernetes/tree/main/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver[source code on GitHub] and use that.
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Enabling The Kubernetes Environment Repository
|
||||
To enable the Kubernetes environment repository the `kubernetes` profile must be included in the list of active profiles.
|
||||
You may activate other profiles as well to use other environment repository implementations.
|
||||
|
||||
#### Config Map and Secret PropertySources
|
||||
By default, only Config Map data will be fetched. To enable Secrets as well you will need to set `spring.cloud.kubernetes.secrets.enableApi=true`.
|
||||
You can disable the Config Map `PropertySource` by setting `spring.cloud.kubernetes.config.enableApi=false`.
|
||||
|
||||
#### Fetching Config Map and Secret Data From Additional Namespaces
|
||||
By default, the Kubernetes environment repository will only fetch Config Map and Secrets from the namespace in which it is deployed.
|
||||
If you want to include data from other namespaces you can set `spring.cloud.kubernetes.configserver.config-map-namespaces` and/or `spring.cloud.kubernetes.configserver.secrets-namespaces` to a comma separated
|
||||
list of namespace values.
|
||||
|
||||
NOTE: If you set `spring.cloud.kubernetes.configserver.config-map-namespaces` and/or `spring.cloud.kubernetes.configserver.secrets-namespaces`
|
||||
you will need to include the namespace in which the Config Server is deployed in order to continue to fetch Config Map and Secret data from that namespace.
|
||||
|
||||
#### Kubernetes Access Controls
|
||||
The Kubernetes Config Server uses the Kubernetes API server to fetch Config Map and Secret data. In order for it to do that
|
||||
it needs ability to `get` and `list` Config Map and Secrets (depending on what you enable/disable).
|
||||
|
||||
### Deployment Yaml
|
||||
|
||||
Below is a sample deployment, service and permissions configuration you can use to deploy a basic Config Server to Kubernetes.
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
name: spring-cloud-kubernetes-configserver
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8888
|
||||
targetPort: 8888
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
type: ClusterIP
|
||||
- apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
name: spring-cloud-kubernetes-configserver
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
name: spring-cloud-kubernetes-configserver:view
|
||||
roleRef:
|
||||
kind: Role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: namespace-reader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: spring-cloud-kubernetes-configserver
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
namespace: default
|
||||
name: namespace-reader
|
||||
rules:
|
||||
- apiGroups: ["", "extensions", "apps"]
|
||||
resources: ["configmaps", "secrets"]
|
||||
verbs: ["get", "list"]
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-configserver-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configserver
|
||||
spec:
|
||||
serviceAccount: spring-cloud-kubernetes-configserver
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-configserver
|
||||
image: springcloud/spring-cloud-kubernetes-configserver
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: SPRING_PROFILES_INCLUDE
|
||||
value: "kubernetes"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8888
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8888
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8888
|
||||
|
||||
----
|
||||
====
|
||||
@@ -1,216 +0,0 @@
|
||||
[#spring-cloud-kubernetes-configuration-watcher]
|
||||
## Spring Cloud Kubernetes Configuration Watcher
|
||||
|
||||
Kubernetes provides the ability to https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-volume[mount a ConfigMap or Secret as a volume]
|
||||
in the container of your application. When the contents of the ConfigMap or Secret changes, the https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically[mounted volume will be updated with those changes].
|
||||
|
||||
However, Spring Boot will not automatically update those changes unless you restart the application. Spring Cloud
|
||||
provides the ability refresh the application context without restarting the application by either hitting the
|
||||
actuator endpoint `/refresh` or via publishing a `RefreshRemoteApplicationEvent` using Spring Cloud Bus.
|
||||
|
||||
To achieve this configuration refresh of a Spring Cloud app running on Kubernetes, you can deploy the Spring Cloud
|
||||
Kubernetes Configuration Watcher controller into your Kubernetes cluster.
|
||||
|
||||
The application is published as a container and is available on https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-configuration-watcher[Docker Hub].
|
||||
However, if you need to customize the config watcher behavior or prefer to build the image yourself you can easily build your own
|
||||
image from the https://github.com/spring-cloud/spring-cloud-kubernetes/tree/main/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configuration-watcher[source code on GitHub] and use that.
|
||||
|
||||
Spring Cloud Kubernetes Configuration Watcher can send refresh notifications to applications in two ways.
|
||||
|
||||
1. Over HTTP in which case the application being notified must of the `/refresh` actuator endpoint exposed and accessible from within the cluster
|
||||
2. Using Spring Cloud Bus, in which case you will need a message broker deployed to your custer for the application to use.
|
||||
|
||||
### Deployment YAML
|
||||
|
||||
Below is a sample deployment YAML you can use to deploy the Kubernetes Configuration Watcher to Kubernetes.
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
name: spring-cloud-kubernetes-configuration-watcher
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8888
|
||||
targetPort: 8888
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
type: ClusterIP
|
||||
- apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
name: spring-cloud-kubernetes-configuration-watcher
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
name: spring-cloud-kubernetes-configuration-watcher:view
|
||||
roleRef:
|
||||
kind: Role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: namespace-reader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: spring-cloud-kubernetes-configuration-watcher
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
namespace: default
|
||||
name: namespace-reader
|
||||
rules:
|
||||
- apiGroups: ["", "extensions", "apps"]
|
||||
resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-configuration-watcher-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-configuration-watcher
|
||||
spec:
|
||||
serviceAccount: spring-cloud-kubernetes-configuration-watcher
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-configuration-watcher
|
||||
image: springcloud/spring-cloud-kubernetes-configuration-watcher:2.0.1-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8888
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8888
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8888
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
The Service Account and associated Role Binding is important for Spring Cloud Kubernetes Configuration to work properly.
|
||||
The controller needs access to read data about ConfigMaps, Pods, Services, Endpoints and Secrets in the Kubernetes cluster.
|
||||
|
||||
### Monitoring ConfigMaps and Secrets
|
||||
|
||||
Spring Cloud Kubernetes Configuration Watcher will react to changes in ConfigMaps with a label of `spring.cloud.kubernetes.config` with the value `true`
|
||||
or any Secret with a label of `spring.cloud.kubernetes.secret` with the value `true`. If the ConfigMap or Secret does not have either of those labels
|
||||
or the values of those labels is not `true` then any changes will be ignored.
|
||||
|
||||
If a change is made to a ConfigMap or Secret with valid labels then Spring Cloud Kubernetes Configuration Watcher will take the name of the ConfigMap or Secret
|
||||
and send a notification to the application with that name. This might not be enough for your use-case though, you could for example what to:
|
||||
|
||||
- bind a config-map to multiple applications, so that a change inside a single configmap triggers a refresh for many services
|
||||
- have profile based sources trigger events for your application
|
||||
|
||||
For that reasons there is an addition annotation you could specify:
|
||||
|
||||
`spring.cloud.kubernetes.configmap.apps` or `spring.cloud.kubernetes.secret.apps`. It takes a String of apps separated by comma,
|
||||
that specifies the names of applications that will receive a notification when changes happen in this secret/configmap.
|
||||
|
||||
For example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-configmap
|
||||
labels:
|
||||
spring.cloud.kubernetes.config: "true"
|
||||
annotations:
|
||||
spring.cloud.kubernetes.configmap.apps: "app-a, app-b"
|
||||
----
|
||||
====
|
||||
|
||||
### HTTP Implementation
|
||||
|
||||
The HTTP implementation is what is used by default. When this implementation is used Spring Cloud Kubernetes Configuration Watcher and a
|
||||
change to a ConfigMap or Secret occurs then the HTTP implementation will use the Spring Cloud Kubernetes Discovery Client to fetch all
|
||||
instances of the application which match the name of the ConfigMap or Secret and send an HTTP POST request to the application's actuator
|
||||
`/refresh` endpoint. By default it will send the post request to `/actuator/refresh` using the port registered in the discovery client.
|
||||
|
||||
#### Non-Default Management Port and Actuator Path
|
||||
|
||||
If the application is using a non-default actuator path and/or using a different port for the management endpoints, the Kubernetes service for the application
|
||||
can add an annotation called `boot.spring.io/actuator` and set its value to the path and port used by the application. For example
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: config-map-demo
|
||||
name: config-map-demo
|
||||
annotations:
|
||||
boot.spring.io/actuator: http://:9090/myactuator/home
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: config-map-demo
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
Another way you can choose to configure the actuator path and/or management port is by setting
|
||||
`spring.cloud.kubernetes.configuration.watcher.actuatorPath` and `spring.cloud.kubernetes.configuration.watcher.actuatorPort`.
|
||||
|
||||
### Messaging Implementation
|
||||
|
||||
The messaging implementation can be enabled by setting profile to either `bus-amqp` (RabbitMQ) or `bus-kafka` (Kafka) when the Spring Cloud Kubernetes Configuration Watcher
|
||||
application is deployed to Kubernetes.
|
||||
|
||||
### Configuring RabbitMQ
|
||||
|
||||
When the `bus-amqp` profile is enabled you will need to configure Spring RabbitMQ to point it to the location of the RabbitMQ
|
||||
instance you would like to use as well as any credentials necessary to authenticate. This can be done
|
||||
by setting the standard Spring RabbitMQ properties, for example
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
rabbitmq:
|
||||
username: user
|
||||
password: password
|
||||
host: rabbitmq
|
||||
----
|
||||
====
|
||||
|
||||
### Configuring Kafka
|
||||
|
||||
When the `bus-kafka` profile is enabled you will need to configure Spring Kafka to point it to the location of the Kafka Broker
|
||||
instance you would like to use. This can be done by setting the standard Spring Kafka properties, for example
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
kafka:
|
||||
producer:
|
||||
bootstrap-servers: localhost:9092
|
||||
----
|
||||
====
|
||||
@@ -1,214 +0,0 @@
|
||||
[#spring-cloud-kubernetes-discoveryserver]
|
||||
## Spring Cloud Kubernetes Discovery Server
|
||||
|
||||
The Spring Cloud Kubernetes Discovery Server provides HTTP endpoints apps can use to gather information
|
||||
about services available within a Kubernetes cluster. The Spring Cloud Kubernetes Discovery Server
|
||||
can be used by apps using the `spring-cloud-starter-kubernetes-discoveryclient` to provide data to
|
||||
the `DiscoveryClient` implementation provided by that starter.
|
||||
|
||||
### Permissions
|
||||
The Spring Cloud Discovery server uses
|
||||
the Kubernetes API server to get data about Service and Endpoint resrouces so it needs list, watch, and
|
||||
get permissions to use those endpoints. See the below sample Kubernetes deployment YAML for an
|
||||
examlpe of how to configure the Service Account on Kubernetes.
|
||||
|
||||
|
||||
### Endpoints
|
||||
There are three endpoints exposed by the server.
|
||||
|
||||
#### `/apps`
|
||||
|
||||
A `GET` request sent to `/apps` will return a JSON array of available services. Each item contains
|
||||
the name of the Kubernetes service and service instance information. Below is a sample response.
|
||||
|
||||
====
|
||||
[source,json]
|
||||
----
|
||||
[
|
||||
{
|
||||
"name":"spring-cloud-kubernetes-discoveryserver",
|
||||
"serviceInstances":[
|
||||
{
|
||||
"instanceId":"836a2f25-daee-4af2-a1be-aab9ce2b938f",
|
||||
"serviceId":"spring-cloud-kubernetes-discoveryserver",
|
||||
"host":"10.244.1.6",
|
||||
"port":8761,
|
||||
"uri":"http://10.244.1.6:8761",
|
||||
"secure":false,
|
||||
"metadata":{
|
||||
"app":"spring-cloud-kubernetes-discoveryserver",
|
||||
"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"spring-cloud-kubernetes-discoveryserver\"},\"name\":\"spring-cloud-kubernetes-discoveryserver\",\"namespace\":\"default\"},\"spec\":{\"ports\":[{\"name\":\"http\",\"port\":80,\"targetPort\":8761}],\"selector\":{\"app\":\"spring-cloud-kubernetes-discoveryserver\"},\"type\":\"ClusterIP\"}}\n",
|
||||
"http":"8761"
|
||||
},
|
||||
"namespace":"default",
|
||||
"scheme":"http"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"kubernetes",
|
||||
"serviceInstances":[
|
||||
{
|
||||
"instanceId":"1234",
|
||||
"serviceId":"kubernetes",
|
||||
"host":"172.18.0.3",
|
||||
"port":6443,
|
||||
"uri":"http://172.18.0.3:6443",
|
||||
"secure":false,
|
||||
"metadata":{
|
||||
"provider":"kubernetes",
|
||||
"component":"apiserver",
|
||||
"https":"6443"
|
||||
},
|
||||
"namespace":"default",
|
||||
"scheme":"http"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
----
|
||||
====
|
||||
|
||||
#### `/apps/{name}`
|
||||
|
||||
A `GET` request to `/apps/{name}` can be used to get instance data for all instances of a given
|
||||
service. Below is a sample response when a `GET` request is made to `/apps/kubernetes`.
|
||||
|
||||
====
|
||||
[source,json]
|
||||
----
|
||||
[
|
||||
{
|
||||
"instanceId":"1234",
|
||||
"serviceId":"kubernetes",
|
||||
"host":"172.18.0.3",
|
||||
"port":6443,
|
||||
"uri":"http://172.18.0.3:6443",
|
||||
"secure":false,
|
||||
"metadata":{
|
||||
"provider":"kubernetes",
|
||||
"component":"apiserver",
|
||||
"https":"6443"
|
||||
},
|
||||
"namespace":"default",
|
||||
"scheme":"http"
|
||||
}
|
||||
]
|
||||
----
|
||||
====
|
||||
|
||||
#### `/app/{name}/{instanceid}`
|
||||
|
||||
A `GET` request made to `/app/{name}/{instanceid}` will return the instance data for a specific
|
||||
instance of a given service. Below is a sample response when a `GET` request is made to `/app/kubernetes/1234`.
|
||||
|
||||
====
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"instanceId":"1234",
|
||||
"serviceId":"kubernetes",
|
||||
"host":"172.18.0.3",
|
||||
"port":6443,
|
||||
"uri":"http://172.18.0.3:6443",
|
||||
"secure":false,
|
||||
"metadata":{
|
||||
"provider":"kubernetes",
|
||||
"component":"apiserver",
|
||||
"https":"6443"
|
||||
},
|
||||
"namespace":"default",
|
||||
"scheme":"http"
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
### Deployment YAML
|
||||
|
||||
An image of the Spring Cloud Discovery Server is hosted on https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-discoveryserver[Docker Hub].
|
||||
However, if you need to customize the discovery server behavior or prefer to build the image yourself you can easily build your own
|
||||
image from the https://github.com/spring-cloud/spring-cloud-kubernetes/tree/main/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-discoveryserver[source code on GitHub] and use that.
|
||||
|
||||
Below is a sample deployment YAML you can use to deploy the Kubernetes Configuration Watcher to Kubernetes.
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
name: spring-cloud-kubernetes-discoveryserver
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8761
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
type: ClusterIP
|
||||
- apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
name: spring-cloud-kubernetes-discoveryserver
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
name: spring-cloud-kubernetes-discoveryserver:view
|
||||
roleRef:
|
||||
kind: Role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: namespace-reader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: spring-cloud-kubernetes-discoveryserver
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
namespace: default
|
||||
name: namespace-reader
|
||||
rules:
|
||||
- apiGroups: ["", "extensions", "apps"]
|
||||
resources: ["services", "endpoints"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-discoveryserver-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryserver
|
||||
spec:
|
||||
serviceAccount: spring-cloud-kubernetes-discoveryserver
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-discoveryserver
|
||||
image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8761
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8761
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8761
|
||||
|
||||
|
||||
----
|
||||
====
|
||||
@@ -1,59 +0,0 @@
|
||||
[[spring-cloud-kubernetes]]
|
||||
= Spring Cloud Kubernetes
|
||||
|
||||
This reference guide covers how to use Spring Cloud Kubernetes.
|
||||
|
||||
[[why-do-you-need-spring-cloud-kubernetes?]]
|
||||
== Why do you need Spring Cloud Kubernetes?
|
||||
|
||||
Spring Cloud Kubernetes provides implementations of well known Spring Cloud interfaces allowing developers to build and run Spring Cloud applications on Kubernetes. While this project may be useful to you when building a cloud native application, it is also not a requirement in order to deploy a Spring Boot app on Kubernetes. If you are just getting started in your journey to running your Spring Boot app on Kubernetes you can accomplish a lot with nothing more than a basic Spring Boot app and Kubernetes itself. To learn more, you can get started by reading the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#cloud-deployment-kubernetes[Spring Boot reference documentation for deploying to Kubernetes ] and also working through the workshop material https://hackmd.io/@ryanjbaxter/spring-on-k8s-workshop[Spring and Kubernetes].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[[configuration-properties]]
|
||||
== Configuration properties
|
||||
|
||||
To see the list of all Kubernetes related configuration properties please check link:appendix.html[the Appendix page].
|
||||
|
||||
[[building]]
|
||||
== Building
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/building.adoc[]
|
||||
|
||||
[[building-docker-images-on-arm64]]
|
||||
=== Building Docker Images On ARM64
|
||||
|
||||
If you run the Spring Cloud Kuberentes build on an ARM64 machine the docker images
|
||||
used for the integration tests will fail to run due to using the wrong architecture.
|
||||
This is because the Paketo build pack does not yet support ARM64. To work around this you
|
||||
can run the build by passing `-Dspring-boot.build-image.builder=dashaun/builder:tiny` to Maven.
|
||||
|
||||
For example:
|
||||
```
|
||||
./mvnw clean install -Dspring-boot.build-image.builder=dashaun/builder:tiny
|
||||
```
|
||||
|
||||
|
||||
[[contributing]]
|
||||
== Contributing
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/contributing.adoc[]
|
||||
|
||||
[[aot-and-native-image-support]]
|
||||
== AOT and native image support
|
||||
|
||||
At this point, Spring Cloud Kubernetes does not support Spring Boot AOT transformations or native images. Partial support might be added in future releases.
|
||||
78
docs/pom.xml
78
docs/pom.xml
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-docs</artifactId>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Kubernetes Docs</name>
|
||||
<description>Spring Cloud Kubernetes Docs</description>
|
||||
<properties>
|
||||
<docs.main>spring-cloud-kubernetes</docs.main>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<configprops.inclusionPattern>spring.cloud.kubernetes.*</configprops.inclusionPattern>
|
||||
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
|
||||
<!-- Don't upload docs jar to central / repo.spring.io -->
|
||||
<maven-deploy-plugin-default.phase>none</maven-deploy-plugin-default.phase>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src/main/asciidoc</sourceDirectory>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>docs</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
13
header.txt
13
header.txt
@@ -1,13 +0,0 @@
|
||||
Copyright (C) ${project.inceptionYear} ${owner}
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
36
mvnw
vendored
36
mvnw
vendored
@@ -8,7 +8,7 @@
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
@@ -19,7 +19,7 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
# Maven Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
@@ -114,7 +114,6 @@ if $mingw ; then
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
@@ -212,7 +211,11 @@ 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"
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
@@ -221,22 +224,38 @@ else
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
@@ -277,6 +296,11 @@ if $cygwin; then
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# 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
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
|
||||
343
mvnw.cmd
vendored
Executable file → Normal file
343
mvnw.cmd
vendored
Executable file → Normal file
@@ -1,161 +1,182 @@
|
||||
@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 https://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%
|
||||
@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 Maven 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 keystroke 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 by 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.5.6/maven-wrapper-0.5.6.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% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%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%
|
||||
|
||||
386
pom.xml
386
pom.xml
@@ -1,366 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2020 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
|
||||
~
|
||||
~ https://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.
|
||||
~
|
||||
-->
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Kubernetes</name>
|
||||
|
||||
<url>https://cloud.spring.io</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-docs-build</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>Spring Cloud Kubernetes Docs Build</name>
|
||||
<description>Builds Spring Cloud Kubernetes Docs.</description>
|
||||
<url>https://spring.io/projects/spring-cloud-kubernetes</url>
|
||||
<scm>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes</url>
|
||||
<connection>
|
||||
scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git
|
||||
<connection>scm:git:https://github.com/spring-cloud/spring-cloud-kubernetes.git
|
||||
</connection>
|
||||
<developerConnection>
|
||||
scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git
|
||||
scm:git:git@github.com:spring-cloud/spring-cloud-kubernetes.git
|
||||
</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<properties>
|
||||
<!-- Dependency Versions -->
|
||||
<mockito-inline.version>4.8.1</mockito-inline.version>
|
||||
<spring-cloud-commons.version>4.1.0-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>4.1.0-SNAPSHOT</spring-cloud-config.version>
|
||||
<spring-cloud-bus.version>4.1.0-SNAPSHOT</spring-cloud-bus.version>
|
||||
<spring-cloud-contract.version>4.1.0-SNAPSHOT</spring-cloud-contract.version>
|
||||
|
||||
<maven-surefire-plugin.version>3.1.0</maven-surefire-plugin.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>
|
||||
<io.spring.maven.antora-version>0.0.3</io.spring.maven.antora-version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>spring-cloud-kubernetes-dependencies</module>
|
||||
<module>spring-cloud-kubernetes-commons</module>
|
||||
<module>spring-cloud-kubernetes-test-support</module>
|
||||
<module>spring-cloud-kubernetes-client-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-client-config</module>
|
||||
<module>spring-cloud-kubernetes-client-loadbalancer</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-config</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-discovery</module>
|
||||
<module>spring-cloud-kubernetes-client-discovery</module>
|
||||
<module>spring-cloud-starter-kubernetes-fabric8</module>
|
||||
<module>spring-cloud-starter-kubernetes-fabric8-config</module>
|
||||
<module>spring-cloud-starter-kubernetes-fabric8-all</module>
|
||||
<module>spring-cloud-starter-kubernetes-client</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-config</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-loadbalancer</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-all</module>
|
||||
<module>spring-cloud-kubernetes-examples</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-leader</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-istio</module>
|
||||
<module>spring-cloud-kubernetes-controllers</module>
|
||||
<module>spring-cloud-kubernetes-integration-tests</module>
|
||||
<module>docs</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-loadbalancer</module>
|
||||
<module>spring-cloud-starter-kubernetes-fabric8-loadbalancer</module>
|
||||
<module>spring-cloud-kubernetes-discovery</module>
|
||||
<module>spring-cloud-starter-kubernetes-discoveryclient</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-dependencies</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-dependencies</artifactId>
|
||||
<version>${spring-cloud-commons.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-dependencies</artifactId>
|
||||
<version>${spring-cloud-config.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-bus-dependencies</artifactId>
|
||||
<version>${spring-cloud-bus.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-dependencies</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!--Spring Boot 3.1 uses Mockito 5.x. Mockito 5.x has removed support for mockito-inline.-->
|
||||
<!--https://github.com/mockito/mockito/issues/2877-->
|
||||
<!--We need to support both Boot 3.0.x and Boot 3.1.x with Spring Cloud K8s 3.0.x-->
|
||||
<!--To maintain compatibility we manage the version ourselves-->
|
||||
<!-- TODO Remove this and all references to mockito-inline in the next minor -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-bom</artifactId>
|
||||
<version>${mockito-inline.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
<version>${spring-cloud-commons.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>flatten-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<groupId>io.spring.maven.antora</groupId>
|
||||
<artifactId>antora-maven-plugin</artifactId>
|
||||
<version>${io.spring.maven.antora-version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<options>
|
||||
<option>--to-dir=target/antora/site</option>
|
||||
<option>--stacktrace</option>
|
||||
<option>--fetch</option>
|
||||
</options>
|
||||
<environment>
|
||||
<ALGOLIA_API_KEY>9d489079e5ec46dbb238909fee5c9c29</ALGOLIA_API_KEY>
|
||||
<ALGOLIA_APP_ID>WB1FQYI187</ALGOLIA_APP_ID>
|
||||
<ALGOLIA_INDEX_NAME>springcloudkubernetes</ALGOLIA_INDEX_NAME>
|
||||
</environment>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<parallel>all</parallel>
|
||||
<reuseForks>false</reuseForks>
|
||||
<includes>
|
||||
<include>${testsToRun}</include>
|
||||
</includes>
|
||||
</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>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- TODO: move t s-c-build -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-no-snapshots</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireReleaseDeps>
|
||||
<message>No Snapshots Allowed!</message>
|
||||
</requireReleaseDeps>
|
||||
</rules>
|
||||
<fail>false</fail>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>sonar</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-unit-test</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<propertyName>surefireArgLine</propertyName>
|
||||
<destFile>${project.build.directory}/jacoco.exec
|
||||
</destFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>post-unit-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- Sets the path to the file which contains the execution data. -->
|
||||
<dataFile>${project.build.directory}/jacoco.exec
|
||||
</dataFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<parallel>all</parallel>
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
./mvnw -s .settings.xml clean install -Dservice.occurence=${_SERVICE_OCCURENCE} #org.jacoco:jacoco-maven-plugin:prepare-agent install -U -P sonar
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
./mvnw deploy -DskipTests -B -Pfast,deploy ${@}
|
||||
./mvnw dockerfile:push -pl :spring-cloud-kubernetes-configuration-watcher -Pdockerpush ${@}
|
||||
./mvnw dockerfile:push -pl :spring-cloud-kubernetes-discoveryserver -Pdockerpush ${@}
|
||||
./mvnw dockerfile:push -pl :spring-cloud-kubernetes-configserver -Pdockerpush ${@}
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
./mvnw clean install -B -Pdocs ${@}
|
||||
|
||||
118
spring-cloud-kubernetes-client-autoconfig/.flattened-pom.xml
Normal file
118
spring-cloud-kubernetes-client-autoconfig/.flattened-pom.xml
Normal file
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-autoconfig</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<description>Spring Cloud parent pom, managing plugins and dependencies for Spring
|
||||
Cloud projects</description>
|
||||
<url>https://cloud.spring.io/spring-cloud-kubernetes-client-autoconfig</url>
|
||||
<inceptionYear>2017</inceptionYear>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dsyer</id>
|
||||
<name>Dave Syer</name>
|
||||
<email>dsyer at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sgibb</id>
|
||||
<name>Spencer Gibb</name>
|
||||
<email>sgibb at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mgrzejszczak</id>
|
||||
<name>Marcin Grzejszczak</name>
|
||||
<email>mgrzejszczak at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rbaxter</id>
|
||||
<name>Ryan Baxter</name>
|
||||
<email>rbaxter at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>omaciaszeksharma</id>
|
||||
<name>Olga Maciaszek-Sharma</name>
|
||||
<email>omaciaszeksharma at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-autoconfig</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-autoconfig</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-client-autoconfig</url>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-commons</artifactId>
|
||||
<version>3.0.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java</artifactId>
|
||||
<version>17.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java-extended</artifactId>
|
||||
<version>17.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||
<version>3.0.7</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<version>3.0.7</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-client-autoconfig</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java-extended</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-inline</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.info.ConditionalOnEnabledInfoContributor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(HealthIndicator.class)
|
||||
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
|
||||
public class KubernetesClientActuatorConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledHealthIndicator("kubernetes")
|
||||
public KubernetesClientHealthIndicator kubernetesHealthIndicator(PodUtils<V1Pod> podUtils) {
|
||||
return new KubernetesClientHealthIndicator(podUtils);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledInfoContributor("kubernetes")
|
||||
public KubernetesClientInfoContributor kubernetesInfoContributor(PodUtils<V1Pod> podUtils) {
|
||||
return new KubernetesClientInfoContributor(podUtils);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
|
||||
@AutoConfigureAfter(KubernetesCommonsAutoConfiguration.class)
|
||||
public class KubernetesClientAutoConfiguration {
|
||||
|
||||
/**
|
||||
* this bean will be based on
|
||||
* {@link org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties}
|
||||
* in the next major release.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ApiClient apiClient(Environment environment) {
|
||||
ApiClient apiClient = kubernetesApiClient();
|
||||
// it's too early to inject KubernetesClientProperties here, all its properties
|
||||
// are missing. For the time being work-around with reading from the environment.
|
||||
apiClient.setUserAgent(environment.getProperty("spring.cloud.kubernetes.client.user-agent",
|
||||
KubernetesClientProperties.DEFAULT_USER_AGENT));
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CoreV1Api coreApi(ApiClient apiClient) {
|
||||
return new CoreV1Api(apiClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) {
|
||||
return new KubernetesNamespaceProvider(environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public KubernetesClientPodUtils kubernetesPodUtils(CoreV1Api client,
|
||||
KubernetesNamespaceProvider kubernetesNamespaceProvider) {
|
||||
return new KubernetesClientPodUtils(client, kubernetesNamespaceProvider.getNamespace());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import io.kubernetes.client.openapi.models.V1PodSpec;
|
||||
import io.kubernetes.client.openapi.models.V1PodStatus;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.AbstractKubernetesHealthIndicator;
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientHealthIndicator extends AbstractKubernetesHealthIndicator {
|
||||
|
||||
private final PodUtils<V1Pod> utils;
|
||||
|
||||
public KubernetesClientHealthIndicator(PodUtils<V1Pod> utils) {
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getDetails() {
|
||||
V1Pod current = this.utils.currentPod().get();
|
||||
if (current != null) {
|
||||
Map<String, Object> details = CollectionUtils.newHashMap(8);
|
||||
details.put(INSIDE, true);
|
||||
|
||||
V1ObjectMeta meta = current.getMetadata();
|
||||
details.put(NAMESPACE, meta.getNamespace());
|
||||
details.put(POD_NAME, meta.getName());
|
||||
details.put(LABELS, meta.getLabels());
|
||||
|
||||
V1PodStatus status = current.getStatus();
|
||||
details.put(POD_IP, status.getPodIP());
|
||||
details.put(HOST_IP, status.getHostIP());
|
||||
|
||||
V1PodSpec spec = current.getSpec();
|
||||
details.put(SERVICE_ACCOUNT, spec.getServiceAccountName());
|
||||
details.put(NODE_NAME, spec.getNodeName());
|
||||
|
||||
return details;
|
||||
}
|
||||
else {
|
||||
return Collections.singletonMap(INSIDE, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import io.kubernetes.client.openapi.models.V1PodSpec;
|
||||
import io.kubernetes.client.openapi.models.V1PodStatus;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.AbstractKubernetesInfoContributor;
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientInfoContributor extends AbstractKubernetesInfoContributor {
|
||||
|
||||
private final PodUtils<V1Pod> utils;
|
||||
|
||||
public KubernetesClientInfoContributor(PodUtils<V1Pod> utils) {
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getDetails() {
|
||||
V1Pod current = this.utils.currentPod().get();
|
||||
if (current != null) {
|
||||
Map<String, Object> details = CollectionUtils.newHashMap(7);
|
||||
details.put(INSIDE, true);
|
||||
|
||||
V1ObjectMeta meta = current.getMetadata();
|
||||
details.put(NAMESPACE, meta.getNamespace());
|
||||
details.put(POD_NAME, meta.getName());
|
||||
|
||||
V1PodSpec spec = current.getSpec();
|
||||
details.put(SERVICE_ACCOUNT, spec.getServiceAccountName());
|
||||
details.put(NODE_NAME, spec.getNodeName());
|
||||
|
||||
V1PodStatus status = current.getStatus();
|
||||
details.put(POD_IP, status.getPodIP());
|
||||
details.put(HOST_IP, status.getHostIP());
|
||||
|
||||
return details;
|
||||
}
|
||||
return Collections.singletonMap(INSIDE, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import io.kubernetes.client.util.Config;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.EnvReader;
|
||||
import org.springframework.cloud.kubernetes.commons.LazilyInstantiate;
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientPodUtils implements PodUtils<V1Pod> {
|
||||
|
||||
/**
|
||||
* Hostname environment variable name.
|
||||
*/
|
||||
public static final String HOSTNAME = "HOSTNAME";
|
||||
|
||||
/**
|
||||
* KUBERNETES_SERVICE_HOST environment variable name.
|
||||
*/
|
||||
public static final String KUBERNETES_SERVICE_HOST = "KUBERNETES_SERVICE_HOST";
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientPodUtils.class);
|
||||
|
||||
private final CoreV1Api client;
|
||||
|
||||
private final String hostName;
|
||||
|
||||
private final Supplier<V1Pod> current;
|
||||
|
||||
private final String namespace;
|
||||
|
||||
private final String serviceHost;
|
||||
|
||||
public KubernetesClientPodUtils(CoreV1Api client, String namespace) {
|
||||
if (client == null) {
|
||||
throw new IllegalArgumentException("Must provide an instance of KubernetesClient");
|
||||
}
|
||||
|
||||
this.client = client;
|
||||
this.hostName = EnvReader.getEnv(HOSTNAME);
|
||||
this.serviceHost = EnvReader.getEnv(KUBERNETES_SERVICE_HOST);
|
||||
this.current = LazilyInstantiate.using(this::internalGetPod);
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<V1Pod> currentPod() {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsideKubernetes() {
|
||||
return currentPod().get() != null;
|
||||
}
|
||||
|
||||
private V1Pod internalGetPod() {
|
||||
try {
|
||||
if (isServiceHostEnvVarPresent() && isHostNameEnvVarPresent() && isServiceAccountFound()) {
|
||||
LOG.debug("reading pod in namespace : " + namespace);
|
||||
return client.readNamespacedPod(hostName, namespace, null);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (t instanceof ApiException apiException) {
|
||||
LOG.warn("error reading pod, with error : " + apiException.getResponseBody());
|
||||
}
|
||||
LOG.warn("Failed to get pod with name:[" + hostName + "]. You should look into this if things aren't"
|
||||
+ " working as you expect. Are you missing serviceaccount permissions?", t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isServiceHostEnvVarPresent() {
|
||||
return StringUtils.hasLength(serviceHost);
|
||||
}
|
||||
|
||||
private boolean isHostNameEnvVarPresent() {
|
||||
return StringUtils.hasLength(hostName);
|
||||
}
|
||||
|
||||
private boolean isServiceAccountFound() {
|
||||
boolean serviceAccountPathPresent = Paths.get(Config.SERVICEACCOUNT_TOKEN_PATH).toFile().exists();
|
||||
if (!serviceAccountPathPresent) {
|
||||
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
|
||||
LOG.warn("serviceaccount path not present, did you disable it via 'automountServiceAccountToken : false'?"
|
||||
+ " Major functionalities will not work without that property being set");
|
||||
}
|
||||
return serviceAccountPathPresent && Paths.get(Config.SERVICEACCOUNT_CA_PATH).toFile().exists();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public final class KubernetesClientUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientUtils.class);
|
||||
|
||||
private KubernetesClientUtils() {
|
||||
}
|
||||
|
||||
public static ApiClient createApiClientForInformerClient() {
|
||||
ApiClient apiClient = kubernetesApiClient();
|
||||
apiClient.setReadTimeout(0);
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
public static ApiClient kubernetesApiClient() {
|
||||
try {
|
||||
// Assume we are running in a cluster
|
||||
ApiClient apiClient = ClientBuilder.cluster().build();
|
||||
LOG.info("Created API client in the cluster.");
|
||||
return apiClient;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info("Could not create the Kubernetes ApiClient in a cluster environment, because : ", e);
|
||||
LOG.info("Trying to use a \"standard\" configuration to create the Kubernetes ApiClient");
|
||||
try {
|
||||
ApiClient apiClient = ClientBuilder.defaultClient();
|
||||
LOG.info("Created standard API client. Unless $KUBECONFIG or $HOME/.kube/config is defined, "
|
||||
+ "this client will try to connect to localhost:8080");
|
||||
return apiClient;
|
||||
}
|
||||
catch (Exception e1) {
|
||||
LOG.warn("Could not create a Kubernetes ApiClient from either a cluster or standard environment. "
|
||||
+ "Will return one that always connects to localhost:8080", e1);
|
||||
return new ClientBuilder().build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method does the namespace resolution for both config map and secrets
|
||||
* implementations. It tries these places to find the namespace:
|
||||
*
|
||||
* <pre>
|
||||
* 1. from a normalized source (which can be null)
|
||||
* 2. from a property 'spring.cloud.kubernetes.client.namespace', if such is present
|
||||
* 3. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath`
|
||||
* property, if such is present
|
||||
* 4. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file,
|
||||
* if such is present (kubernetes default path)
|
||||
* </pre>
|
||||
*
|
||||
* If any of the above fail, we throw a NamespaceResolutionFailedException.
|
||||
* @param namespace normalized namespace
|
||||
* @param configurationTarget Config Map/Secret
|
||||
* @param provider the provider which computes the namespace
|
||||
* @return application namespace
|
||||
* @throws NamespaceResolutionFailedException when namespace could not be resolved
|
||||
*/
|
||||
public static String getApplicationNamespace(String namespace, String configurationTarget,
|
||||
KubernetesNamespaceProvider provider) {
|
||||
if (StringUtils.hasText(namespace)) {
|
||||
LOG.debug(configurationTarget + " namespace : " + namespace);
|
||||
return namespace;
|
||||
}
|
||||
|
||||
if (provider != null) {
|
||||
String providerNamespace = provider.getNamespace();
|
||||
if (StringUtils.hasText(providerNamespace)) {
|
||||
LOG.debug(configurationTarget + " namespace from provider : " + namespace);
|
||||
return providerNamespace;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NamespaceResolutionFailedException("unresolved namespace");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client.profile;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.KubernetesClientPodUtils;
|
||||
import org.springframework.cloud.kubernetes.commons.profile.AbstractKubernetesProfileEnvironmentPostProcessor;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static io.kubernetes.client.util.Config.ENV_SERVICE_HOST;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
public class KubernetesClientProfileEnvironmentPostProcessor extends AbstractKubernetesProfileEnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
protected boolean isInsideKubernetes(Environment environment) {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
KubernetesClientPodUtils utils = new KubernetesClientPodUtils(api, environment.getProperty(NAMESPACE_PROPERTY));
|
||||
return environment.containsProperty(ENV_SERVICE_HOST) || utils.isInsideKubernetes();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.cloud.kubernetes.client.profile.KubernetesClientProfileEnvironmentPostProcessor
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration
|
||||
org.springframework.cloud.kubernetes.client.KubernetesClientActuatorConfiguration
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalManagementPort;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = { "management.health.kubernetes.enabled=false", "management.endpoint.health.show-details=always",
|
||||
"management.endpoint.health.show-components=always", "spring.main.cloud-platform=KUBERNETES",
|
||||
"management.endpoints.web.exposure.include=health" })
|
||||
class ActuatorDisabledHealthTest {
|
||||
|
||||
@Autowired
|
||||
private ReactiveHealthContributorRegistry registry;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@LocalManagementPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
void healthEndpointShouldNotContainKubernetes() {
|
||||
this.webClient.get().uri("http://localhost:{port}/actuator/health", this.port)
|
||||
.accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("components.kubernetes").doesNotExist();
|
||||
|
||||
Assertions.assertNull(registry.getContributor("kubernetes"),
|
||||
"reactive kubernetes contributor must NOT be present when 'management.health.kubernetes.enabled=false'");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalManagementPort;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = { "management.health.kubernetes.enabled=true", "management.endpoint.health.show-details=always",
|
||||
"management.endpoint.health.show-components=always", "management.endpoints.web.exposure.include=health",
|
||||
"spring.main.cloud-platform=KUBERNETES" })
|
||||
class ActuatorEnabledHealthTest {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@Autowired
|
||||
private ReactiveHealthContributorRegistry registry;
|
||||
|
||||
@LocalManagementPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
void healthEndpointShouldContainKubernetes() {
|
||||
this.webClient.get().uri("http://localhost:{port}/actuator/health", this.port)
|
||||
.accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("components.kubernetes").exists();
|
||||
|
||||
Assertions.assertNotNull(registry.getContributor("kubernetes"),
|
||||
"reactive kubernetes contributor must be present when 'management.health.kubernetes.enabled=true'");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = "spring.main.cloud-platform=KUBERNETES")
|
||||
public class KubernetesClientHealthIndicatorInsideTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
// test that the bean responsible for health is present.
|
||||
// the actual fields it must provide are tested in
|
||||
// KubernetesClientHealthIndicatorTests.
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(context.getBean(KubernetesClientHealthIndicator.class)).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = { "management.health.kubernetes.enabled=false" })
|
||||
public class KubernetesClientHealthIndicatorNotInsideTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
// test that the bean responsible for info contribution is NOT present.
|
||||
@Test
|
||||
public void test() {
|
||||
assertThatThrownBy(() -> context.getBean(KubernetesClientHealthIndicator.class))
|
||||
.isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.HOST_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.INSIDE;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.LABELS;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.NAMESPACE;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.NODE_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.POD_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.POD_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.SERVICE_ACCOUNT;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_HOST_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_LABELS;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_NAMESPACE;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_NODE_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_POD_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_POD_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_SERVICE_ACCOUNT;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class KubernetesClientHealthIndicatorTests {
|
||||
|
||||
@Mock
|
||||
private PodUtils<V1Pod> utils;
|
||||
|
||||
@Test
|
||||
void getDetailsNotInsideTest() {
|
||||
when(utils.currentPod()).thenReturn(() -> null);
|
||||
KubernetesClientHealthIndicator healthIndicator = new KubernetesClientHealthIndicator(utils);
|
||||
Map<String, Object> details = healthIndicator.getDetails();
|
||||
|
||||
assertThat(details.size()).isEqualTo(1);
|
||||
assertThat(details.get(INSIDE)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDetailsInsideTest() {
|
||||
|
||||
when(utils.currentPod()).thenReturn(StubProvider::stubPod);
|
||||
KubernetesClientHealthIndicator healthIndicator = new KubernetesClientHealthIndicator(utils);
|
||||
Map<String, Object> details = healthIndicator.getDetails();
|
||||
|
||||
assertThat(details.size()).isEqualTo(8);
|
||||
assertThat(details.get(INSIDE)).isEqualTo(true);
|
||||
|
||||
assertThat(details.get(HOST_IP)).isEqualTo(STUB_HOST_IP);
|
||||
assertThat(details.get(POD_IP)).isEqualTo(STUB_POD_IP);
|
||||
assertThat(details.get(NODE_NAME)).isEqualTo(STUB_NODE_NAME);
|
||||
assertThat(details.get(SERVICE_ACCOUNT)).isEqualTo(STUB_SERVICE_ACCOUNT);
|
||||
assertThat(details.get(POD_NAME)).isEqualTo(STUB_POD_NAME);
|
||||
assertThat(details.get(NAMESPACE)).isEqualTo(STUB_NAMESPACE);
|
||||
assertThat(details.get(LABELS)).isEqualTo(STUB_LABELS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = "spring.main.cloud-platform=KUBERNETES")
|
||||
public class KubernetesClientInfoContributorInsideTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
// test that the bean responsible for info contribution is present.
|
||||
// the actual fields it must provide are tested in
|
||||
// KubernetesClientInfoContributorTests.
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(context.getBean(KubernetesClientInfoContributor.class)).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.client.example.App;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
properties = { "management.info.kubernetes.enabled=false" })
|
||||
public class KubernetesClientInfoContributorNotInsideTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
// test that the bean responsible for info contribution is NOT present.
|
||||
@Test
|
||||
public void test() {
|
||||
assertThatThrownBy(() -> context.getBean(KubernetesClientInfoContributor.class))
|
||||
.isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.HOST_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.INSIDE;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.NAMESPACE;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.NODE_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.POD_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.POD_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientHealthIndicator.SERVICE_ACCOUNT;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_HOST_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_NAMESPACE;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_NODE_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_POD_IP;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_POD_NAME;
|
||||
import static org.springframework.cloud.kubernetes.client.StubProvider.STUB_SERVICE_ACCOUNT;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class KubernetesClientInfoContributorTests {
|
||||
|
||||
@Mock
|
||||
private PodUtils<V1Pod> utils;
|
||||
|
||||
@Test
|
||||
void getDetailsIsNotInside() {
|
||||
when(utils.currentPod()).thenReturn(() -> null);
|
||||
KubernetesClientInfoContributor infoContributor = new KubernetesClientInfoContributor(utils);
|
||||
Map<String, Object> details = infoContributor.getDetails();
|
||||
|
||||
assertThat(details.size()).isEqualTo(1);
|
||||
assertThat(details.get(INSIDE)).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDetailsInside() {
|
||||
|
||||
when(utils.currentPod()).thenReturn(StubProvider::stubPod);
|
||||
KubernetesClientInfoContributor infoContributor = new KubernetesClientInfoContributor(utils);
|
||||
Map<String, Object> details = infoContributor.getDetails();
|
||||
|
||||
assertThat(details.size()).isEqualTo(7);
|
||||
assertThat(details.get(INSIDE)).isEqualTo(true);
|
||||
|
||||
assertThat(details.get(HOST_IP)).isEqualTo(STUB_HOST_IP);
|
||||
assertThat(details.get(POD_IP)).isEqualTo(STUB_POD_IP);
|
||||
assertThat(details.get(NODE_NAME)).isEqualTo(STUB_NODE_NAME);
|
||||
assertThat(details.get(SERVICE_ACCOUNT)).isEqualTo(STUB_SERVICE_ACCOUNT);
|
||||
assertThat(details.get(POD_NAME)).isEqualTo(STUB_POD_NAME);
|
||||
assertThat(details.get(NAMESPACE)).isEqualTo(STUB_NAMESPACE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import io.kubernetes.client.util.Config;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.EnvReader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public class KubernetesClientPodUtilsTests {
|
||||
|
||||
private static final String KUBERNETES_SERVICE_HOST = KubernetesClientPodUtils.KUBERNETES_SERVICE_HOST;
|
||||
|
||||
private static final String HOSTNAME = KubernetesClientPodUtils.HOSTNAME;
|
||||
|
||||
private static final String SERVICE_ACCOUNT_TOKEN_PATH = Config.SERVICEACCOUNT_TOKEN_PATH;
|
||||
|
||||
private static final String SERVICE_ACCOUNT_CERT_PATH = Config.SERVICEACCOUNT_CA_PATH;
|
||||
|
||||
private static final String POD_HOSTNAME = "pod-hostname";
|
||||
|
||||
private static final String HOST = "10.1.1.1";
|
||||
|
||||
private static final V1Pod POD = new V1Pod();
|
||||
|
||||
private final CoreV1Api client = Mockito.mock(CoreV1Api.class);
|
||||
|
||||
private final Path tokenPath = Mockito.mock(Path.class);
|
||||
|
||||
private final File tokenFile = Mockito.mock(File.class);
|
||||
|
||||
private final Path certPath = Mockito.mock(Path.class);
|
||||
|
||||
private final File certFile = Mockito.mock(File.class);
|
||||
|
||||
private MockedStatic<EnvReader> envReader;
|
||||
|
||||
private MockedStatic<Paths> paths;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
envReader = Mockito.mockStatic(EnvReader.class);
|
||||
paths = Mockito.mockStatic(Paths.class);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
envReader.close();
|
||||
paths.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorThrowsIllegalArgumentExceptionWhenKubeClientIsNull() {
|
||||
assertThatThrownBy(() -> new KubernetesClientPodUtils(null, "namespace"))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Must provide an instance of KubernetesClient");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceHostNotPresent() {
|
||||
mockHost(null);
|
||||
|
||||
KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace");
|
||||
Supplier<V1Pod> sup = util.currentPod();
|
||||
assertSupplierAndClient(sup, util);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostNameNotPresent() {
|
||||
mockHost(HOST);
|
||||
mockHostname(null);
|
||||
|
||||
KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace");
|
||||
Supplier<V1Pod> sup = util.currentPod();
|
||||
assertSupplierAndClient(sup, util);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceAccountPathNotPresent() {
|
||||
mockTokenPath(false);
|
||||
mockHostname(HOST);
|
||||
|
||||
KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace");
|
||||
Supplier<V1Pod> sup = util.currentPod();
|
||||
assertSupplierAndClient(sup, util);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceAccountCertPathNotPresent() {
|
||||
mockTokenPath(true);
|
||||
mockCertPath(false);
|
||||
mockHostname(HOST);
|
||||
|
||||
KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace");
|
||||
Supplier<V1Pod> sup = util.currentPod();
|
||||
assertSupplierAndClient(sup, util);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allPresent() throws ApiException {
|
||||
mockTokenPath(true);
|
||||
mockCertPath(true);
|
||||
mockHost(HOST);
|
||||
mockHostname(POD_HOSTNAME);
|
||||
mockPodResult();
|
||||
|
||||
KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace");
|
||||
Supplier<V1Pod> sup = util.currentPod();
|
||||
assertThat(sup.get()).isNotNull();
|
||||
assertThat(util.isInsideKubernetes()).isTrue();
|
||||
}
|
||||
|
||||
private void assertSupplierAndClient(Supplier<V1Pod> sup, KubernetesClientPodUtils util) {
|
||||
assertThat(sup.get()).isNull();
|
||||
assertThat(util.isInsideKubernetes()).isFalse();
|
||||
}
|
||||
|
||||
private void mockHost(String host) {
|
||||
envReader.when(() -> EnvReader.getEnv(KUBERNETES_SERVICE_HOST)).thenReturn(host);
|
||||
}
|
||||
|
||||
private void mockHostname(String name) {
|
||||
envReader.when(() -> EnvReader.getEnv(HOSTNAME)).thenReturn(name);
|
||||
}
|
||||
|
||||
private void mockTokenPath(boolean result) {
|
||||
Mockito.when(tokenPath.toFile()).thenReturn(tokenFile);
|
||||
Mockito.when(tokenFile.exists()).thenReturn(result);
|
||||
paths.when(() -> Paths.get(SERVICE_ACCOUNT_TOKEN_PATH)).thenReturn(tokenPath);
|
||||
}
|
||||
|
||||
private void mockCertPath(boolean result) {
|
||||
Mockito.when(certPath.toFile()).thenReturn(certFile);
|
||||
Mockito.when(certFile.exists()).thenReturn(result);
|
||||
paths.when(() -> Paths.get(SERVICE_ACCOUNT_CERT_PATH)).thenReturn(certPath);
|
||||
}
|
||||
|
||||
private void mockPodResult() throws ApiException {
|
||||
Mockito.when(client.readNamespacedPod(POD_HOSTNAME, "namespace", null)).thenReturn(POD);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
class KubernetesClientUtilsTests {
|
||||
|
||||
private final KubernetesNamespaceProvider provider = Mockito.mock(KubernetesNamespaceProvider.class);
|
||||
|
||||
@Test
|
||||
void testNamespaceFromNormalizedSource() {
|
||||
String result = KubernetesClientUtils.getApplicationNamespace("abc", "target", null);
|
||||
assertThat(result).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceFromProvider() {
|
||||
Mockito.when(provider.getNamespace()).thenReturn("def");
|
||||
String result = KubernetesClientUtils.getApplicationNamespace("", "target", provider);
|
||||
assertThat(result).isEqualTo("def");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceResolutionFailed() {
|
||||
assertThatThrownBy(() -> KubernetesClientUtils.getApplicationNamespace("", "target", null))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Pod;
|
||||
import io.kubernetes.client.openapi.models.V1PodSpec;
|
||||
import io.kubernetes.client.openapi.models.V1PodStatus;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
final class StubProvider {
|
||||
|
||||
static final String STUB_POD_IP = "127.0.0.1";
|
||||
|
||||
static final String STUB_HOST_IP = "123.456.789.1";
|
||||
|
||||
static final String STUB_NODE_NAME = "nodeName";
|
||||
|
||||
static final String STUB_SERVICE_ACCOUNT = "serviceAccount";
|
||||
|
||||
static final String STUB_POD_NAME = "mypod";
|
||||
|
||||
static final String STUB_NAMESPACE = "default";
|
||||
|
||||
static final Map<String, String> STUB_LABELS = Collections.singletonMap("spring", "cloud");
|
||||
|
||||
private StubProvider() {
|
||||
}
|
||||
|
||||
static V1Pod stubPod() {
|
||||
|
||||
V1ObjectMeta metaData = new V1ObjectMeta().labels(STUB_LABELS).name(STUB_POD_NAME).namespace(STUB_NAMESPACE);
|
||||
V1PodStatus status = new V1PodStatus().podIP(STUB_POD_IP).hostIP(STUB_HOST_IP);
|
||||
V1PodSpec spec = new V1PodSpec().nodeName(STUB_NODE_NAME).serviceAccountName(STUB_SERVICE_ACCOUNT);
|
||||
|
||||
return new V1Pod().metadata(metaData).status(status).spec(spec);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user