diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 7b6906c0e5..0000000000 --- a/.editorconfig +++ /dev/null @@ -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 diff --git a/.flattened-pom.xml b/.flattened-pom.xml new file mode 100644 index 0000000000..b8bb8fabfc --- /dev/null +++ b/.flattened-pom.xml @@ -0,0 +1,138 @@ + + + + 4.0.0 + + org.springframework.cloud + spring-cloud-build + 4.0.4-SNAPSHOT + + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + pom + Spring Cloud Kubernetes + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git + https://github.com/spring-cloud/spring-cloud-kubernetes + + + + spring + + + + false + + + true + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + + + false + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + false + + spring-releases + Spring Releases + https://repo.spring.io/release + + + + + diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100755 index aeafef9d32..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -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. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100755 index bbcbbe7d61..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -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. diff --git a/.github/workflows/composites/build-controllers-project/action.yaml b/.github/workflows/composites/build-controllers-project/action.yaml deleted file mode 100644 index 307451c8f5..0000000000 --- a/.github/workflows/composites/build-controllers-project/action.yaml +++ /dev/null @@ -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 .. diff --git a/.github/workflows/composites/build-integration-tests-project/action.yaml b/.github/workflows/composites/build-integration-tests-project/action.yaml deleted file mode 100644 index 23fbb33aa8..0000000000 --- a/.github/workflows/composites/build-integration-tests-project/action.yaml +++ /dev/null @@ -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 .. diff --git a/.github/workflows/composites/cache/action.yaml b/.github/workflows/composites/cache/action.yaml deleted file mode 100644 index 792bb396c8..0000000000 --- a/.github/workflows/composites/cache/action.yaml +++ /dev/null @@ -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') }} - diff --git a/.github/workflows/composites/clean-space/action.yaml b/.github/workflows/composites/clean-space/action.yaml deleted file mode 100644 index 69d61642fd..0000000000 --- a/.github/workflows/composites/clean-space/action.yaml +++ /dev/null @@ -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 diff --git a/.github/workflows/composites/env-variables/action.yaml b/.github/workflows/composites/env-variables/action.yaml deleted file mode 100644 index a1d6764ff3..0000000000 --- a/.github/workflows/composites/env-variables/action.yaml +++ /dev/null @@ -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 diff --git a/.github/workflows/composites/matrix-bounds-on-test-times-cache-hit/action.yaml b/.github/workflows/composites/matrix-bounds-on-test-times-cache-hit/action.yaml deleted file mode 100644 index 4badaf1b57..0000000000 --- a/.github/workflows/composites/matrix-bounds-on-test-times-cache-hit/action.yaml +++ /dev/null @@ -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 diff --git a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml b/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml deleted file mode 100644 index 3230b5945f..0000000000 --- a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml +++ /dev/null @@ -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 - diff --git a/.github/workflows/composites/pre-test-actions/action.yaml b/.github/workflows/composites/pre-test-actions/action.yaml deleted file mode 100644 index d2bb6b96b9..0000000000 --- a/.github/workflows/composites/pre-test-actions/action.yaml +++ /dev/null @@ -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 - - - - diff --git a/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml b/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml deleted file mode 100644 index 39e79ebdd7..0000000000 --- a/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml +++ /dev/null @@ -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 - - diff --git a/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml b/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml deleted file mode 100644 index ce8c81cff3..0000000000 --- a/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml +++ /dev/null @@ -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 diff --git a/.github/workflows/composites/save-controller-images/action.yaml b/.github/workflows/composites/save-controller-images/action.yaml deleted file mode 100644 index 056b1b2adb..0000000000 --- a/.github/workflows/composites/save-controller-images/action.yaml +++ /dev/null @@ -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 .. diff --git a/.github/workflows/composites/save-integration-tests-images/action.yaml b/.github/workflows/composites/save-integration-tests-images/action.yaml deleted file mode 100644 index cbc92e55f7..0000000000 --- a/.github/workflows/composites/save-integration-tests-images/action.yaml +++ /dev/null @@ -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 .. diff --git a/.github/workflows/composites/setup-jdk1.8/action.yaml b/.github/workflows/composites/setup-jdk1.8/action.yaml deleted file mode 100755 index 7dab637584..0000000000 --- a/.github/workflows/composites/setup-jdk1.8/action.yaml +++ /dev/null @@ -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' diff --git a/.github/workflows/composites/setup-jdk17/action.yaml b/.github/workflows/composites/setup-jdk17/action.yaml deleted file mode 100755 index 19dcd374ab..0000000000 --- a/.github/workflows/composites/setup-jdk17/action.yaml +++ /dev/null @@ -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' diff --git a/.github/workflows/composites/test-bounds/action.yaml b/.github/workflows/composites/test-bounds/action.yaml deleted file mode 100644 index a9a1738bb7..0000000000 --- a/.github/workflows/composites/test-bounds/action.yaml +++ /dev/null @@ -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 diff --git a/.github/workflows/composites/test-times/action.yaml b/.github/workflows/composites/test-times/action.yaml deleted file mode 100644 index 33d2c13bfe..0000000000 --- a/.github/workflows/composites/test-times/action.yaml +++ /dev/null @@ -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 .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 }} diff --git a/.github/workflows/composites/upload-docker-images/action.yaml b/.github/workflows/composites/upload-docker-images/action.yaml deleted file mode 100644 index 83c7657e19..0000000000 --- a/.github/workflows/composites/upload-docker-images/action.yaml +++ /dev/null @@ -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 }} - - diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000000..0f3db977a0 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -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 }} diff --git a/.github/workflows/maven.yaml b/.github/workflows/maven.yaml deleted file mode 100644 index 6264d4c008..0000000000 --- a/.github/workflows/maven.yaml +++ /dev/null @@ -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 diff --git a/.gitignore b/.gitignore index 74b4110323..6be8a4a166 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.mvn/maven.config b/.mvn/maven.config deleted file mode 100644 index 3b8cf46e1e..0000000000 --- a/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local -P spring diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java old mode 100755 new mode 100644 index 1f38b9c899..b901097f2d --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -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(); + } } diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100755 new mode 100644 index 01e6799737..2cc7d4a55c Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index 00d32aab1d..642d572ce9 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -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 \ No newline at end of file +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 diff --git a/.sdkmanrc b/.sdkmanrc deleted file mode 100644 index 415f90832f..0000000000 --- a/.sdkmanrc +++ /dev/null @@ -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 diff --git a/.settings.xml b/.settings.xml deleted file mode 100644 index c8add61d78..0000000000 --- a/.settings.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - repo.spring.io - ${env.CI_DEPLOY_USERNAME} - ${env.CI_DEPLOY_PASSWORD} - - - - - - spring - - true - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - diff --git a/.springformat b/.springformat deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9b259bdfcf..0000000000 --- a/LICENSE +++ /dev/null @@ -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. diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 7a1eb797b8..0000000000 --- a/NOTICE +++ /dev/null @@ -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 diff --git a/README.adoc b/README.adoc index 5dfeafc2aa..0165454393 100644 --- a/README.adoc +++ b/README.adoc @@ -1,2484 +1,23 @@ -//// -DO NOT EDIT THIS FILE. IT WAS GENERATED. -Manual changes to this file will be lost when it is generated again. -Edit the files in the src/main/asciidoc/ directory instead. -//// += Spring Cloud Kubernetes Docs Build +You're currently viewing the Antora playbook branch. +The playbook branch hosts the docs build that is used to build and publish the production docs site. -= Spring Cloud Kubernetes -:doctype: book -:idprefix: -:idseparator: - -:toc: left -:toclevels: 4 -:tabsize: 4 -:numbered: -:sectanchors: -:sectnums: -:icons: font -:hide-uri-scheme: -:docinfo: shared,private +The Spring Cloud Kubernetes reference docs are built using https://antora.org[Antora]. +This README covers how to build the docs in a software branch as well as how to build the production docs site locally. -:sc-ext: java -:project-full-name: Spring Cloud Kubernetes -:all: {asterisk}{asterisk} +== Building the Site -This reference guide covers how to use Spring Cloud Kubernetes. +You can build the entire site by invoking the following on the docs-build branch and then viewing the site at `target/site/index.html` -== 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]. - -== 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 ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8 - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client - ----- -| <> implementation that -resolves service names to Kubernetes Services. - -| [source,xml] -.Fabric8 Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-config - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-config - ----- -| Load application properties from Kubernetes -<> and <>. -<> application properties when a ConfigMap or -Secret changes. - -| [source,xml] -.Fabric8 Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-all - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-all - ----- -| All Spring Cloud Kubernetes features. -|=== - -== 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] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-discoveryclient - ----- -==== - -NOTE: `spring-cloud-starter-kubernetes-discoveryclient` is designed to be used with the -<>. - -==== -Fabric8 Kubernetes Client -[source,xml] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8 - ----- -==== - -==== -Kubernetes Java Client -[source,xml] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client - ----- -==== - -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.adoc#namespace-resolution[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"] -``` - -== Kubernetes native service discovery - -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=` - -== Kubernetes PropertySource implementations - -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. - -[[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 <> 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. -|=== - -=== 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 +./mvnw antora ---- -==== -+ -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 ----- -==== +== Building a Specific Branch -. 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 +./mvnw antora ---- -==== - -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 <> to get a better understanding of how the namespace -of the application is resolved. - -<>; 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 <>. -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] - -[[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. - -[[order_of_configMaps_and_secrets]] -=== Order of ConfigMaps and Secrets - -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. - -=== `PropertySource` Reload - -WARNING: This functionality has been deprecated in the 2020.0 release. Please see -the <> 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. -<> 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. - -[[namespace-label-filtering]] -=== Reload namespace and label filtering -By default, a namespace chosen using the steps outlined in <> 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. - -== 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 - -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 - -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 - -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. - -== Pod Health Indicator - -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]`. - -== Info Contributor - -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]`. - -== 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] ----- - - org.springframework.cloud - spring-cloud-kubernetes-fabric8-leader - ----- -==== - -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 ----- -==== - -== 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] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-loadbalancer - ----- -==== - -==== -Kubernetes Java Client Implementation -[source,xml] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-loadbalancer - ----- -==== - -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. - -== Security Configurations Inside Kubernetes - - -=== 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 - -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: "" ----- -==== - -== Service Registry Implementation - -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. - -[#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 ----- -==== - -[#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 - ----- -==== - -[#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 - - ----- -==== - -== Examples - -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] - -== Other Resources - -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]. - -== Configuration properties - -To see the list of all Kubernetes related configuration properties please check link:appendix.html[the Appendix page]. - -== Building - -:jdkversion: 17 - -=== Basic Compile and Test - -To build the source you will need to install JDK {jdkversion}. - -Spring Cloud uses Maven for most build-related activities, and you -should be able to get off the ground quite quickly by cloning the -project you are interested in and typing - ----- -$ ./mvnw install ----- - -NOTE: You can also install Maven (>=3.3.3) yourself and run the `mvn` command -in place of `./mvnw` in the examples below. If you do that you also -might need to add `-P spring` if your local Maven settings do not -contain repository declarations for spring pre-release artifacts. - -NOTE: Be aware that you might need to increase the amount of memory -available to Maven by setting a `MAVEN_OPTS` environment variable with -a value like `-Xmx512m -XX:MaxPermSize=128m`. We try to cover this in -the `.mvn` configuration, so if you find you have to do it to make a -build succeed, please raise a ticket to get the settings added to -source control. - -The projects that require middleware (i.e. Redis) for testing generally -require that a local instance of [Docker](https://www.docker.com/get-started) is installed and running. - - -=== Documentation - -The spring-cloud-build module has a "docs" profile, and if you switch -that on it will try to build asciidoc sources from -`src/main/asciidoc`. As part of that process it will look for a -`README.adoc` and process it by loading all the includes, but not -parsing or rendering it, just copying it to `${main.basedir}` -(defaults to `${basedir}`, i.e. the root of the project). If there are -any changes in the README it will then show up after a Maven build as -a modified file in the correct place. Just commit it and push the change. - -=== Working with the code -If you don't have an IDE preference we would recommend that you use -https://www.springsource.com/developer/sts[Spring Tools Suite] or -https://eclipse.org[Eclipse] when working with the code. We use the -https://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools -should also work without issue as long as they use Maven 3.3.3 or better. - -==== Activate the Spring Maven profile -Spring Cloud projects require the 'spring' Maven profile to be activated to resolve -the spring milestone and snapshot repositories. Use your preferred IDE to set this -profile to be active, or you may experience build errors. - -==== Importing into eclipse with m2eclipse -We recommend the https://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with -eclipse. If you don't already have m2eclipse installed it is available from the "eclipse -marketplace". - -NOTE: Older versions of m2e do not support Maven 3.3, so once the -projects are imported into Eclipse you will also need to tell -m2eclipse to use the right profile for the projects. If you -see many different errors related to the POMs in the projects, check -that you have an up to date installation. If you can't upgrade m2e, -add the "spring" profile to your `settings.xml`. Alternatively you can -copy the repository settings from the "spring" profile of the parent -pom into your `settings.xml`. - -==== Importing into eclipse without m2eclipse -If you prefer not to use m2eclipse you can generate eclipse project metadata using the -following command: - -[indent=0] ----- - $ ./mvnw eclipse:eclipse ----- - -The generated eclipse projects can be imported by selecting `import existing projects` -from the `file` menu. - - -=== 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 - -:spring-cloud-build-branch: master - -Spring Cloud is released under the non-restrictive Apache 2.0 license, -and follows a very standard Github development process, using Github -tracker for issues and merging pull requests into master. If you want -to contribute even something trivial please do not hesitate, but -follow the guidelines below. - -=== Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. - -=== Code of Conduct -This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of -conduct]. By participating, you are expected to uphold this code. Please report -unacceptable behavior to spring-code-of-conduct@pivotal.io. - -=== Code Conventions and Housekeeping -None of these is essential for a pull request, but they will all help. They can also be -added after the original pull request but before a merge. - -* Use the Spring Framework code format conventions. If you use Eclipse - you can import formatter settings using the - `eclipse-code-formatter.xml` file from the - https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring - Cloud Build] project. If using IntelliJ, you can use the - https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter - Plugin] to import the same file. -* Make sure all new `.java` files to have a simple Javadoc class comment with at least an - `@author` tag identifying you, and preferably at least a paragraph on what the class is - for. -* Add the ASF license header comment to all new `.java` files (copy from existing files - in the project) -* Add yourself as an `@author` to the .java files that you modify substantially (more - than cosmetic changes). -* Add some Javadocs and, if you change the namespace, some XSD doc elements. -* A few unit tests would help a lot as well -- someone has to do it. -* If no-one else is using your branch, please rebase it against the current master (or - other target branch in the main project). -* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions], - if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit - message (where XXXX is the issue number). - -=== Checkstyle - -Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are: - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    └── checkstyle.xml <1> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules - -==== Checkstyle configuration - -Checkstyle rules are *disabled by default*. To add checkstyle to your project just define the following properties and plugins. - -.pom.xml ----- - -true <1> - true - <2> - true - <3> - - - - - <4> - io.spring.javaformat - spring-javaformat-maven-plugin - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - ----- -<1> Fails the build upon Checkstyle errors -<2> Fails the build upon Checkstyle violations -<3> Checkstyle analyzes also the test sources -<4> Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules -<5> Add checkstyle plugin to your build and reporting phases - -If you need to suppress some rules (e.g. line length needs to be longer), then it's enough for you to define a file under `${project.root}/src/checkstyle/checkstyle-suppressions.xml` with your suppressions. Example: - -.projectRoot/src/checkstyle/checkstyle-suppresions.xml ----- - - - - - - ----- - -It's advisable to copy the `${spring-cloud-build.rootFolder}/.editorconfig` and `${spring-cloud-build.rootFolder}/.springformat` to your project. That way, some default formatting rules will be applied. You can do so by running this script: - -```bash -$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig -$ touch .springformat -``` - -=== IDE setup - -==== Intellij IDEA - -In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin. -The following files can be found in the https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools[Spring Cloud Build] project. - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    ├── checkstyle.xml <1> -    └── intellij -       ├── Intellij_Project_Defaults.xml <4> -       └── Intellij_Spring_Boot_Java_Conventions.xml <5> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules -<4> Project defaults for Intellij that apply most of Checkstyle rules -<5> Project style conventions for Intellij that apply most of Checkstyle rules - -.Code style - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-code-style.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Code style`. There click on the icon next to the `Scheme` section. There, click on the `Import Scheme` value and pick the `Intellij IDEA code style XML` option. Import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml` file. - -.Inspection profiles - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-inspections.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Inspections`. There click on the icon next to the `Profile` section. There, click on the `Import Profile` and import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml` file. - -.Checkstyle - -To have Intellij work with Checkstyle, you have to install the `Checkstyle` plugin. It's advisable to also install the `Assertions2Assertj` to automatically convert the JUnit assertions - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-checkstyle.png[Checkstyle] - -Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on the `+` icon in the `Configuration file` section. There, you'll have to define where the checkstyle rules should be picked from. In the image above, we've picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build's GitHub repository (e.g. for the `checkstyle.xml` : `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml`). We need to provide the following variables: - -- `checkstyle.header.file` - please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` URL. -- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL. -- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`. - -IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. - -=== Duplicate Finder - -Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath. - -==== Duplicate Finder configuration - -Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst's `pom.xml`. - -.pom.xml -[source,xml] ----- - - - - org.basepom.maven - duplicate-finder-maven-plugin - - - ----- - -For other properties, we have set defaults as listed in the https://github.com/basepom/duplicate-finder-maven-plugin/wiki[plugin documentation]. - -You can easily override them but setting the value of the selected property prefixed with `duplicate-finder-maven-plugin`. For example, set `duplicate-finder-maven-plugin.skip` to `true` in order to skip duplicates check in your build. - -If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your setup, make sure to add them in the plugin configuration section of your project: - -[source,xml] ----- - - - - org.basepom.maven - duplicate-finder-maven-plugin - - - org.joda.time.base.BaseDateTime - .*module-info - - - changelog.txt - - - - - - - ----- - - -== 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. diff --git a/docs/antora-playbook.yml b/antora-playbook.yml similarity index 60% rename from docs/antora-playbook.yml rename to antora-playbook.yml index 9a70e676ca..140356ac09 100644 --- a/docs/antora-playbook.yml +++ b/antora-playbook.yml @@ -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 diff --git a/config/releaser.yml b/config/releaser.yml deleted file mode 100644 index 46d7a7751b..0000000000 --- a/config/releaser.yml +++ /dev/null @@ -1,2 +0,0 @@ -releaser.maven.build-command: ./scripts/integration-tests.sh -releaser.maven.deploy-command: ./scripts/deploy.sh {{systemProps}} diff --git a/docs/.flattened-pom.xml b/docs/.flattened-pom.xml new file mode 100644 index 0000000000..3c3a9470e5 --- /dev/null +++ b/docs/.flattened-pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-docs + 3.0.4-SNAPSHOT + Spring Cloud Kubernetes Docs + Spring Cloud Kubernetes Docs + https://cloud.spring.io/spring-cloud-kubernetes-docs + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-docs + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-docs + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-docs + + + + org.springframework.cloud + spring-cloud-starter-kubernetes-fabric8 + 3.0.4-SNAPSHOT + compile + + + org.springframework.cloud + spring-cloud-starter-kubernetes-fabric8-all + 3.0.4-SNAPSHOT + compile + + + org.springframework.cloud + spring-cloud-starter-kubernetes-fabric8-config + 3.0.4-SNAPSHOT + compile + + + diff --git a/docs/.github/workflows/deploy-docs.yml b/docs/.github/workflows/deploy-docs.yml deleted file mode 100644 index be4b92dfc0..0000000000 --- a/docs/.github/workflows/deploy-docs.yml +++ /dev/null @@ -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) diff --git a/docs/antora.yml b/docs/antora.yml deleted file mode 100644 index 15b346da04..0000000000 --- a/docs/antora.yml +++ /dev/null @@ -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/ diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc deleted file mode 100644 index 26a0c3fedb..0000000000 --- a/docs/modules/ROOT/nav.adoc +++ /dev/null @@ -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[] diff --git a/docs/modules/ROOT/pages/README.adoc b/docs/modules/ROOT/pages/README.adoc deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/modules/ROOT/pages/_attributes.adoc b/docs/modules/ROOT/pages/_attributes.adoc deleted file mode 100644 index bed0a077d8..0000000000 --- a/docs/modules/ROOT/pages/_attributes.adoc +++ /dev/null @@ -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} diff --git a/docs/modules/ROOT/pages/_configprops.adoc b/docs/modules/ROOT/pages/_configprops.adoc deleted file mode 100644 index 01a5d8cdef..0000000000 --- a/docs/modules/ROOT/pages/_configprops.adoc +++ /dev/null @@ -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+++` | - -|=== diff --git a/docs/modules/ROOT/pages/appendix.adoc b/docs/modules/ROOT/pages/appendix.adoc deleted file mode 100644 index eef1c9056b..0000000000 --- a/docs/modules/ROOT/pages/appendix.adoc +++ /dev/null @@ -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. - diff --git a/docs/modules/ROOT/pages/discovery-client.adoc b/docs/modules/ROOT/pages/discovery-client.adoc deleted file mode 100644 index f44d74a400..0000000000 --- a/docs/modules/ROOT/pages/discovery-client.adoc +++ /dev/null @@ -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] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-discoveryclient - ----- -==== - -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] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8 - ----- -==== - -==== -Kubernetes Java Client -[source,xml] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client - ----- -==== - -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"] -``` diff --git a/docs/modules/ROOT/pages/discovery-kubernetes-native.adoc b/docs/modules/ROOT/pages/discovery-kubernetes-native.adoc deleted file mode 100644 index a4b716456a..0000000000 --- a/docs/modules/ROOT/pages/discovery-kubernetes-native.adoc +++ /dev/null @@ -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=` diff --git a/docs/modules/ROOT/pages/examples.adoc b/docs/modules/ROOT/pages/examples.adoc deleted file mode 100644 index ca0b11ec72..0000000000 --- a/docs/modules/ROOT/pages/examples.adoc +++ /dev/null @@ -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] diff --git a/docs/modules/ROOT/pages/getting-started.adoc b/docs/modules/ROOT/pages/getting-started.adoc deleted file mode 100644 index 1abaad2242..0000000000 --- a/docs/modules/ROOT/pages/getting-started.adoc +++ /dev/null @@ -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 ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8 - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client - ----- -| <> implementation that -resolves service names to Kubernetes Services. - -| [source,xml] -.Fabric8 Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-config - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-config - ----- -| Load application properties from Kubernetes -xref:property-source-config/configmap-propertysource.adoc[ConfigMaps] and <>. -xref:property-source-config/propertysource-reload.adoc[Reload] application properties when a ConfigMap or -Secret changes. - -| [source,xml] -.Fabric8 Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-all - ----- - -[source,xml] -.Kubernetes Client Dependency ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-all - ----- -| All Spring Cloud Kubernetes features. -|=== diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/modules/ROOT/pages/info-contributor.adoc b/docs/modules/ROOT/pages/info-contributor.adoc deleted file mode 100644 index 54f62e2349..0000000000 --- a/docs/modules/ROOT/pages/info-contributor.adoc +++ /dev/null @@ -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]`. diff --git a/docs/modules/ROOT/pages/kubernetes-awareness.adoc b/docs/modules/ROOT/pages/kubernetes-awareness.adoc deleted file mode 100644 index 6e939d82d7..0000000000 --- a/docs/modules/ROOT/pages/kubernetes-awareness.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/leader-election.adoc b/docs/modules/ROOT/pages/leader-election.adoc deleted file mode 100644 index bfe8483639..0000000000 --- a/docs/modules/ROOT/pages/leader-election.adoc +++ /dev/null @@ -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] ----- - - org.springframework.cloud - spring-cloud-kubernetes-fabric8-leader - ----- -==== - -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 ----- -==== diff --git a/docs/modules/ROOT/pages/load-balancer.adoc b/docs/modules/ROOT/pages/load-balancer.adoc deleted file mode 100644 index 432b019f1c..0000000000 --- a/docs/modules/ROOT/pages/load-balancer.adoc +++ /dev/null @@ -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] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-fabric8-loadbalancer - ----- -==== - -==== -Kubernetes Java Client Implementation -[source,xml] ----- - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-loadbalancer - ----- -==== - -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. diff --git a/docs/modules/ROOT/pages/other-resources.adoc b/docs/modules/ROOT/pages/other-resources.adoc deleted file mode 100644 index e81bcc02e7..0000000000 --- a/docs/modules/ROOT/pages/other-resources.adoc +++ /dev/null @@ -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]. diff --git a/docs/modules/ROOT/pages/pod-health-indicator.adoc b/docs/modules/ROOT/pages/pod-health-indicator.adoc deleted file mode 100644 index 80b812842d..0000000000 --- a/docs/modules/ROOT/pages/pod-health-indicator.adoc +++ /dev/null @@ -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]`. diff --git a/docs/modules/ROOT/pages/property-source-config.adoc b/docs/modules/ROOT/pages/property-source-config.adoc deleted file mode 100644 index 29f1fc6547..0000000000 --- a/docs/modules/ROOT/pages/property-source-config.adoc +++ /dev/null @@ -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. - diff --git a/docs/modules/ROOT/pages/property-source-config/configmap-propertysource.adoc b/docs/modules/ROOT/pages/property-source-config/configmap-propertysource.adoc deleted file mode 100644 index 791cffc018..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/configmap-propertysource.adoc +++ /dev/null @@ -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. -|=== - diff --git a/docs/modules/ROOT/pages/property-source-config/namespace-label-filtering.adoc b/docs/modules/ROOT/pages/property-source-config/namespace-label-filtering.adoc deleted file mode 100644 index 6593db55d9..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/namespace-label-filtering.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/property-source-config/namespace-resolution.adoc b/docs/modules/ROOT/pages/property-source-config/namespace-resolution.adoc deleted file mode 100644 index e335c3c499..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/namespace-resolution.adoc +++ /dev/null @@ -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. - diff --git a/docs/modules/ROOT/pages/property-source-config/order_of_configMaps_and_secrets.adoc b/docs/modules/ROOT/pages/property-source-config/order_of_configMaps_and_secrets.adoc deleted file mode 100644 index 6ce8b392f9..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/order_of_configMaps_and_secrets.adoc +++ /dev/null @@ -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. - diff --git a/docs/modules/ROOT/pages/property-source-config/propertysource-reload.adoc b/docs/modules/ROOT/pages/property-source-config/propertysource-reload.adoc deleted file mode 100644 index 6e4fc85a59..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/propertysource-reload.adoc +++ /dev/null @@ -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. - diff --git a/docs/modules/ROOT/pages/property-source-config/secrets-propertysource.adoc b/docs/modules/ROOT/pages/property-source-config/secrets-propertysource.adoc deleted file mode 100644 index 3c8606da0a..0000000000 --- a/docs/modules/ROOT/pages/property-source-config/secrets-propertysource.adoc +++ /dev/null @@ -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] - diff --git a/docs/modules/ROOT/pages/sagan-boot.adoc b/docs/modules/ROOT/pages/sagan-boot.adoc deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/modules/ROOT/pages/sagan-index.adoc b/docs/modules/ROOT/pages/sagan-index.adoc deleted file mode 100644 index a7f394a780..0000000000 --- a/docs/modules/ROOT/pages/sagan-index.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/security-service-accounts.adoc b/docs/modules/ROOT/pages/security-service-accounts.adoc deleted file mode 100644 index 89b58cee95..0000000000 --- a/docs/modules/ROOT/pages/security-service-accounts.adoc +++ /dev/null @@ -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: "" ----- -==== diff --git a/docs/modules/ROOT/pages/service-registry.adoc b/docs/modules/ROOT/pages/service-registry.adoc deleted file mode 100644 index a6102d3e25..0000000000 --- a/docs/modules/ROOT/pages/service-registry.adoc +++ /dev/null @@ -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. diff --git a/docs/modules/ROOT/pages/spring-cloud-kubernetes-configserver.adoc b/docs/modules/ROOT/pages/spring-cloud-kubernetes-configserver.adoc deleted file mode 100644 index 23cb8c12df..0000000000 --- a/docs/modules/ROOT/pages/spring-cloud-kubernetes-configserver.adoc +++ /dev/null @@ -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 - ----- -==== diff --git a/docs/modules/ROOT/pages/spring-cloud-kubernetes-configuration-watcher.adoc b/docs/modules/ROOT/pages/spring-cloud-kubernetes-configuration-watcher.adoc deleted file mode 100644 index 7acb43a50b..0000000000 --- a/docs/modules/ROOT/pages/spring-cloud-kubernetes-configuration-watcher.adoc +++ /dev/null @@ -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 ----- -==== diff --git a/docs/modules/ROOT/pages/spring-cloud-kubernetes-discoveryserver.adoc b/docs/modules/ROOT/pages/spring-cloud-kubernetes-discoveryserver.adoc deleted file mode 100644 index ebe0e2b99b..0000000000 --- a/docs/modules/ROOT/pages/spring-cloud-kubernetes-discoveryserver.adoc +++ /dev/null @@ -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 - - ----- -==== diff --git a/docs/modules/ROOT/pages/spring-cloud-kubernetes.adoc b/docs/modules/ROOT/pages/spring-cloud-kubernetes.adoc deleted file mode 100644 index ff77459f3f..0000000000 --- a/docs/modules/ROOT/pages/spring-cloud-kubernetes.adoc +++ /dev/null @@ -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. diff --git a/docs/pom.xml b/docs/pom.xml deleted file mode 100644 index 1da38f1d8a..0000000000 --- a/docs/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - 4.0.0 - org.springframework.cloud - spring-cloud-kubernetes-docs - - org.springframework.cloud - spring-cloud-kubernetes - 3.1.0-SNAPSHOT - - jar - Spring Cloud Kubernetes Docs - Spring Cloud Kubernetes Docs - - spring-cloud-kubernetes - ${basedir}/.. - spring.cloud.kubernetes.* - deploy - - none - - - - ${project.groupId} - spring-cloud-starter-kubernetes-fabric8 - - - ${project.groupId} - spring-cloud-starter-kubernetes-fabric8-all - - - ${project.groupId} - spring-cloud-starter-kubernetes-fabric8-config - - - - src/main/asciidoc - - - - docs - - - - pl.project13.maven - git-commit-id-plugin - - - org.codehaus.mojo - exec-maven-plugin - - - org.apache.maven.plugins - maven-dependency-plugin - - - org.apache.maven.plugins - maven-resources-plugin - - - org.asciidoctor - asciidoctor-maven-plugin - - - org.apache.maven.plugins - maven-antrun-plugin - false - - - maven-deploy-plugin - - - - - - diff --git a/header.txt b/header.txt deleted file mode 100644 index 014e8a4cc6..0000000000 --- a/header.txt +++ /dev/null @@ -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. diff --git a/mvnw b/mvnw index 8b9da3b8b6..41c0f0c23d 100755 --- a/mvnw +++ b/mvnw @@ -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" \ diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index a5284c7939..86115719e5 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -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% diff --git a/pom.xml b/pom.xml index e17b33d4ec..f8c240c195 100644 --- a/pom.xml +++ b/pom.xml @@ -1,366 +1,70 @@ - - + + - - 4.0.0 - - org.springframework.cloud - spring-cloud-build - 4.1.0-SNAPSHOT - - - - spring-cloud-kubernetes - 3.1.0-SNAPSHOT - pom - Spring Cloud Kubernetes - - https://cloud.spring.io - 2017 - - - Pivotal Software, Inc. - https://www.spring.io - - - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0.txt - repo - - + org.springframework.cloud + spring-cloud-kubernetes-docs-build + 0.0.1-SNAPSHOT + Spring Cloud Kubernetes Docs Build + Builds Spring Cloud Kubernetes Docs. + https://spring.io/projects/spring-cloud-kubernetes - https://github.com/spring-cloud/spring-cloud-kubernetes - - scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git + scm:git:https://github.com/spring-cloud/spring-cloud-kubernetes.git - scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git + scm:git:git@github.com:spring-cloud/spring-cloud-kubernetes.git - HEAD + https://github.com/spring-cloud/spring-cloud-kubernetes + + https://github.com/spring-cloud/spring-cloud-kubernetes/issues + - - 4.8.1 - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - - 3.1.0 - - true - true - - true - + 0.0.3 - - spring-cloud-kubernetes-dependencies - spring-cloud-kubernetes-commons - spring-cloud-kubernetes-test-support - spring-cloud-kubernetes-client-autoconfig - spring-cloud-kubernetes-client-config - spring-cloud-kubernetes-client-loadbalancer - spring-cloud-kubernetes-fabric8-autoconfig - spring-cloud-kubernetes-fabric8-config - spring-cloud-kubernetes-fabric8-discovery - spring-cloud-kubernetes-client-discovery - spring-cloud-starter-kubernetes-fabric8 - spring-cloud-starter-kubernetes-fabric8-config - spring-cloud-starter-kubernetes-fabric8-all - spring-cloud-starter-kubernetes-client - spring-cloud-starter-kubernetes-client-config - spring-cloud-starter-kubernetes-client-loadbalancer - spring-cloud-starter-kubernetes-client-all - spring-cloud-kubernetes-examples - spring-cloud-kubernetes-fabric8-leader - spring-cloud-kubernetes-fabric8-istio - spring-cloud-kubernetes-controllers - spring-cloud-kubernetes-integration-tests - docs - spring-cloud-kubernetes-fabric8-loadbalancer - spring-cloud-starter-kubernetes-fabric8-loadbalancer - spring-cloud-kubernetes-discovery - spring-cloud-starter-kubernetes-discoveryclient - - - - - - - org.springframework.cloud - spring-cloud-kubernetes-dependencies - ${project.version} - pom - import - - - - org.springframework.cloud - spring-cloud-commons-dependencies - ${spring-cloud-commons.version} - pom - import - - - - org.springframework.cloud - spring-cloud-config-dependencies - ${spring-cloud-config.version} - pom - import - - - - org.springframework.cloud - spring-cloud-bus-dependencies - ${spring-cloud-bus.version} - pom - import - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - - org.mockito - mockito-bom - ${mockito-inline.version} - pom - import - - - - org.codehaus.groovy - groovy-all - ${groovy.version} - - - - org.springframework.cloud - spring-cloud-test-support - ${spring-cloud-commons.version} - test - - - - org.codehaus.mojo - flatten-maven-plugin - - - org.apache.maven.plugins - maven-compiler-plugin - true - - 17 - 17 - - - - - org.apache.maven.plugins - maven-surefire-plugin - true + io.spring.maven.antora + antora-maven-plugin + ${io.spring.maven.antora-version} + true - all - false - - ${testsToRun} - + + + + + + + 9d489079e5ec46dbb238909fee5c9c29 + WB1FQYI187 + springcloudkubernetes + - - org.apache.maven.plugins - maven-checkstyle-plugin - - - io.spring.javaformat - spring-javaformat-maven-plugin - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - + + + spring-snapshot + https://repo.spring.io/snapshot + + true + + + false + + + + spring-milestone + https://repo.spring.io/milestone + + - - - spring - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - release - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 1.3.1 - - - enforce-no-snapshots - - enforce - - - - - No Snapshots Allowed! - - - false - - - - - - - - - sonar - - - - org.jacoco - jacoco-maven-plugin - - - pre-unit-test - - prepare-agent - - - surefireArgLine - ${project.build.directory}/jacoco.exec - - - - - post-unit-test - test - - report - - - - ${project.build.directory}/jacoco.exec - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - all - false - - - - - - diff --git a/runSonar.sh b/runSonar.sh deleted file mode 100755 index b150b5213b..0000000000 --- a/runSonar.sh +++ /dev/null @@ -1 +0,0 @@ -./mvnw -s .settings.xml clean install -Dservice.occurence=${_SERVICE_OCCURENCE} #org.jacoco:jacoco-maven-plugin:prepare-agent install -U -P sonar diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100755 index c7d1b14e1e..0000000000 --- a/scripts/deploy.sh +++ /dev/null @@ -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 ${@} diff --git a/scripts/integration-tests.sh b/scripts/integration-tests.sh deleted file mode 100755 index 4d5fa33886..0000000000 --- a/scripts/integration-tests.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -e - -./mvnw clean install -B -Pdocs ${@} - diff --git a/spring-cloud-kubernetes-client-autoconfig/.flattened-pom.xml b/spring-cloud-kubernetes-client-autoconfig/.flattened-pom.xml new file mode 100644 index 0000000000..6687a902a0 --- /dev/null +++ b/spring-cloud-kubernetes-client-autoconfig/.flattened-pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-client-autoconfig + 3.0.4-SNAPSHOT + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io/spring-cloud-kubernetes-client-autoconfig + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-autoconfig + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-autoconfig + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-client-autoconfig + + + + org.springframework.cloud + spring-cloud-kubernetes-commons + 3.0.4-SNAPSHOT + compile + + + io.kubernetes + client-java + 17.0.2 + compile + + + io.kubernetes + client-java-extended + 17.0.2 + compile + + + org.springframework.boot + spring-boot-actuator-autoconfigure + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-autoconfigure + 3.0.7 + compile + + + diff --git a/spring-cloud-kubernetes-client-autoconfig/pom.xml b/spring-cloud-kubernetes-client-autoconfig/pom.xml deleted file mode 100644 index ed1dc54104..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - spring-cloud-kubernetes - org.springframework.cloud - 3.1.0-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-client-autoconfig - - - - org.springframework.cloud - spring-cloud-kubernetes-commons - - - io.kubernetes - client-java - - - io.kubernetes - client-java-extended - - - org.springframework.boot - spring-boot-actuator-autoconfigure - true - - - org.springframework.boot - spring-boot-autoconfigure - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.springframework.boot - spring-boot-starter-webflux - test - - - org.mockito - mockito-inline - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientActuatorConfiguration.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientActuatorConfiguration.java deleted file mode 100644 index eae0776446..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientActuatorConfiguration.java +++ /dev/null @@ -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 podUtils) { - return new KubernetesClientHealthIndicator(podUtils); - } - - @Bean - @ConditionalOnEnabledInfoContributor("kubernetes") - public KubernetesClientInfoContributor kubernetesInfoContributor(PodUtils podUtils) { - return new KubernetesClientInfoContributor(podUtils); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientAutoConfiguration.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientAutoConfiguration.java deleted file mode 100644 index 26c5c3a4d5..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientAutoConfiguration.java +++ /dev/null @@ -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()); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicator.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicator.java deleted file mode 100644 index 7a2490b18a..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicator.java +++ /dev/null @@ -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 utils; - - public KubernetesClientHealthIndicator(PodUtils utils) { - this.utils = utils; - } - - @Override - protected Map getDetails() { - V1Pod current = this.utils.currentPod().get(); - if (current != null) { - Map 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); - } - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributor.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributor.java deleted file mode 100644 index 4d9d5e687f..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributor.java +++ /dev/null @@ -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 utils; - - public KubernetesClientInfoContributor(PodUtils utils) { - this.utils = utils; - } - - @Override - public Map getDetails() { - V1Pod current = this.utils.currentPod().get(); - if (current != null) { - Map 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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtils.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtils.java deleted file mode 100644 index f50394db19..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtils.java +++ /dev/null @@ -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 { - - /** - * 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 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 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(); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java deleted file mode 100644 index b931e07dd6..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java +++ /dev/null @@ -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: - * - *
-	 *     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)
-	 * 
- * - * 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"); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessor.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessor.java deleted file mode 100644 index 767d082355..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessor.java +++ /dev/null @@ -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(); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 3768e9e32f..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=\ -org.springframework.cloud.kubernetes.client.profile.KubernetesClientProfileEnvironmentPostProcessor diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 42d61d84df..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration -org.springframework.cloud.kubernetes.client.KubernetesClientActuatorConfiguration diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorDisabledHealthTest.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorDisabledHealthTest.java deleted file mode 100644 index a6675c2970..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorDisabledHealthTest.java +++ /dev/null @@ -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'"); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorEnabledHealthTest.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorEnabledHealthTest.java deleted file mode 100644 index df2a41e04d..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/ActuatorEnabledHealthTest.java +++ /dev/null @@ -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'"); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorInsideTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorInsideTests.java deleted file mode 100644 index 910e385735..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorInsideTests.java +++ /dev/null @@ -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(); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorNotInsideTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorNotInsideTests.java deleted file mode 100644 index ac29de59b3..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorNotInsideTests.java +++ /dev/null @@ -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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorTests.java deleted file mode 100644 index b3e47d253a..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientHealthIndicatorTests.java +++ /dev/null @@ -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 utils; - - @Test - void getDetailsNotInsideTest() { - when(utils.currentPod()).thenReturn(() -> null); - KubernetesClientHealthIndicator healthIndicator = new KubernetesClientHealthIndicator(utils); - Map 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 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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorInsideTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorInsideTests.java deleted file mode 100644 index 5cb9437fbf..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorInsideTests.java +++ /dev/null @@ -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(); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorNotInsideTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorNotInsideTests.java deleted file mode 100644 index ec6fac6b25..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorNotInsideTests.java +++ /dev/null @@ -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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorTests.java deleted file mode 100644 index ce40a543fb..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientInfoContributorTests.java +++ /dev/null @@ -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 utils; - - @Test - void getDetailsIsNotInside() { - when(utils.currentPod()).thenReturn(() -> null); - KubernetesClientInfoContributor infoContributor = new KubernetesClientInfoContributor(utils); - Map 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 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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtilsTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtilsTests.java deleted file mode 100644 index a81bbefb5a..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientPodUtilsTests.java +++ /dev/null @@ -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; - - private MockedStatic 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 sup = util.currentPod(); - assertSupplierAndClient(sup, util); - } - - @Test - public void hostNameNotPresent() { - mockHost(HOST); - mockHostname(null); - - KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace"); - Supplier sup = util.currentPod(); - assertSupplierAndClient(sup, util); - } - - @Test - public void serviceAccountPathNotPresent() { - mockTokenPath(false); - mockHostname(HOST); - - KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace"); - Supplier sup = util.currentPod(); - assertSupplierAndClient(sup, util); - } - - @Test - public void serviceAccountCertPathNotPresent() { - mockTokenPath(true); - mockCertPath(false); - mockHostname(HOST); - - KubernetesClientPodUtils util = new KubernetesClientPodUtils(client, "namespace"); - Supplier 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 sup = util.currentPod(); - assertThat(sup.get()).isNotNull(); - assertThat(util.isInsideKubernetes()).isTrue(); - } - - private void assertSupplierAndClient(Supplier 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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtilsTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtilsTests.java deleted file mode 100644 index 8f11da75da..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtilsTests.java +++ /dev/null @@ -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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/StubProvider.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/StubProvider.java deleted file mode 100644 index 10b810a009..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/StubProvider.java +++ /dev/null @@ -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 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); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentDefaultHeader.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentDefaultHeader.java deleted file mode 100644 index 46ac865e9a..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentDefaultHeader.java +++ /dev/null @@ -1,59 +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.default_api; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; - -import io.kubernetes.client.openapi.ApiClient; -import okhttp3.Request; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Robert McNees - * - * This tests that the apiClient created in KubernetesClientAutoConfiguration will not set - * itself as the default apiClient. This is to avoid overwriting the user's - * defaultApiClient if they include this project. - * - * kubernetes informer is disabled because KubernetesClientInformerAutoConfiguration - * creates a defaultApiClient that will be autowired instead of the ApiClient created in - * KubernetesClientAutoConfiguration - */ -@SpringBootTest(classes = App.class, - properties = { "kubernetes.informer.enabled=false", "spring.main.cloud-platform=KUBERNETES" }) -class ApiClientUserAgentDefaultHeader { - - @Autowired - private ApiClient apiClient; - - @Test - void testApiClientUserAgentDefaultHeader() throws MalformedURLException { - assertThat(apiClient).isNotNull(); - Request.Builder builder = new Request.Builder(); - apiClient.processHeaderParams(Collections.emptyMap(), builder); - assertThat(builder.url(new URL("http://example.com")).build().headers().get("User-Agent")) - .isEqualTo("Spring-Cloud-Kubernetes-Application"); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentNonDefaultHeader.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentNonDefaultHeader.java deleted file mode 100644 index 7c08fb6b73..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/ApiClientUserAgentNonDefaultHeader.java +++ /dev/null @@ -1,63 +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.default_api; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; - -import io.kubernetes.client.openapi.ApiClient; -import okhttp3.Request; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Robert McNees - * - * This tests that the apiClient created in KubernetesClientAutoConfiguration will not set - * itself as the default apiClient. This is to avoid overwriting the user's - * defaultApiClient if they include this project. - * - * kubernetes informer is disabled because KubernetesClientInformerAutoConfiguration - * creates a defaultApiClient that will be autowired instead of the ApiClient created in - * KubernetesClientAutoConfiguration - */ -@SpringBootTest(classes = App.class, properties = { "kubernetes.informer.enabled=false", - "spring.cloud.kubernetes.client.userAgent=non-default", "spring.main.cloud-platform=KUBERNETES" }) -class ApiClientUserAgentNonDefaultHeader { - - @Autowired - private ApiClient apiClient; - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void testApiClientUserAgentDefaultHeader() throws MalformedURLException { - assertThat(apiClient).isNotNull(); - Request.Builder builder = new Request.Builder(); - apiClient.processHeaderParams(Collections.emptyMap(), builder); - assertThat(builder.url(new URL("http://example.com")).build().headers().get("User-Agent")) - .isEqualTo("non-default"); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/App.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/App.java deleted file mode 100644 index 20263cbb2d..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/App.java +++ /dev/null @@ -1,24 +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.default_api; - -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -class App { - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/DefaultApiClientNotSameAsApiClient.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/DefaultApiClientNotSameAsApiClient.java deleted file mode 100644 index b5afab4995..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/default_api/DefaultApiClientNotSameAsApiClient.java +++ /dev/null @@ -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.default_api; - -import io.kubernetes.client.openapi.ApiClient; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Robert McNees - * - * This tests that the apiClient created in KubernetesClientAutoConfiguration will not set - * itself as the default apiClient. This is to avoid overwriting the user's - * defaultApiClient if they include this project. - * - * kubernetes informer is disabled because KubernetesClientInformerAutoConfiguration - * creates a defaultApiClient that will be autowired instead of the ApiClient created in - * KubernetesClientAutoConfiguration - */ -@SpringBootTest(classes = App.class, - properties = { "kubernetes.informer.enabled=false", "spring.main.cloud-platform=KUBERNETES" }) -class DefaultApiClientNotSameAsApiClient { - - @Autowired - private ApiClient apiClient; - - @Test - void testCreatedApiClientIsNotDefault() { - assertThat(apiClient).isNotNull(); - - ApiClient defaultApiClient = io.kubernetes.client.openapi.Configuration.getDefaultApiClient(); - assertThat(defaultApiClient).isNotNull(); - - assertThat(defaultApiClient).isNotSameAs(apiClient); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/example/App.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/example/App.java deleted file mode 100644 index fbcdb3f51d..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/example/App.java +++ /dev/null @@ -1,41 +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.example; - -import io.kubernetes.client.openapi.ApiClient; -import okhttp3.OkHttpClient; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author wind57 - */ -@SpringBootApplication -public class App { - - @Bean - public ApiClient apiClient() { - ApiClient apiClient = mock(ApiClient.class); - when(apiClient.getHttpClient()).thenReturn(new OkHttpClient.Builder().build()); - return apiClient; - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorNoProfileTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorNoProfileTests.java deleted file mode 100644 index 21e1fce21a..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorNoProfileTests.java +++ /dev/null @@ -1,43 +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 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.core.env.Environment; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.kubernetes.commons.profile.AbstractKubernetesProfileEnvironmentPostProcessor.KUBERNETES_PROFILE; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(classes = { App.class }) -class KubernetesClientProfileEnvironmentPostProcessorNoProfileTests { - - @Autowired - private Environment environment; - - @Test - void whenNoKubernetesEnvironmentAndNoApiAccessThenNoProfileEnabled() { - assertThat(environment.getActiveProfiles()).doesNotContain(KUBERNETES_PROFILE); - } - -} diff --git a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorTests.java b/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorTests.java deleted file mode 100644 index fcff0ef771..0000000000 --- a/spring-cloud-kubernetes-client-autoconfig/src/test/java/org/springframework/cloud/kubernetes/client/profile/KubernetesClientProfileEnvironmentPostProcessorTests.java +++ /dev/null @@ -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.profile; - -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.core.env.Environment; - -import static io.kubernetes.client.util.Config.ENV_SERVICE_HOST; -import static io.kubernetes.client.util.Config.ENV_SERVICE_PORT; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.kubernetes.commons.profile.AbstractKubernetesProfileEnvironmentPostProcessor.KUBERNETES_PROFILE; - -/** - * @author Thomas Vitale - */ -@SpringBootTest(properties = { ENV_SERVICE_HOST + "=10.0.0.1", ENV_SERVICE_PORT + "=80", - "spring.main.cloud-platform=KUBERNETES" }, classes = { App.class }) -class KubernetesClientProfileEnvironmentPostProcessorTests { - - @Autowired - private Environment environment; - - @Test - void whenKubernetesEnvironmentAndNoApiAccessThenProfileEnabled() { - assertThat(environment.getActiveProfiles()).contains(KUBERNETES_PROFILE); - } - -} diff --git a/spring-cloud-kubernetes-client-config/.flattened-pom.xml b/spring-cloud-kubernetes-client-config/.flattened-pom.xml new file mode 100644 index 0000000000..f5658eebd7 --- /dev/null +++ b/spring-cloud-kubernetes-client-config/.flattened-pom.xml @@ -0,0 +1,151 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-client-config + 3.0.4-SNAPSHOT + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io/spring-cloud-kubernetes-client-config + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-config + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-config + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-client-config + + + + org.springframework.cloud + spring-cloud-kubernetes-client-autoconfig + 3.0.4-SNAPSHOT + compile + + + org.springframework.cloud + spring-cloud-kubernetes-commons + 3.0.4-SNAPSHOT + compile + + + io.kubernetes + client-java + 17.0.2 + compile + + + io.kubernetes + client-java-extended + 17.0.2 + compile + + + org.springframework.boot + spring-boot-starter-logging + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-actuator + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-actuator-autoconfigure + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-autoconfigure + 3.0.7 + compile + + + org.springframework.cloud + spring-cloud-starter + 4.0.4-SNAPSHOT + compile + + + org.springframework.retry + spring-retry + 2.0.1 + compile + true + + + diff --git a/spring-cloud-kubernetes-client-config/pom.xml b/spring-cloud-kubernetes-client-config/pom.xml deleted file mode 100644 index 80a8d7dbed..0000000000 --- a/spring-cloud-kubernetes-client-config/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - spring-cloud-kubernetes - org.springframework.cloud - 3.1.0-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-client-config - - - - org.springframework.cloud - spring-cloud-kubernetes-client-autoconfig - - - org.springframework.cloud - spring-cloud-kubernetes-commons - - - io.kubernetes - client-java - - - io.kubernetes - client-java-extended - - - org.springframework.boot - spring-boot-starter-logging - true - - - org.springframework.boot - spring-boot-actuator - true - - - org.springframework.boot - spring-boot-actuator-autoconfigure - true - - - org.springframework.boot - spring-boot-autoconfigure - - - - org.springframework.cloud - spring-cloud-starter - - - - org.springframework.retry - spring-retry - true - - - org.springframework.boot - spring-boot-starter-aop - true - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - org.springframework.boot - spring-boot-starter-web - test - - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - - org.springframework.boot - spring-boot-starter-web - test - - - - org.springframework.boot - spring-boot-starter-webflux - test - - - org.springframework.boot - spring-boot-starter-aop - test - - - org.mockito - mockito-inline - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - - diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientBootstrapConfiguration.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientBootstrapConfiguration.java deleted file mode 100644 index 91ae4eb408..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientBootstrapConfiguration.java +++ /dev/null @@ -1,64 +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.config; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesConfigEnabled; -import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesSecretsEnabled; -import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesConfigRetryDisabled; -import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesSecretsRetryDisabled; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @author Ryan Baxter - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter(KubernetesBootstrapConfiguration.class) -@Import({ KubernetesCommonsAutoConfiguration.class, KubernetesClientAutoConfiguration.class }) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -public class KubernetesClientBootstrapConfiguration { - - @Bean - @ConditionalOnKubernetesConfigEnabled - @ConditionalOnKubernetesConfigRetryDisabled - public KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator( - ConfigMapConfigProperties properties, CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - return new KubernetesClientConfigMapPropertySourceLocator(coreV1Api, properties, kubernetesNamespaceProvider); - } - - @Bean - @ConditionalOnKubernetesSecretsEnabled - @ConditionalOnKubernetesSecretsRetryDisabled - public KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator(SecretsConfigProperties properties, - CoreV1Api coreV1Api, KubernetesNamespaceProvider kubernetesNamespaceProvider) { - return new KubernetesClientSecretsPropertySourceLocator(coreV1Api, kubernetesNamespaceProvider, properties); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigContext.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigContext.java deleted file mode 100644 index 91a5556a1e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigContext.java +++ /dev/null @@ -1,31 +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.config; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.core.env.Environment; - -/** - * A context/holder for various data needed to compute property sources. - * - * @author wind57 - */ -public record KubernetesClientConfigContext(CoreV1Api client, NormalizedSource normalizedSource, String namespace, - Environment environment) { -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java deleted file mode 100644 index 19d7f14ff9..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java +++ /dev/null @@ -1,103 +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.config; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.boot.BootstrapRegistry; -import org.springframework.boot.ConfigurableBootstrapContext; -import org.springframework.boot.context.config.ConfigDataLocation; -import org.springframework.boot.context.config.ConfigDataLocationResolverContext; -import org.springframework.boot.context.config.Profiles; -import org.springframework.boot.logging.DeferredLogFactory; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; -import org.springframework.core.env.Environment; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient; -import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientConfigDataLocationResolver extends KubernetesConfigDataLocationResolver { - - public KubernetesClientConfigDataLocationResolver(DeferredLogFactory factory) { - super(factory); - } - - @Override - protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, KubernetesConfigDataLocationResolver.PropertyHolder propertyHolder, - KubernetesNamespaceProvider namespaceProvider) { - KubernetesClientProperties kubernetesClientProperties = propertyHolder.kubernetesClientProperties(); - ConfigMapConfigProperties configMapProperties = propertyHolder.configMapConfigProperties(); - SecretsConfigProperties secretsProperties = propertyHolder.secretsProperties(); - - ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); - CoreV1Api coreV1Api = registerClientAndCoreV1Api(bootstrapContext, kubernetesClientProperties); - - if (configMapProperties != null && configMapProperties.enabled()) { - ConfigMapPropertySourceLocator configMapPropertySourceLocator = new KubernetesClientConfigMapPropertySourceLocator( - coreV1Api, configMapProperties, namespaceProvider); - if (isRetryEnabledForConfigMap(configMapProperties)) { - configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator( - configMapPropertySourceLocator, configMapProperties, new KubernetesClientConfigMapsCache()); - } - - registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator, - "configDataConfigMapPropertySourceLocator"); - } - - if (secretsProperties != null && secretsProperties.enabled()) { - SecretsPropertySourceLocator secretsPropertySourceLocator = new KubernetesClientSecretsPropertySourceLocator( - coreV1Api, namespaceProvider, secretsProperties); - if (isRetryEnabledForSecrets(secretsProperties)) { - secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator( - secretsPropertySourceLocator, secretsProperties, new KubernetesClientSecretsCache()); - } - - registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator, - "configDataSecretsPropertySourceLocator"); - } - } - - private CoreV1Api registerClientAndCoreV1Api(ConfigurableBootstrapContext bootstrapContext, - KubernetesClientProperties kubernetesClientProperties) { - ApiClient apiClient = kubernetesApiClient(); - apiClient.setUserAgent(kubernetesClientProperties.userAgent()); - registerSingle(bootstrapContext, ApiClient.class, apiClient, "configDataApiClient"); - - CoreV1Api coreV1Api = new CoreV1Api(apiClient); - bootstrapContext.registerIfAbsent(CoreV1Api.class, BootstrapRegistry.InstanceSupplier.of(coreV1Api)); - - return coreV1Api; - } - - protected KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) { - return new KubernetesNamespaceProvider(environment); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySource.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySource.java deleted file mode 100644 index d66f16d582..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySource.java +++ /dev/null @@ -1,58 +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.config; - -import java.util.EnumMap; -import java.util.Optional; - -import org.springframework.cloud.kubernetes.commons.config.NormalizedSourceType; -import org.springframework.cloud.kubernetes.commons.config.SourceData; -import org.springframework.cloud.kubernetes.commons.config.SourceDataEntriesProcessor; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -public class KubernetesClientConfigMapPropertySource extends SourceDataEntriesProcessor { - - private static final EnumMap STRATEGIES = new EnumMap<>( - NormalizedSourceType.class); - - static { - STRATEGIES.put(NormalizedSourceType.NAMED_CONFIG_MAP, namedConfigMap()); - STRATEGIES.put(NormalizedSourceType.LABELED_CONFIG_MAP, labeledConfigMap()); - } - - public KubernetesClientConfigMapPropertySource(KubernetesClientConfigContext context) { - super(getSourceData(context)); - } - - private static SourceData getSourceData(KubernetesClientConfigContext context) { - NormalizedSourceType type = context.normalizedSource().type(); - return Optional.ofNullable(STRATEGIES.get(type)).map(x -> x.apply(context)) - .orElseThrow(() -> new IllegalArgumentException("no strategy found for : " + type)); - } - - private static KubernetesClientContextToSourceData namedConfigMap() { - return new NamedConfigMapContextToSourceDataProvider().get(); - } - - private static KubernetesClientContextToSourceData labeledConfigMap() { - return new LabeledConfigMapContextToSourceDataProvider().get(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocator.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocator.java deleted file mode 100644 index 56a17e6a7e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocator.java +++ /dev/null @@ -1,60 +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.config; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -@Order(0) -public class KubernetesClientConfigMapPropertySourceLocator extends ConfigMapPropertySourceLocator { - - private final CoreV1Api coreV1Api; - - private final KubernetesNamespaceProvider kubernetesNamespaceProvider; - - public KubernetesClientConfigMapPropertySourceLocator(CoreV1Api coreV1Api, ConfigMapConfigProperties properties, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - super(properties, new KubernetesClientConfigMapsCache()); - this.coreV1Api = coreV1Api; - this.kubernetesNamespaceProvider = kubernetesNamespaceProvider; - } - - @Override - protected MapPropertySource getMapPropertySource(NormalizedSource source, ConfigurableEnvironment environment) { - - String normalizedNamespace = source.namespace().orElse(null); - String namespace = getApplicationNamespace(normalizedNamespace, source.target(), kubernetesNamespaceProvider); - - KubernetesClientConfigContext context = new KubernetesClientConfigContext(coreV1Api, source, namespace, - environment); - return new KubernetesClientConfigMapPropertySource(context); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapsCache.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapsCache.java deleted file mode 100644 index 1b6a6c5bfb..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapsCache.java +++ /dev/null @@ -1,82 +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.config; - -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.commons.config.ConfigMapCache; -import org.springframework.cloud.kubernetes.commons.config.StrippedSourceContainer; -import org.springframework.core.log.LogAccessor; - -/** - * A cache of V1ConfigMap(s) per namespace. Makes sure we read config maps only once from - * a namespace. - * - * @author wind57 - */ -final class KubernetesClientConfigMapsCache implements ConfigMapCache { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesClientConfigMapsCache.class)); - - /** - * at the moment our loading of config maps is using a single thread, but might change - * in the future, thus a thread safe structure. - */ - private static final ConcurrentHashMap> CACHE = new ConcurrentHashMap<>(); - - @Override - public void discardAll() { - CACHE.clear(); - } - - static List byNamespace(CoreV1Api coreV1Api, String namespace) { - boolean[] b = new boolean[1]; - List result = CACHE.computeIfAbsent(namespace, x -> { - try { - b[0] = true; - return strippedConfigMaps(coreV1Api - .listNamespacedConfigMap(namespace, null, null, null, null, null, null, null, null, null, null) - .getItems()); - } - catch (ApiException apiException) { - throw new RuntimeException(apiException.getResponseBody(), apiException); - } - }); - - if (b[0]) { - LOG.debug(() -> "Loaded all config maps in namespace '" + namespace + "'"); - } - else { - LOG.debug(() -> "Loaded (from cache) all config maps in namespace '" + namespace + "'"); - } - - return result; - } - - private static List strippedConfigMaps(List configMaps) { - return configMaps.stream().map(configMap -> new StrippedSourceContainer(configMap.getMetadata().getLabels(), - configMap.getMetadata().getName(), configMap.getData())).collect(Collectors.toList()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtils.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtils.java deleted file mode 100644 index cfbeb100ca..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtils.java +++ /dev/null @@ -1,153 +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.config; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.kubernetes.client.openapi.apis.CoreV1Api; -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.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; -import org.springframework.cloud.kubernetes.commons.config.StrippedSourceContainer; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.core.env.Environment; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace; - -/** - * @author Ryan Baxter - */ -public final class KubernetesClientConfigUtils { - - private static final Log LOG = LogFactory.getLog(KubernetesClientConfigUtils.class); - - // k8s-native client already returns data from secrets as being decoded - // this flags makes sure we use it everywhere - private static final boolean DECODE = Boolean.FALSE; - - private KubernetesClientConfigUtils() { - } - - /** - * finds namespaces to be used for the event based reloading. - */ - public static Set namespaces(KubernetesNamespaceProvider provider, ConfigReloadProperties properties, - String target) { - Set namespaces = properties.namespaces(); - if (namespaces.isEmpty()) { - namespaces = Set.of(getApplicationNamespace(null, target, provider)); - } - LOG.debug("informer namespaces : " + namespaces); - return namespaces; - } - - /** - *
-	 *     1. read all secrets in the provided namespace
-	 *     2. from the above, filter the ones that we care about (filter by labels)
-	 *     3. with secret names from (2), find out if there are any profile based secrets (if profiles is not empty)
-	 *     4. concat (2) and (3) and these are the secrets we are interested in
-	 *     5. see if any of the secrets from (4) has a single yaml/properties file
-	 *     6. gather all the names of the secrets (from 4) + data they hold
-	 * 
- */ - static MultipleSourcesContainer secretsDataByLabels(CoreV1Api coreV1Api, String namespace, - Map labels, Environment environment, Set profiles) { - List strippedSecrets = strippedSecrets(coreV1Api, namespace); - if (strippedSecrets.isEmpty()) { - return MultipleSourcesContainer.empty(); - } - return ConfigUtils.processLabeledData(strippedSecrets, environment, labels, namespace, profiles, DECODE); - } - - /** - *
-	 *     1. read all config maps in the provided namespace
-	 *     2. from the above, filter the ones that we care about (filter by labels)
-	 *     3. with config maps names from (2), find out if there are any profile based ones (if profiles is not empty)
-	 *     4. concat (2) and (3) and these are the config maps we are interested in
-	 *     5. see if any from (4) has a single yaml/properties file
-	 *     6. gather all the names of the config maps (from 4) + data they hold
-	 * 
- */ - static MultipleSourcesContainer configMapsDataByLabels(CoreV1Api coreV1Api, String namespace, - Map labels, Environment environment, Set profiles) { - List strippedConfigMaps = strippedConfigMaps(coreV1Api, namespace); - if (strippedConfigMaps.isEmpty()) { - return MultipleSourcesContainer.empty(); - } - return ConfigUtils.processLabeledData(strippedConfigMaps, environment, labels, namespace, profiles, DECODE); - } - - /** - *
-	 *     1. read all secrets in the provided namespace
-	 *     2. from the above, filter the ones that we care about (by name)
-	 *     3. see if any of the secrets has a single yaml/properties file
-	 *     4. gather all the names of the secrets + decoded data they hold
-	 * 
- */ - static MultipleSourcesContainer secretsDataByName(CoreV1Api coreV1Api, String namespace, - LinkedHashSet sourceNames, Environment environment) { - List strippedSecrets = strippedSecrets(coreV1Api, namespace); - if (strippedSecrets.isEmpty()) { - return MultipleSourcesContainer.empty(); - } - return ConfigUtils.processNamedData(strippedSecrets, environment, sourceNames, namespace, DECODE); - } - - /** - *
-	 *     1. read all config maps in the provided namespace
-	 *     2. from the above, filter the ones that we care about (by name)
-	 *     3. see if any of the config maps has a single yaml/properties file
-	 *     4. gather all the names of the config maps + data they hold
-	 * 
- */ - static MultipleSourcesContainer configMapsDataByName(CoreV1Api coreV1Api, String namespace, - LinkedHashSet sourceNames, Environment environment) { - List strippedConfigMaps = strippedConfigMaps(coreV1Api, namespace); - if (strippedConfigMaps.isEmpty()) { - return MultipleSourcesContainer.empty(); - } - return ConfigUtils.processNamedData(strippedConfigMaps, environment, sourceNames, namespace, DECODE); - } - - private static List strippedConfigMaps(CoreV1Api coreV1Api, String namespace) { - List strippedConfigMaps = KubernetesClientConfigMapsCache.byNamespace(coreV1Api, - namespace); - if (strippedConfigMaps.isEmpty()) { - LOG.debug("No configmaps in namespace '" + namespace + "'"); - } - return strippedConfigMaps; - } - - private static List strippedSecrets(CoreV1Api coreV1Api, String namespace) { - List strippedSecrets = KubernetesClientSecretsCache.byNamespace(coreV1Api, namespace); - if (strippedSecrets.isEmpty()) { - LOG.debug("No configmaps in namespace '" + namespace + "'"); - } - return strippedSecrets; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientContextToSourceData.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientContextToSourceData.java deleted file mode 100644 index 070a8b841c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientContextToSourceData.java +++ /dev/null @@ -1,31 +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.config; - -import java.util.function.Function; - -import org.springframework.cloud.kubernetes.commons.config.SourceData; - -/** - * A more succinct way to define a Function from KubernetesClientConfigContext to - * SourceData. - * - * @author wind57 - */ -interface KubernetesClientContextToSourceData extends Function { - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientRetryBootstrapConfiguration.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientRetryBootstrapConfiguration.java deleted file mode 100644 index 5b5cd79abc..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientRetryBootstrapConfiguration.java +++ /dev/null @@ -1,67 +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.config; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesConfigOrSecretsRetryEnabled; -import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesConfigRetryEnabled; -import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesSecretsRetryEnabled; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @author Ryan Baxter - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter(KubernetesBootstrapConfiguration.class) -@AutoConfigureBefore(KubernetesClientBootstrapConfiguration.class) -@Import({ KubernetesCommonsAutoConfiguration.class, KubernetesClientAutoConfiguration.class }) -@ConditionalOnKubernetesConfigOrSecretsRetryEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -public class KubernetesClientRetryBootstrapConfiguration { - - @Bean - @ConditionalOnKubernetesConfigRetryEnabled - public KubernetesClientConfigMapPropertySourceLocator retryableConfigMapPropertySourceLocator( - ConfigMapConfigProperties properties, CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - return new RetryableKubernetesClientConfigMapPropertySourceLocator(coreV1Api, properties, - kubernetesNamespaceProvider); - } - - @Bean - @ConditionalOnKubernetesSecretsRetryEnabled - public KubernetesClientSecretsPropertySourceLocator retryableSecretsPropertySourceLocator( - SecretsConfigProperties properties, CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - return new RetryableKubernetesClientSecretsPropertySourceLocator(coreV1Api, kubernetesNamespaceProvider, - properties); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsCache.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsCache.java deleted file mode 100644 index 8381d9a410..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsCache.java +++ /dev/null @@ -1,89 +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.config; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1Secret; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.commons.config.SecretsCache; -import org.springframework.cloud.kubernetes.commons.config.StrippedSourceContainer; -import org.springframework.core.log.LogAccessor; -import org.springframework.util.ObjectUtils; - -/** - * A cache of V1ConfigMap(s) per namespace. Makes sure we read config maps only once from - * a namespace. - * - * @author wind57 - */ -public class KubernetesClientSecretsCache implements SecretsCache { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesClientConfigMapsCache.class)); - - /** - * at the moment our loading of config maps is using a single thread, but might change - * in the future, thus a thread safe structure. - */ - private static final ConcurrentHashMap> CACHE = new ConcurrentHashMap<>(); - - @Override - public void discardAll() { - CACHE.clear(); - } - - static List byNamespace(CoreV1Api coreV1Api, String namespace) { - boolean[] b = new boolean[1]; - List result = CACHE.computeIfAbsent(namespace, x -> { - try { - b[0] = true; - return strippedSecrets(coreV1Api - .listNamespacedSecret(namespace, null, null, null, null, null, null, null, null, null, null) - .getItems()); - } - catch (ApiException apiException) { - throw new RuntimeException(apiException.getResponseBody(), apiException); - } - }); - - if (b[0]) { - LOG.debug(() -> "Loaded all secrets in namespace '" + namespace + "'"); - } - else { - LOG.debug(() -> "Loaded (from cache) all secrets in namespace '" + namespace + "'"); - } - - return result; - } - - private static List strippedSecrets(List secrets) { - return secrets.stream().map(secret -> new StrippedSourceContainer(secret.getMetadata().getLabels(), - secret.getMetadata().getName(), transform(secret.getData()))).collect(Collectors.toList()); - } - - private static Map transform(Map in) { - return ObjectUtils.isEmpty(in) ? Map.of() - : in.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, en -> new String(en.getValue()))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySource.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySource.java deleted file mode 100644 index 642386f604..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySource.java +++ /dev/null @@ -1,62 +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.config; - -import java.util.EnumMap; -import java.util.Optional; - -import org.springframework.cloud.kubernetes.commons.config.NormalizedSourceType; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource; -import org.springframework.cloud.kubernetes.commons.config.SourceData; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -public class KubernetesClientSecretsPropertySource extends SecretsPropertySource { - - public KubernetesClientSecretsPropertySource(SourceData sourceData) { - super(sourceData); - } - - private static final EnumMap STRATEGIES = new EnumMap<>( - NormalizedSourceType.class); - - static { - STRATEGIES.put(NormalizedSourceType.NAMED_SECRET, namedSecret()); - STRATEGIES.put(NormalizedSourceType.LABELED_SECRET, labeledSecret()); - } - - public KubernetesClientSecretsPropertySource(KubernetesClientConfigContext context) { - super(getSourceData(context)); - } - - private static SourceData getSourceData(KubernetesClientConfigContext context) { - NormalizedSourceType type = context.normalizedSource().type(); - return Optional.ofNullable(STRATEGIES.get(type)).map(x -> x.apply(context)) - .orElseThrow(() -> new IllegalArgumentException("no strategy found for : " + type)); - } - - private static KubernetesClientContextToSourceData namedSecret() { - return new NamedSecretContextToSourceDataProvider().get(); - } - - private static KubernetesClientContextToSourceData labeledSecret() { - return new LabeledSecretContextToSourceDataProvider().get(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocator.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocator.java deleted file mode 100644 index 057a43d90f..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocator.java +++ /dev/null @@ -1,61 +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.config; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.ConfigurableEnvironment; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -@Order(1) -public class KubernetesClientSecretsPropertySourceLocator extends SecretsPropertySourceLocator { - - private final CoreV1Api coreV1Api; - - private final KubernetesNamespaceProvider kubernetesNamespaceProvider; - - public KubernetesClientSecretsPropertySourceLocator(CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider, SecretsConfigProperties secretsConfigProperties) { - super(secretsConfigProperties, new KubernetesClientSecretsCache()); - this.coreV1Api = coreV1Api; - this.kubernetesNamespaceProvider = kubernetesNamespaceProvider; - } - - @Override - protected SecretsPropertySource getPropertySource(ConfigurableEnvironment environment, NormalizedSource source) { - - String normalizedNamespace = source.namespace().orElse(null); - String namespace = getApplicationNamespace(normalizedNamespace, source.target(), kubernetesNamespaceProvider); - - KubernetesClientConfigContext context = new KubernetesClientConfigContext(coreV1Api, source, namespace, - environment); - - return new KubernetesClientSecretsPropertySource(context); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProvider.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProvider.java deleted file mode 100644 index 6d4381ffd2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProvider.java +++ /dev/null @@ -1,63 +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.config; - -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -import org.springframework.cloud.kubernetes.commons.config.LabeledConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.LabeledSourceData; -import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; - -class LabeledConfigMapContextToSourceDataProvider implements Supplier { - - LabeledConfigMapContextToSourceDataProvider() { - } - - /* - * Computes a ContextSourceData (think content) for configmap(s) based on some labels. - * There could be many sources that are read based on incoming labels, for which we - * will be computing a single Map in the end. - * - * If there is no config maps found for the provided labels, we will return an "empty" - * SourceData. Its name is going to be the concatenated labels mapped to an empty Map. - * - * If we find config maps(s) for the provided labels, its name is going to be the - * concatenated names mapped to the data they hold as a Map. - */ - @Override - public KubernetesClientContextToSourceData get() { - - return context -> { - - LabeledConfigMapNormalizedSource source = (LabeledConfigMapNormalizedSource) context.normalizedSource(); - - return new LabeledSourceData() { - @Override - public MultipleSourcesContainer dataSupplier(Map labels, Set profiles) { - return KubernetesClientConfigUtils.configMapsDataByLabels(context.client(), context.namespace(), - labels, context.environment(), profiles); - } - - }.compute(source.labels(), source.prefix(), source.target(), source.profileSpecificSources(), - source.failFast(), context.namespace(), context.environment().getActiveProfiles()); - }; - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProvider.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProvider.java deleted file mode 100644 index 9cf72cbc0b..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProvider.java +++ /dev/null @@ -1,68 +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.config; - -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.LabeledSourceData; -import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; - -/** - * Provides an implementation of {@link KubernetesClientContextToSourceData} for a labeled - * secret. - * - * @author wind57 - */ -final class LabeledSecretContextToSourceDataProvider implements Supplier { - - LabeledSecretContextToSourceDataProvider() { - - } - - /* - * Computes a ContextSourceData (think content) for secret(s) based on some labels. - * There could be many secrets that are read based on incoming labels, for which we - * will be computing a single Map in the end. - * - * If there is no secret found for the provided labels, we will return an "empty" - * SourceData. Its name is going to be the concatenated labels mapped to an empty Map. - * - * If we find secret(s) for the provided labels, its name is going to be the - * concatenated secret names mapped to the data they hold as a Map. - */ - @Override - public KubernetesClientContextToSourceData get() { - return context -> { - - LabeledSecretNormalizedSource source = (LabeledSecretNormalizedSource) context.normalizedSource(); - - return new LabeledSourceData() { - @Override - public MultipleSourcesContainer dataSupplier(Map labels, Set profiles) { - return KubernetesClientConfigUtils.secretsDataByLabels(context.client(), context.namespace(), - labels, context.environment(), profiles); - } - - }.compute(source.labels(), source.prefix(), source.target(), source.profileSpecificSources(), - source.failFast(), context.namespace(), context.environment().getActiveProfiles()); - }; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProvider.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProvider.java deleted file mode 100644 index c19ee3fbc9..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProvider.java +++ /dev/null @@ -1,56 +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.config; - -import java.util.LinkedHashSet; -import java.util.function.Supplier; - -import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; -import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NamedSourceData; - -/** - * Provides an implementation of {@link KubernetesClientContextToSourceData} for a named - * config map. - * - * @author wind57 - */ -final class NamedConfigMapContextToSourceDataProvider implements Supplier { - - NamedConfigMapContextToSourceDataProvider() { - } - - @Override - public KubernetesClientContextToSourceData get() { - - return context -> { - - NamedConfigMapNormalizedSource source = (NamedConfigMapNormalizedSource) context.normalizedSource(); - - return new NamedSourceData() { - @Override - public MultipleSourcesContainer dataSupplier(LinkedHashSet sourceNames) { - return KubernetesClientConfigUtils.configMapsDataByName(context.client(), context.namespace(), - sourceNames, context.environment()); - } - }.compute(source.name().orElseThrow(), source.prefix(), source.target(), source.profileSpecificSources(), - source.failFast(), context.namespace(), context.environment().getActiveProfiles()); - }; - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProvider.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProvider.java deleted file mode 100644 index 82eee3710f..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProvider.java +++ /dev/null @@ -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.config; - -import java.util.LinkedHashSet; -import java.util.function.Supplier; - -import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; -import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NamedSourceData; - -/** - * Provides an implementation of {@link KubernetesClientContextToSourceData} for a named - * secret. - * - * @author wind57 - */ -final class NamedSecretContextToSourceDataProvider implements Supplier { - - NamedSecretContextToSourceDataProvider() { - } - - @Override - public KubernetesClientContextToSourceData get() { - return context -> { - - NamedSecretNormalizedSource source = (NamedSecretNormalizedSource) context.normalizedSource(); - - return new NamedSourceData() { - @Override - public MultipleSourcesContainer dataSupplier(LinkedHashSet sourceNames) { - return KubernetesClientConfigUtils.secretsDataByName(context.client(), context.namespace(), - sourceNames, context.environment()); - } - }.compute(source.name().orElseThrow(), source.prefix(), source.target(), source.profileSpecificSources(), - source.failFast(), context.namespace(), context.environment().getActiveProfiles()); - }; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientConfigMapPropertySourceLocator.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientConfigMapPropertySourceLocator.java deleted file mode 100644 index 7e8bfbc19d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientConfigMapPropertySourceLocator.java +++ /dev/null @@ -1,55 +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.config; - -import java.util.Collection; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; -import org.springframework.retry.annotation.Retryable; - -/** - * ConfigMapPropertySourceLocator for when retry is enabled. - * - * @author Ryan Baxter - */ -@Order(0) -class RetryableKubernetesClientConfigMapPropertySourceLocator extends KubernetesClientConfigMapPropertySourceLocator { - - RetryableKubernetesClientConfigMapPropertySourceLocator(CoreV1Api coreV1Api, ConfigMapConfigProperties properties, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - super(coreV1Api, properties, kubernetesNamespaceProvider); - } - - @Override - @Retryable(interceptor = "kubernetesConfigRetryInterceptor") - public PropertySource locate(Environment environment) { - return super.locate(environment); - } - - @Override - @Retryable(interceptor = "kubernetesConfigRetryInterceptor") - public Collection> locateCollection(Environment environment) { - return super.locateCollection(environment); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientSecretsPropertySourceLocator.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientSecretsPropertySourceLocator.java deleted file mode 100644 index 3f01b8ccec..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/RetryableKubernetesClientSecretsPropertySourceLocator.java +++ /dev/null @@ -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.config; - -import java.util.Collection; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; -import org.springframework.retry.annotation.Retryable; - -/** - * SecretsPropertySourceLocator for when retry is enabled. - * - * @author Ryan Baxter - */ -@Order(1) -class RetryableKubernetesClientSecretsPropertySourceLocator extends KubernetesClientSecretsPropertySourceLocator { - - RetryableKubernetesClientSecretsPropertySourceLocator(CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider, SecretsConfigProperties secretsConfigProperties) { - super(coreV1Api, kubernetesNamespaceProvider, secretsConfigProperties); - } - - @Override - @Retryable(interceptor = "kubernetesSecretsRetryInterceptor") - public PropertySource locate(Environment environment) { - return super.locate(environment); - } - - @Override - @Retryable(interceptor = "kubernetesSecretsRetryInterceptor") - public Collection> locateCollection(Environment environment) { - return super.locateCollection(environment); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfiguration.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfiguration.java deleted file mode 100644 index 3abf084385..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfiguration.java +++ /dev/null @@ -1,152 +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.config.reload; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration; -import org.springframework.cloud.commons.util.TaskSchedulerWrapper; -import org.springframework.cloud.context.refresh.ContextRefresher; -import org.springframework.cloud.context.restart.RestartEndpoint; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; -import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.PollingSecretsChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.condition.ConditionalOnConfigMapsReloadEnabled; -import org.springframework.cloud.kubernetes.commons.config.reload.condition.ConditionalOnKubernetesReloadEnabled; -import org.springframework.cloud.kubernetes.commons.config.reload.condition.ConditionalOnSecretsReloadEnabled; -import org.springframework.cloud.kubernetes.commons.config.reload.condition.EventReloadDetectionMode; -import org.springframework.cloud.kubernetes.commons.config.reload.condition.PollingReloadDetectionMode; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.env.AbstractEnvironment; -import org.springframework.scheduling.TaskScheduler; - -/** - * @author Ryan Baxter - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@ConditionalOnKubernetesReloadEnabled -@ConditionalOnClass({ EndpointAutoConfiguration.class, RestartEndpoint.class, ContextRefresher.class }) -@AutoConfigureAfter({ InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class, - RefreshAutoConfiguration.class, ConfigReloadPropertiesAutoConfiguration.class }) -@Import(ConfigReloadAutoConfiguration.class) -public class KubernetesClientConfigReloadAutoConfiguration { - - /** - * Polling configMap ConfigurationChangeDetector. - * @param properties config reload properties - * @param strategy configuration update strategy - * @param configMapPropertySourceLocator configMap property source locator - * @return a bean that listen to configuration changes and fire a reload. - */ - @Bean - @ConditionalOnConfigMapsReloadEnabled - @ConditionalOnBean(KubernetesClientConfigMapPropertySourceLocator.class) - @Conditional(PollingReloadDetectionMode.class) - public ConfigurationChangeDetector configMapPropertyChangePollingWatcher(ConfigReloadProperties properties, - ConfigurationUpdateStrategy strategy, - KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator, - AbstractEnvironment environment, TaskSchedulerWrapper taskScheduler) { - - return new PollingConfigMapChangeDetector(environment, properties, strategy, - KubernetesClientConfigMapPropertySource.class, configMapPropertySourceLocator, - taskScheduler.getTaskScheduler()); - } - - /** - * Polling secrets ConfigurationChangeDetector. - * @param properties config reload properties - * @param strategy configuration update strategy - * @param secretsPropertySourceLocator secrets property source locator - * @return a bean that listen to configuration changes and fire a reload. - */ - @Bean - @ConditionalOnSecretsReloadEnabled - @ConditionalOnBean(KubernetesClientSecretsPropertySourceLocator.class) - @Conditional(PollingReloadDetectionMode.class) - public ConfigurationChangeDetector secretsPropertyChangePollingWatcher(ConfigReloadProperties properties, - ConfigurationUpdateStrategy strategy, - KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator, AbstractEnvironment environment, - TaskSchedulerWrapper taskScheduler) { - - return new PollingSecretsChangeDetector(environment, properties, strategy, - KubernetesClientSecretsPropertySource.class, secretsPropertySourceLocator, - taskScheduler.getTaskScheduler()); - } - - /** - * Event Based configMap ConfigurationChangeDetector. - * @param properties config reload properties - * @param strategy configuration update strategy - * @param configMapPropertySourceLocator configMap property source locator - * @return a bean that listen to configMap change events and fire a reload. - */ - @Bean - @ConditionalOnConfigMapsReloadEnabled - @ConditionalOnBean(KubernetesClientConfigMapPropertySourceLocator.class) - @Conditional(EventReloadDetectionMode.class) - public ConfigurationChangeDetector configMapPropertyChangeEventWatcher(ConfigReloadProperties properties, - ConfigurationUpdateStrategy strategy, - KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator, - AbstractEnvironment environment, CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - - return new KubernetesClientEventBasedConfigMapChangeDetector(coreV1Api, environment, properties, strategy, - configMapPropertySourceLocator, kubernetesNamespaceProvider); - } - - /** - * Event Based secrets ConfigurationChangeDetector. - * @param properties config reload properties - * @param strategy configuration update strategy - * @param secretsPropertySourceLocator secrets property source locator - * @return a bean that listen to secrets change events and fire a reload. - */ - @Bean - @ConditionalOnSecretsReloadEnabled - @ConditionalOnBean(KubernetesClientSecretsPropertySourceLocator.class) - @Conditional(EventReloadDetectionMode.class) - public ConfigurationChangeDetector secretsPropertyChangeEventWatcher(ConfigReloadProperties properties, - ConfigurationUpdateStrategy strategy, - KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator, AbstractEnvironment environment, - CoreV1Api coreV1Api, KubernetesNamespaceProvider kubernetesNamespaceProvider) { - - return new KubernetesClientEventBasedSecretsChangeDetector(coreV1Api, environment, properties, strategy, - secretsPropertySourceLocator, kubernetesNamespaceProvider); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java deleted file mode 100644 index f5f36591ea..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java +++ /dev/null @@ -1,156 +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.config.reload; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import io.kubernetes.client.common.KubernetesObject; -import io.kubernetes.client.informer.ResourceEventHandler; -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.util.CallGeneratorParams; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.log.LogAccessor; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient; -import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.namespaces; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientEventBasedConfigMapChangeDetector extends ConfigurationChangeDetector { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesClientEventBasedConfigMapChangeDetector.class)); - - private final CoreV1Api coreV1Api; - - private final KubernetesClientConfigMapPropertySourceLocator propertySourceLocator; - - private final ApiClient apiClient; - - private final List> informers = new ArrayList<>(); - - private final List factories = new ArrayList<>(); - - private final Set namespaces; - - private final boolean enableReloadFiltering; - - private final ResourceEventHandler handler = new ResourceEventHandler<>() { - - @Override - public void onAdd(V1ConfigMap configMap) { - LOG.debug(() -> "ConfigMap " + configMap.getMetadata().getName() + " was added in namespace " - + configMap.getMetadata().getNamespace()); - onEvent(configMap); - } - - @Override - public void onUpdate(V1ConfigMap oldConfigMap, V1ConfigMap newConfigMap) { - LOG.debug(() -> "ConfigMap " + newConfigMap.getMetadata().getName() + " was updated in namespace " - + newConfigMap.getMetadata().getNamespace()); - if (Objects.equals(oldConfigMap.getData(), newConfigMap.getData())) { - LOG.debug(() -> "data in configmap has not changed, will not reload"); - } - else { - onEvent(newConfigMap); - } - } - - @Override - public void onDelete(V1ConfigMap configMap, boolean deletedFinalStateUnknown) { - LOG.debug(() -> "ConfigMap " + configMap.getMetadata().getName() + " was deleted in namespace " - + configMap.getMetadata().getNamespace()); - onEvent(configMap); - } - }; - - public KubernetesClientEventBasedConfigMapChangeDetector(CoreV1Api coreV1Api, ConfigurableEnvironment environment, - ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy, - KubernetesClientConfigMapPropertySourceLocator propertySourceLocator, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - super(environment, properties, strategy); - this.propertySourceLocator = propertySourceLocator; - this.coreV1Api = coreV1Api; - this.apiClient = createApiClientForInformerClient(); - this.enableReloadFiltering = properties.enableReloadFiltering(); - namespaces = namespaces(kubernetesNamespaceProvider, properties, "configmap"); - } - - @PostConstruct - void inform() { - LOG.info(() -> "Kubernetes event-based configMap change detector activated"); - - namespaces.forEach(namespace -> { - SharedIndexInformer informer; - String[] filter = new String[1]; - - if (enableReloadFiltering) { - filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true"; - } - SharedInformerFactory factory = new SharedInformerFactory(apiClient); - factories.add(factory); - informer = factory.sharedIndexInformerFor( - (CallGeneratorParams params) -> coreV1Api.listNamespacedConfigMapCall(namespace, null, null, null, - null, filter[0], null, params.resourceVersion, null, params.timeoutSeconds, params.watch, - null), - V1ConfigMap.class, V1ConfigMapList.class); - - LOG.debug(() -> "added configmap informer for namespace : " + namespace + " with filter : " + filter[0]); - - informer.addEventHandler(handler); - informers.add(informer); - factory.startAllRegisteredInformers(); - }); - - } - - @PreDestroy - void shutdown() { - informers.forEach(SharedIndexInformer::stop); - factories.forEach(SharedInformerFactory::stopAllRegisteredInformers); - } - - protected void onEvent(KubernetesObject configMap) { - boolean reload = ConfigReloadUtil.reload("config-map", configMap.toString(), propertySourceLocator, environment, - KubernetesClientConfigMapPropertySource.class); - if (reload) { - reloadProperties(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java deleted file mode 100644 index 2beb30dbdc..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java +++ /dev/null @@ -1,176 +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.config.reload; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.kubernetes.client.common.KubernetesObject; -import io.kubernetes.client.informer.ResourceEventHandler; -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.CallGeneratorParams; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.log.LogAccessor; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient; -import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.namespaces; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientEventBasedSecretsChangeDetector extends ConfigurationChangeDetector { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesClientEventBasedSecretsChangeDetector.class)); - - private final CoreV1Api coreV1Api; - - private final KubernetesClientSecretsPropertySourceLocator propertySourceLocator; - - private final ApiClient apiClient; - - private final List> informers = new ArrayList<>(); - - private final List factories = new ArrayList<>(); - - private final Set namespaces; - - private final boolean enableReloadFiltering; - - private final ResourceEventHandler handler = new ResourceEventHandler<>() { - - @Override - public void onAdd(V1Secret secret) { - LOG.debug(() -> "Secret " + secret.getMetadata().getName() + " was added in namespace " - + secret.getMetadata().getNamespace()); - onEvent(secret); - } - - @Override - public void onUpdate(V1Secret oldSecret, V1Secret newSecret) { - LOG.debug(() -> "Secret " + newSecret.getMetadata().getName() + " was updated in namespace " - + newSecret.getMetadata().getNamespace()); - - if (KubernetesClientEventBasedSecretsChangeDetector.equals(oldSecret.getData(), newSecret.getData())) { - LOG.debug(() -> "data in secret has not changed, will not reload"); - } - else { - onEvent(newSecret); - } - } - - @Override - public void onDelete(V1Secret secret, boolean deletedFinalStateUnknown) { - LOG.debug(() -> "Secret " + secret.getMetadata().getName() + " was deleted in namespace " - + secret.getMetadata().getNamespace()); - onEvent(secret); - } - }; - - public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, ConfigurableEnvironment environment, - ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy, - KubernetesClientSecretsPropertySourceLocator propertySourceLocator, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - super(environment, properties, strategy); - this.propertySourceLocator = propertySourceLocator; - this.coreV1Api = coreV1Api; - this.apiClient = createApiClientForInformerClient(); - this.enableReloadFiltering = properties.enableReloadFiltering(); - namespaces = namespaces(kubernetesNamespaceProvider, properties, "secret"); - } - - @PostConstruct - void inform() { - LOG.info(() -> "Kubernetes event-based secrets change detector activated"); - - namespaces.forEach(namespace -> { - SharedIndexInformer informer; - String[] filter = new String[1]; - - if (enableReloadFiltering) { - filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true"; - } - SharedInformerFactory factory = new SharedInformerFactory(apiClient); - factories.add(factory); - informer = factory.sharedIndexInformerFor( - (CallGeneratorParams params) -> coreV1Api.listNamespacedSecretCall(namespace, null, null, null, - null, filter[0], null, params.resourceVersion, null, params.timeoutSeconds, params.watch, - null), - V1Secret.class, V1SecretList.class); - - LOG.debug(() -> "added secret informer for namespace : " + namespace + " with filter : " + filter[0]); - - informer.addEventHandler(handler); - informers.add(informer); - factory.startAllRegisteredInformers(); - }); - - } - - @PreDestroy - void shutdown() { - informers.forEach(SharedIndexInformer::stop); - factories.forEach(SharedInformerFactory::stopAllRegisteredInformers); - } - - protected void onEvent(KubernetesObject secret) { - boolean reload = ConfigReloadUtil.reload("secrets", secret.toString(), propertySourceLocator, environment, - KubernetesClientSecretsPropertySource.class); - if (reload) { - reloadProperties(); - } - } - - static boolean equals(Map left, Map right) { - Map innerLeft = Optional.ofNullable(left).orElse(Map.of()); - Map innerRight = Optional.ofNullable(right).orElse(Map.of()); - - if (innerLeft.size() != innerRight.size()) { - return false; - } - - for (Map.Entry entry : innerLeft.entrySet()) { - String key = entry.getKey(); - byte[] value = entry.getValue(); - if (!Arrays.equals(value, innerRight.get(key))) { - return false; - } - } - return true; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 4006bda9a6..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,6 +0,0 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.kubernetes.client.config.KubernetesClientBootstrapConfiguration,\ -org.springframework.cloud.kubernetes.client.config.KubernetesClientRetryBootstrapConfiguration -# ConfigData Location Resolvers -org.springframework.boot.context.config.ConfigDataLocationResolver=\ -org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigDataLocationResolver diff --git a/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 6a9e6f8ee2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientConfigReloadAutoConfiguration diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/Application.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/Application.java deleted file mode 100644 index 39e6ce9a5e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/Application.java +++ /dev/null @@ -1,24 +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.config; - -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/EnableRetryBootstrapConfiguration.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/EnableRetryBootstrapConfiguration.java deleted file mode 100644 index c9a5cc5fc2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/EnableRetryBootstrapConfiguration.java +++ /dev/null @@ -1,33 +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.config; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; -import org.springframework.retry.annotation.EnableRetry; - -/** - * @author Ryan Baxter - */ -@Order(0) -@Configuration -@ConditionalOnProperty("spring.cloud.kubernetes.test.enable-retry") -@EnableRetry -public class EnableRetryBootstrapConfiguration { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java deleted file mode 100644 index 3e234007d1..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java +++ /dev/null @@ -1,227 +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.config; - -import java.util.function.Supplier; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.boot.DefaultBootstrapContext; -import org.springframework.boot.context.config.ConfigDataLocation; -import org.springframework.boot.context.config.ConfigDataLocationResolverContext; -import org.springframework.boot.context.config.Profiles; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.logging.DeferredLogFactory; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; -import org.springframework.mock.env.MockEnvironment; - -/** - * @author wind57 - */ -class KubernetesClientConfigDataLocationResolverTests { - - private static final DeferredLogFactory FACTORY = Supplier::get; - - private static final ConfigDataLocationResolverContext RESOLVER_CONTEXT = Mockito - .mock(ConfigDataLocationResolverContext.class); - - private static final KubernetesClientConfigDataLocationResolver RESOLVER = new KubernetesClientConfigDataLocationResolver( - FACTORY); - - /* - * both ConfigMapConfigProperties and SecretsConfigProperties are null, thus they are - * not registered. It also means that ConfigMapPropertySourceLocator and - * SecretsPropertySourceLocator are not registered either. - */ - @Test - void testBothMissing() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.config.enabled", "false"); - environment.setProperty("spring.cloud.kubernetes.secrets.enabled", "false"); - ConfigurationPropertySources.attach(environment); - Binder binder = new Binder(ConfigurationPropertySources.get(environment)); - - DefaultBootstrapContext context = new DefaultBootstrapContext(); - Mockito.when(RESOLVER_CONTEXT.getBinder()).thenReturn(binder); - Mockito.when(RESOLVER_CONTEXT.getBootstrapContext()).thenReturn(context); - - Profiles profiles = Mockito.mock(Profiles.class); - ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); - - Assertions.assertTrue(context.isRegistered(KubernetesClientProperties.class)); - Assertions.assertTrue(context.isRegistered(CoreV1Api.class)); - Assertions.assertTrue(context.isRegistered(ApiClient.class)); - - Assertions.assertFalse(context.isRegistered(ConfigMapConfigProperties.class)); - Assertions.assertFalse(context.isRegistered(SecretsConfigProperties.class)); - - Assertions.assertFalse(context.isRegistered(ConfigMapPropertySourceLocator.class)); - Assertions.assertFalse(context.isRegistered(SecretsPropertySourceLocator.class)); - } - - /* - * both ConfigMapConfigProperties and SecretsConfigProperties are enabled - * (via @Default on 'spring.cloud.kubernetes.config.enabled' and - * 'spring.cloud.kubernetes.secrets.enabled'); as such they are both registered. - * - * It also means that ConfigMapPropertySourceLocator and SecretsPropertySourceLocator - * are registered too. - * - * Since retry is not enabled explicitly, we also assert the types to ensure that - * these are not retryable beans. - */ - @Test - void testBothPresent() { - MockEnvironment environment = new MockEnvironment(); - ConfigurationPropertySources.attach(environment); - Binder binder = new Binder(ConfigurationPropertySources.get(environment)); - - DefaultBootstrapContext context = new DefaultBootstrapContext(); - Mockito.when(RESOLVER_CONTEXT.getBinder()).thenReturn(binder); - Mockito.when(RESOLVER_CONTEXT.getBootstrapContext()).thenReturn(context); - - Profiles profiles = Mockito.mock(Profiles.class); - ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); - - Assertions.assertTrue(context.isRegistered(KubernetesClientProperties.class)); - Assertions.assertTrue(context.isRegistered(CoreV1Api.class)); - Assertions.assertTrue(context.isRegistered(ApiClient.class)); - - Assertions.assertTrue(context.isRegistered(ConfigMapConfigProperties.class)); - Assertions.assertTrue(context.isRegistered(SecretsConfigProperties.class)); - - Assertions.assertTrue(context.isRegistered(ConfigMapPropertySourceLocator.class)); - Assertions.assertTrue(context.isRegistered(SecretsPropertySourceLocator.class)); - - ConfigMapPropertySourceLocator configMapPropertySourceLocator = context - .get(ConfigMapPropertySourceLocator.class); - Assertions.assertSame(KubernetesClientConfigMapPropertySourceLocator.class, - configMapPropertySourceLocator.getClass()); - - SecretsPropertySourceLocator secretsPropertySourceLocator = context.get(SecretsPropertySourceLocator.class); - Assertions.assertSame(KubernetesClientSecretsPropertySourceLocator.class, - secretsPropertySourceLocator.getClass()); - - } - - /** - * both ConfigMapConfigProperties and SecretsConfigProperties are enabled explicitly, - * as such they are both registered. - * - * It also means that ConfigMapPropertySourceLocator and SecretsPropertySourceLocator - * are registered too. - * - * Since retry is not enabled explicitly, we also assert the types to ensure that - * these are not retryable beans. - */ - @Test - void testBothPresentExplicitly() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.config.enabled", "true"); - environment.setProperty("spring.cloud.kubernetes.secrets.enabled", "true"); - ConfigurationPropertySources.attach(environment); - Binder binder = new Binder(ConfigurationPropertySources.get(environment)); - - DefaultBootstrapContext context = new DefaultBootstrapContext(); - Mockito.when(RESOLVER_CONTEXT.getBinder()).thenReturn(binder); - Mockito.when(RESOLVER_CONTEXT.getBootstrapContext()).thenReturn(context); - - Profiles profiles = Mockito.mock(Profiles.class); - ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); - - Assertions.assertTrue(context.isRegistered(KubernetesClientProperties.class)); - Assertions.assertTrue(context.isRegistered(CoreV1Api.class)); - Assertions.assertTrue(context.isRegistered(ApiClient.class)); - - Assertions.assertTrue(context.isRegistered(ConfigMapConfigProperties.class)); - Assertions.assertTrue(context.isRegistered(SecretsConfigProperties.class)); - - ConfigMapPropertySourceLocator configMapPropertySourceLocator = context - .get(ConfigMapPropertySourceLocator.class); - Assertions.assertSame(KubernetesClientConfigMapPropertySourceLocator.class, - configMapPropertySourceLocator.getClass()); - - SecretsPropertySourceLocator secretsPropertySourceLocator = context.get(SecretsPropertySourceLocator.class); - Assertions.assertSame(KubernetesClientSecretsPropertySourceLocator.class, - secretsPropertySourceLocator.getClass()); - } - - /* - * both ConfigMapConfigProperties and SecretsConfigProperties are enabled - * (via @Default on 'spring.cloud.kubernetes.config.enabled' and - * 'spring.cloud.kubernetes.secrets.enabled'); as such they are both registered. - * - * It also means that ConfigMapPropertySourceLocator and SecretsPropertySourceLocator - * are registered too. - * - * Since retry is enabled explicitly, we also assert the types to ensure that these - * are retryable beans. - */ - @Test - void testBothPresentAndRetryEnabled() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.config.retry.enabled", "true"); - environment.setProperty("spring.cloud.kubernetes.config.fail-fast", "true"); - environment.setProperty("spring.cloud.kubernetes.secrets.retry.enabled", "true"); - environment.setProperty("spring.cloud.kubernetes.secrets.fail-fast", "true"); - ConfigurationPropertySources.attach(environment); - Binder binder = new Binder(ConfigurationPropertySources.get(environment)); - - DefaultBootstrapContext context = new DefaultBootstrapContext(); - Mockito.when(RESOLVER_CONTEXT.getBinder()).thenReturn(binder); - Mockito.when(RESOLVER_CONTEXT.getBootstrapContext()).thenReturn(context); - - Profiles profiles = Mockito.mock(Profiles.class); - ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); - - Assertions.assertTrue(context.isRegistered(KubernetesClientProperties.class)); - Assertions.assertTrue(context.isRegistered(CoreV1Api.class)); - Assertions.assertTrue(context.isRegistered(ApiClient.class)); - - Assertions.assertTrue(context.isRegistered(ConfigMapConfigProperties.class)); - Assertions.assertTrue(context.isRegistered(SecretsConfigProperties.class)); - - Assertions.assertTrue(context.isRegistered(ConfigMapPropertySourceLocator.class)); - Assertions.assertTrue(context.isRegistered(SecretsPropertySourceLocator.class)); - - ConfigMapPropertySourceLocator configMapPropertySourceLocator = context - .get(ConfigMapPropertySourceLocator.class); - Assertions.assertSame(ConfigDataRetryableConfigMapPropertySourceLocator.class, - configMapPropertySourceLocator.getClass()); - - SecretsPropertySourceLocator secretsPropertySourceLocator = context.get(SecretsPropertySourceLocator.class); - Assertions.assertSame(ConfigDataRetryableSecretsPropertySourceLocator.class, - secretsPropertySourceLocator.getClass()); - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocatorTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocatorTests.java deleted file mode 100644 index 0ec6e336a3..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceLocatorTests.java +++ /dev/null @@ -1,198 +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.config; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; -import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; -import org.springframework.cloud.kubernetes.commons.config.RetryProperties; -import org.springframework.core.env.PropertySource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -class KubernetesClientConfigMapPropertySourceLocatorTests { - - private static final V1ConfigMapList PROPERTIES_CONFIGMAP_LIST = new V1ConfigMapList() - .addItemsItem( - new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-640").withNamespace("default") - .withResourceVersion("1").build()) - .addToData("application.properties", - "spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n" - + "logging.level.org.springframework.cloud.kubernetes=TRACE") - .build()); - - private static WireMockServer wireMockServer; - - private static final MockEnvironment ENV = new MockEnvironment(); - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @Test - void locateWithoutSources() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), List.of(), - Map.of(), true, "bootstrap-640", null, false, false, false, RetryProperties.DEFAULT); - MockEnvironment mockEnvironment = new MockEnvironment(); - mockEnvironment.setProperty("spring.cloud.kubernetes.client.namespace", "default"); - PropertySource propertySource = new KubernetesClientConfigMapPropertySourceLocator(api, - configMapConfigProperties, new KubernetesNamespaceProvider(mockEnvironment)).locate(ENV); - assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isTrue(); - } - - @Test - void locateWithSources() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - - ConfigMapConfigProperties.Source source = new ConfigMapConfigProperties.Source("bootstrap-640", "default", - Collections.emptyMap(), null, null, null); - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), - List.of(source), Map.of(), true, "fake-name", null, false, false, false, RetryProperties.DEFAULT); - - PropertySource propertySource = new KubernetesClientConfigMapPropertySourceLocator(api, - configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment())).locate(ENV); - assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isTrue(); - } - - /** - *
-	 *     1. not providing the namespace
-	 * 
- * - * will result in an Exception - */ - @Test - void testLocateWithoutNamespaceConstructor() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), List.of(), - Map.of(), true, "bootstrap-640", null, false, false, false, RetryProperties.DEFAULT); - - assertThatThrownBy(() -> new KubernetesClientConfigMapPropertySourceLocator(api, configMapConfigProperties, - new KubernetesNamespaceProvider(new MockEnvironment())).locate(ENV)) - .isInstanceOf(NamespaceResolutionFailedException.class); - } - - /** - *
-	 *     1. not providing the namespace
-	 * 
- * - * will result in an Exception - */ - @Test - void testLocateWithoutNamespace() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), List.of(), - Map.of(), true, "bootstrap-640", null, false, false, false, RetryProperties.DEFAULT); - assertThatThrownBy(() -> new KubernetesClientConfigMapPropertySourceLocator(api, configMapConfigProperties, - new KubernetesNamespaceProvider(ENV)).locate(ENV)) - .isInstanceOf(NamespaceResolutionFailedException.class); - } - - @Test - public void locateShouldThrowExceptionOnFailureWhenFailFastIsEnabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), List.of(), - Map.of(), true, "bootstrap-640", "default", false, false, true, RetryProperties.DEFAULT); - - KubernetesClientConfigMapPropertySourceLocator locator = new KubernetesClientConfigMapPropertySourceLocator(api, - configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment())); - - assertThatThrownBy(() -> locator.locate(new MockEnvironment())).isInstanceOf(IllegalStateException.class) - .hasMessage("Internal Server Error"); - } - - @Test - public void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(), List.of(), - Map.of(), true, "bootstrap-640", "default", false, false, false, RetryProperties.DEFAULT); - - KubernetesClientConfigMapPropertySourceLocator locator = new KubernetesClientConfigMapPropertySourceLocator(api, - configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment())); - - assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment())); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceTests.java deleted file mode 100644 index 95abc2dcfa..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigMapPropertySourceTests.java +++ /dev/null @@ -1,204 +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.config; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -class KubernetesClientConfigMapPropertySourceTests { - - private static final V1ConfigMapList PROPERTIES_CONFIGMAP_LIST = new V1ConfigMapList() - .addItemsItem( - new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-640").withNamespace("default") - .withResourceVersion("1").build()) - .addToData("application.properties", - "spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n" - + "logging.level.org.springframework.cloud.kubernetes=TRACE") - .build()); - - private static final V1ConfigMapList YAML_CONFIGMAP_LIST = new V1ConfigMapList() - .addItemsItem(new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-641").withNamespace("default") - .withResourceVersion("1").build()) - .addToData("application.yaml", - "dummy:\n property:\n string2: \"a\"\n int2: 1\n bool2: true\n") - .build()); - - private static WireMockServer wireMockServer; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - new KubernetesClientConfigMapsCache().discardAll(); - } - - @Test - public void propertiesFile() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - - NormalizedSource source = new NamedConfigMapNormalizedSource("bootstrap-640", "default", false, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(context); - - verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps"))); - assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isTrue(); - assertThat(propertySource.getProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isEqualTo("0"); - assertThat(propertySource.containsProperty("logging.level.org.springframework.cloud.kubernetes")).isTrue(); - assertThat(propertySource.getProperty("logging.level.org.springframework.cloud.kubernetes")).isEqualTo("TRACE"); - - } - - @Test - public void yamlFile() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(YAML_CONFIGMAP_LIST)))); - - NormalizedSource source = new NamedConfigMapNormalizedSource("bootstrap-641", "default", false, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(context); - - verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps"))); - assertThat(propertySource.containsProperty("dummy.property.string2")).isTrue(); - assertThat(propertySource.getProperty("dummy.property.string2")).isEqualTo("a"); - assertThat(propertySource.containsProperty("dummy.property.int2")).isTrue(); - assertThat(propertySource.getProperty("dummy.property.int2")).isEqualTo(1); - assertThat(propertySource.containsProperty("dummy.property.bool2")).isTrue(); - assertThat(propertySource.getProperty("dummy.property.bool2")).isEqualTo(true); - - } - - @Test - public void propertiesFileWithPrefix() { - CoreV1Api api = new CoreV1Api(); - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST)))); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("prefix", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource("bootstrap-640", "default", false, prefix, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(context); - - verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps"))); - assertThat(propertySource.containsProperty("prefix.spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isTrue(); - assertThat(propertySource.getProperty("prefix.spring.cloud.kubernetes.configuration.watcher.refreshDelay")) - .isEqualTo("0"); - assertThat(propertySource.containsProperty("prefix.logging.level.org.springframework.cloud.kubernetes")) - .isTrue(); - assertThat(propertySource.getProperty("prefix.logging.level.org.springframework.cloud.kubernetes")) - .isEqualTo("TRACE"); - } - - @Test - void constructorWithNamespaceMustNotFail() { - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("prefix", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource("bootstrap-640", "default", false, prefix, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(new CoreV1Api(), source, "default", - new MockEnvironment()); - - assertThat(new KubernetesClientConfigMapPropertySource(context)).isNotNull(); - } - - @Test - public void constructorShouldThrowExceptionOnFailureWhenFailFastIsEnabled() { - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("prefix", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource("my-config", "default", true, prefix, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(new CoreV1Api(), source, "default", - new MockEnvironment()); - - assertThatThrownBy(() -> new KubernetesClientConfigMapPropertySource(context)) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps"))); - } - - @Test - public void constructorShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() { - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("prefix", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource("my-config", "default", false, prefix, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(new CoreV1Api(), source, "default", - new MockEnvironment()); - - assertThatNoException().isThrownBy((() -> new KubernetesClientConfigMapPropertySource(context))); - verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps"))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigReloadAutoConfigurationTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigReloadAutoConfigurationTest.java deleted file mode 100644 index 3e017b2080..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigReloadAutoConfigurationTest.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; -import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientConfigReloadAutoConfiguration; -import org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientEventBasedConfigMapChangeDetector; -import org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientEventBasedSecretsChangeDetector; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector; -import org.springframework.cloud.kubernetes.commons.config.reload.PollingSecretsChangeDetector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Haytham Mohamed - **/ - -public class KubernetesClientConfigReloadAutoConfigurationTest { - - private ConfigurableApplicationContext context; - - public static WireMockServer wireMockServer; - - protected void setup(String... env) { - List envList = (env != null) ? new ArrayList<>(Arrays.asList(env)) : new ArrayList<>(); - envList.add("spring.cloud.kubernetes.client.namespace=default"); - String[] envArray = envList.toArray(new String[0]); - - context = new SpringApplicationBuilder(PropertyPlaceholderAutoConfiguration.class, LocalTestConfig.class, - ConfigReloadAutoConfiguration.class, RefreshAutoConfiguration.class, EndpointAutoConfiguration.class, - InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class, - ConfigurationPropertiesBindingPostProcessor.class, ConfigReloadPropertiesAutoConfiguration.class, - ConfigurationPropertiesRebinderAutoConfiguration.class, KubernetesClientBootstrapConfiguration.class, - KubernetesBootstrapConfiguration.class, KubernetesClientConfigReloadAutoConfiguration.class) - .web(org.springframework.boot.WebApplicationType.NONE).properties(envArray).run(); - } - - @BeforeAll - static void startWireMockServer() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - } - - @AfterEach - void afterEach() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @BeforeEach - void beforeEach() { - V1ConfigMapList TEST_CONFIGMAP = new V1ConfigMapList().addItemsItem(new V1ConfigMapBuilder().withMetadata( - new V1ObjectMetaBuilder().withName("test-cm").withNamespace("default").withResourceVersion("1").build()) - .addToData("app.name", "test").build()); - - WireMock.stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(TEST_CONFIGMAP)))); - } - - // 1. watchers - - @Test - void kubernetesWatchersWhenKubernetesDisabled() { - setup(); - assertThat(context.containsBean("configMapPropertySourceLocator")).isFalse(); - assertThat(context.containsBean("secretsPropertySourceLocator")).isFalse(); - assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("configMapPropertyChangeEventWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangeEventWatcher")).isFalse(); - } - - @Test - void kubernetesWatchersWhenConfigDisabled() { - setup("spring.cloud.kubernetes.config.enabled=false"); - assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("configMapPropertyChangeEventWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangeEventWatcher")).isFalse(); - } - - @Test - void kubernetesWatchersWhenReloadDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=false"); - assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("configMapPropertyChangeEventWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangeEventWatcher")).isFalse(); - } - - @Test - void kubernetesReloadEnabledButSecretAndConfigDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.config.enabled=false", - "spring.cloud.kubernetes.secrets.enabled=false"); - assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse(); - assertThat(context.containsBean("configMapPropertyChangeEventWatcher")).isFalse(); - assertThat(context.containsBean("secretsPropertyChangeEventWatcher")).isFalse(); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true by default
-	 *
-	 *     - config map event watcher is picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsEnabledByDefault() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.main.cloud-platform=KUBERNETES"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - Assertions.assertTrue(map.values().iterator().next().getClass() - .isAssignableFrom(KubernetesClientEventBasedConfigMapChangeDetector.class)); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true by default
-	 *
-	 *     - config map event watcher is picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=event", - "spring.main.cloud-platform=KUBERNETES"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - Assertions.assertTrue(map.values().iterator().next().getClass() - .isAssignableFrom(KubernetesClientEventBasedConfigMapChangeDetector.class)); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=event", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 0); - } - - /** - *
-	 *     - reload mode is enabled (via poll reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitoringConfigMapsDisabledMonitoringSecretsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=polling", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 0); - } - - /** - *
-	 *     - reload mode is enabled (via poll reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true by default
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitoringConfigMapsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=polling", - "spring.main.cloud-platform=KUBERNETES"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - Assertions.assertTrue( - map.values().iterator().next().getClass().isAssignableFrom(PollingConfigMapChangeDetector.class)); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsDisabledMonitoringSecretsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.reload.monitoring-secrets=true", - "spring.cloud.kubernetes.reload.monitoring-configMaps=false", - "spring.cloud.kubernetes.reload.mode=event"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - Assertions.assertTrue(map.values().iterator().next().getClass() - .isAssignableFrom(KubernetesClientEventBasedSecretsChangeDetector.class)); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitoringConfigMapsDisabledMonitoringSecretsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.reload.monitoring-secrets=true", - "spring.cloud.kubernetes.reload.monitoring-configMaps=false", - "spring.cloud.kubernetes.reload.mode=polling"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - Assertions.assertTrue( - map.values().iterator().next().getClass().isAssignableFrom(PollingSecretsChangeDetector.class)); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true
-	 *
-	 *     - config map event watcher is picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsEnabledMonitoringSecretsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.reload.monitoring-secrets=true", - "spring.cloud.kubernetes.reload.monitoring-configMaps=true", - "spring.cloud.kubernetes.reload.mode=event"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 2); - List result = map.values().stream() - .sorted(Comparator.comparing(x -> x.getClass().getName())).toList(); - Assertions.assertEquals(result.get(0).getClass(), KubernetesClientEventBasedConfigMapChangeDetector.class); - Assertions.assertEquals(result.get(1).getClass(), KubernetesClientEventBasedSecretsChangeDetector.class); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitoringConfigMapsEnabledMonitoringSecretsEnabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.reload.monitoring-secrets=true", - "spring.cloud.kubernetes.reload.monitoring-configMaps=true", - "spring.cloud.kubernetes.reload.mode=polling"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 2); - List result = map.values().stream() - .sorted(Comparator.comparing(x -> x.getClass().getName())).toList(); - Assertions.assertEquals(result.get(0).getClass(), PollingConfigMapChangeDetector.class); - Assertions.assertEquals(result.get(1).getClass(), PollingSecretsChangeDetector.class); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsDisabledMonitoringSecretsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=event", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=false", - "spring.cloud.kubernetes.reload.monitoring-secrets=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 0); - } - - /** - *
-	 *     - reload mode is enabled (via poll reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is false
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitorConfigMapsDisabledMonitoringSecretsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=polling", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=false", - "spring.cloud.kubernetes.reload.monitoring-secrets=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 0); - } - - /** - *
-	 *     - reload mode is enabled (via event reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is false
-	 *
-	 *     - config map event watcher is picked up
-	 *     - config map polling watcher is not picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadEventEnabledMonitoringConfigMapsEnabledMonitoringSecretsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=event", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=true", - "spring.cloud.kubernetes.reload.monitoring-secrets=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - List result = map.values().stream() - .sorted(Comparator.comparing(x -> x.getClass().getName())).toList(); - Assertions.assertEquals(result.get(0).getClass(), KubernetesClientEventBasedConfigMapChangeDetector.class); - } - - /** - *
-	 *     - reload mode is enabled (via polling reload)
-	 *     - spring.cloud.kubernetes.reload.monitoring-configMaps is true
-	 *     - spring.cloud.kubernetes.reload.monitoring-secrets is false
-	 *
-	 *     - config map event watcher is not picked up
-	 *     - config map polling watcher is picked up
-	 *     - secrets event watcher is not picked up
-	 *     - secrets polling watcher is not picked up
-	 * 
- */ - @Test - void reloadPollingEnabledMonitoringConfigMapsEnabledMonitoringSecretsDisabled() { - setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=polling", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.monitoring-configMaps=true", - "spring.cloud.kubernetes.reload.monitoring-secrets=false"); - Map map = context.getBeansOfType(ConfigurationChangeDetector.class); - Assertions.assertEquals(map.size(), 1); - List result = map.values().stream() - .sorted(Comparator.comparing(x -> x.getClass().getName())).toList(); - Assertions.assertEquals(result.get(0).getClass(), PollingConfigMapChangeDetector.class); - } - - // 2. config and secrets property source locators - - @Test - void kubernetesConfigAndSecretEnabledByDefault() { - setup("spring.main.cloud-platform=KUBERNETES"); - assertThat(context.containsBean("configMapPropertySourceLocator")).isTrue(); - assertThat(context.containsBean("secretsPropertySourceLocator")).isTrue(); - } - - @Test - void kubernetesConfigEnabledButSecretDisabled() { - setup("spring.cloud.kubernetes.secrets.enabled=false", "spring.main.cloud-platform=KUBERNETES"); - assertThat(context.containsBean("configMapPropertySourceLocator")).isTrue(); - assertThat(context.containsBean("secretsPropertySourceLocator")).isFalse(); - } - - @Test - void kubernetesSecretsEnabledButConfigDisabled() { - setup("spring.cloud.kubernetes.config.enabled=false", "spring.main.cloud-platform=KUBERNETES"); - assertThat(context.containsBean("configMapPropertySourceLocator")).isFalse(); - assertThat(context.containsBean("secretsPropertySourceLocator")).isTrue(); - } - - @Configuration(proxyBeanMethods = false) - @AutoConfigureBefore(KubernetesClientAutoConfiguration.class) - static class LocalTestConfig { - - @ConditionalOnMissingBean(KubernetesClientProperties.class) - @Bean - KubernetesClientProperties kubernetesClientProperties() { - return new KubernetesClientProperties(null, null, null, "default", null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null); - } - - @Bean - ApiClient apiClient() { - ApiClient apiClient = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - apiClient.setDebugging(true); - apiClient.setReadTimeout(0); - return apiClient; - } - - @Bean - CoreV1Api coreApi(ApiClient apiClient) { - return new CoreV1Api(apiClient); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtilsTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtilsTests.java deleted file mode 100644 index f874bad16c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigUtilsTests.java +++ /dev/null @@ -1,56 +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.config; - -import java.time.Duration; -import java.util.Set; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.mock.env.MockEnvironment; - -/** - * @author wind57 - */ -class KubernetesClientConfigUtilsTests { - - @Test - void testNamespacesFromProperties() { - ConfigReloadProperties properties = new ConfigReloadProperties(false, false, false, - ConfigReloadProperties.ReloadStrategy.REFRESH, ConfigReloadProperties.ReloadDetectionMode.EVENT, - Duration.ofMillis(15000), Set.of("non-default"), false, Duration.ofSeconds(2)); - Set namespaces = KubernetesClientConfigUtils - .namespaces(new KubernetesNamespaceProvider(new MockEnvironment()), properties, "configmap"); - Assertions.assertEquals(1, namespaces.size()); - Assertions.assertEquals(namespaces.iterator().next(), "non-default"); - } - - @Test - void testNamespacesFromProvider() { - ConfigReloadProperties properties = ConfigReloadProperties.DEFAULT; - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.client.namespace", "some"); - KubernetesNamespaceProvider provider = new KubernetesNamespaceProvider(environment); - Set namespaces = KubernetesClientConfigUtils.namespaces(provider, properties, "configmap"); - Assertions.assertEquals(1, namespaces.size()); - Assertions.assertEquals(namespaces.iterator().next(), "some"); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocatorTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocatorTests.java deleted file mode 100644 index 841dfa79f1..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocatorTests.java +++ /dev/null @@ -1,188 +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.config; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; -import org.springframework.cloud.kubernetes.commons.config.RetryProperties; -import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; -import org.springframework.core.env.PropertySource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -class KubernetesClientSecretsPropertySourceLocatorTests { - - private static final String LIST_API = "/api/v1/namespaces/default/secrets"; - - private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n" - + "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n" - + "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n" - + "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n" - + "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n" - + "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n" - + "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n" - + "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n" - + "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n" - + "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n" - + "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n" - + "\t\t\t\t\"namespace\": \"default\",\n" - + "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n" - + "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n" - + "\t\t\t\t\"resourceVersion\": \"162708\",\n" - + "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n" - + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n" - + "\t\t\t\t\"annotations\": {\n" - + "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n" - + "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n" - + "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" - + "\t\t}\n" + "\t]\n" + "}"; - - private static WireMockServer wireMockServer; - - private static final MockEnvironment ENV = new MockEnvironment(); - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterAll - static void after() { - wireMockServer.stop(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @Test - void getLocateWithSources() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY))); - - SecretsConfigProperties.Source source1 = new SecretsConfigProperties.Source("db-secret", "", - Collections.emptyMap(), null, null, null); - - SecretsConfigProperties.Source source2 = new SecretsConfigProperties.Source("rabbit-password", "", - Collections.emptyMap(), null, null, null); - - SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties(true, Map.of(), List.of(), - List.of(source1, source2), true, "app", "default", false, true, false, RetryProperties.DEFAULT); - - PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api, - new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties).locate(ENV); - assertThat(propertySource.containsProperty("password")).isTrue(); - assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd"); - } - - @Test - void getLocateWithOutSources() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY))); - SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties(true, Map.of(), List.of(), - List.of(), true, "db-secret", "default", false, true, false, RetryProperties.DEFAULT); - - PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api, - new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties).locate(ENV); - assertThat(propertySource.containsProperty("password")).isTrue(); - assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd"); - } - - /** - *
-	 *     1. not providing the namespace
-	 * 
- * - * will result in an Exception - */ - @Test - void testLocateWithoutNamespaceConstructor() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY))); - - SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties(true, Map.of(), List.of(), - List.of(), true, "db-secret", "", false, true, false, RetryProperties.DEFAULT); - - assertThatThrownBy(() -> new KubernetesClientSecretsPropertySourceLocator(api, - new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties).locate(ENV)) - .isInstanceOf(NamespaceResolutionFailedException.class); - } - - @Test - void locateShouldThrowExceptionOnFailureWhenFailFastIsEnabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties(true, Map.of(), List.of(), - List.of(), true, "db-secret", "default", false, true, true, RetryProperties.DEFAULT); - - KubernetesClientSecretsPropertySourceLocator locator = new KubernetesClientSecretsPropertySourceLocator(api, - new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties); - - assertThatThrownBy(() -> locator.locate(new MockEnvironment())).isInstanceOf(IllegalStateException.class) - .hasMessage("Internal Server Error"); - } - - @Test - void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties(true, Map.of(), List.of(), - List.of(), true, "db-secret", "default", false, true, false, RetryProperties.DEFAULT); - - KubernetesClientSecretsPropertySourceLocator locator = new KubernetesClientSecretsPropertySourceLocator(api, - new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties); - - assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment())); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceTests.java deleted file mode 100644 index d3ebd5ad29..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceTests.java +++ /dev/null @@ -1,197 +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.config; - -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.openapi.models.V1SecretListBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -class KubernetesClientSecretsPropertySourceTests { - - private static final String API = "/api/v1/namespaces/default/secrets"; - - private static final V1SecretList SECRET_LIST = new V1SecretListBuilder().addToItems(new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("db-secret").withResourceVersion("0") - .withNamespace("default").build()) - .addToData("password", "p455w0rd".getBytes()).addToData("username", "user".getBytes()).build()).build(); - - private static final V1SecretList EMPTY_DATA_SECRET_LIST = new V1SecretListBuilder() - .addToItems(new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withName("db-secret") - .withResourceVersion("0").withNamespace("default").build()).build()) - .build(); - - private static final String LIST_API_WITH_LABEL = "/api/v1/namespaces/default/secrets"; - - private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n" - + "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n" - + "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n" - + "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n" - + "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n" - + "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n" - + "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n" - + "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n" - + "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n" - + "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n" - + "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n" - + "\t\t\t\t\"namespace\": \"default\",\n" - + "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n" - + "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n" - + "\t\t\t\t\"resourceVersion\": \"162708\",\n" - + "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n" - + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n" - + "\t\t\t\t\"annotations\": {\n" - + "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n" - + "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n" - + "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" - + "\t\t}\n" + "\t]\n" + "}"; - - private static WireMockServer wireMockServer; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterAll - static void after() { - WireMock.shutdownServer(); - wireMockServer.stop(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - new KubernetesClientSecretsCache().discardAll(); - } - - @Test - void emptyDataSecretTest() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(EMPTY_DATA_SECRET_LIST)))); - - NormalizedSource source = new NamedSecretNormalizedSource("db-secret", "default", false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - - KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(context); - assertThat(propertySource.getName()).isEqualTo("secret.db-secret.default"); - assertThat(propertySource.getPropertyNames()).isEmpty(); - } - - @Test - void secretsTest() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SECRET_LIST)))); - - NormalizedSource source = new NamedSecretNormalizedSource("db-secret", "default", false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - - KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(context); - assertThat(propertySource.containsProperty("password")).isTrue(); - assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd"); - assertThat(propertySource.containsProperty("username")).isTrue(); - assertThat(propertySource.getProperty("username")).isEqualTo("user"); - } - - @Test - void secretLabelsTest() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(LIST_API_WITH_LABEL).willReturn(aResponse().withStatus(200).withBody(LIST_BODY))); - Map labels = new HashMap<>(); - labels.put("spring.cloud.kubernetes.secret", "true"); - - NormalizedSource source = new LabeledSecretNormalizedSource("default", labels, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - - KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(context); - assertThat(propertySource.containsProperty("spring.rabbitmq.password")).isTrue(); - assertThat(propertySource.getProperty("spring.rabbitmq.password")).isEqualTo("password"); - } - - @Test - void constructorShouldThrowExceptionOnFailureWhenFailFastIsEnabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - NormalizedSource source = new NamedSecretNormalizedSource("secret", "default", true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - - assertThatThrownBy(() -> new KubernetesClientSecretsPropertySource(context)) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - verify(getRequestedFor(urlEqualTo(API))); - } - - @Test - void constructorShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() { - CoreV1Api api = new CoreV1Api(); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - NormalizedSource source = new NamedSecretNormalizedSource("secret", "db-secret", false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default", - new MockEnvironment()); - - assertThatNoException().isThrownBy((() -> new KubernetesClientSecretsPropertySource(context))); - verify(getRequestedFor(urlEqualTo(API))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProviderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProviderTests.java deleted file mode 100644 index 653755b400..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledConfigMapContextToSourceDataProviderTests.java +++ /dev/null @@ -1,514 +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.config; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.LabeledConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.SourceData; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class LabeledConfigMapContextToSourceDataProviderTests { - - private static final Map LABELS = new LinkedHashMap<>(); - - private static final Map RED_LABEL = Map.of("color", "red"); - - private static final Map BLUE_LABEL = Map.of("color", "blue"); - - private static final Map PINK_LABEL = Map.of("color", "pink"); - - private static final String NAMESPACE = "default"; - - static { - LABELS.put("label2", "value2"); - LABELS.put("label1", "value1"); - } - - @BeforeAll - static void setup() { - WireMockServer wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - new KubernetesClientConfigMapsCache().discardAll(); - } - - /** - * we have a single config map deployed. it has two labels and these match against our - * queries. - */ - @Test - void singleConfigMapMatchAgainstLabels() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("test-configmap") - .withLabels(LABELS).withNamespace(NAMESPACE).build()).addToData("name", "value").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, LABELS, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals("configmap.test-configmap.default", sourceData.sourceName()); - Assertions.assertEquals(Map.of("name", "value"), sourceData.sourceData()); - - } - - /** - * we have three configmaps deployed. two of them have labels that match (color=red), - * one does not (color=blue). - */ - @Test - void twoConfigMapsMatchAgainstLabels() { - - V1ConfigMap redOne = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("red-configmap") - .withLabels(RED_LABEL).withNamespace(NAMESPACE).build()).addToData("colorOne", "really-red").build(); - - V1ConfigMap redTwo = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("red-configmap-again").withLabels(RED_LABEL).withNamespace(NAMESPACE).build()) - .addToData("colorTwo", "really-red-again").build(); - - V1ConfigMap blue = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("blue-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("color", "blue").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(redOne).addItemsItem(redTwo) - .addItemsItem(blue); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, RED_LABEL, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red-configmap.red-configmap-again.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("colorOne"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("colorTwo"), "really-red-again"); - - } - - /** - * one configmap deployed (pink), does not match our query (blue). - */ - @Test - void configMapNoMatch() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("pink-configmap") - .withLabels(PINK_LABEL).withNamespace(NAMESPACE).build()).addToData("color", "pink").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.color.default"); - Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap()); - - } - - /** - * LabeledConfigMapContextToSourceDataProvider gets as input a Fabric8ConfigContext. - * This context has a namespace as well as a NormalizedSource, that has a namespace - * too. It is easy to get confused in code on which namespace to use. This test makes - * sure that we use the proper one. - */ - @Test - void namespaceMatch() { - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("test-configmap") - .withLabels(LABELS).withNamespace(NAMESPACE).build()).addToData("name", "value").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - String wrongNamespace = NAMESPACE + "nope"; - NormalizedSource source = new LabeledConfigMapNormalizedSource(wrongNamespace, LABELS, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals("configmap.test-configmap.default", sourceData.sourceName()); - Assertions.assertEquals(Map.of("name", "value"), sourceData.sourceData()); - } - - /** - * one configmap with name : "blue-configmap" and labels "color=blue" is deployed. we - * search it with the same labels, find it, and assert that name of the SourceData (it - * must use its name, not its labels) and values in the SourceData must be prefixed - * (since we have provided an explicit prefix). - */ - @Test - void testWithPrefix() { - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("blue-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("what-color", "blue-color").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - ConfigUtils.Prefix mePrefix = ConfigUtils.findPrefix("me", false, false, "irrelevant"); - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, mePrefix, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals("configmap.blue-configmap.default", sourceData.sourceName()); - Assertions.assertEquals(Map.of("me.what-color", "blue-color"), sourceData.sourceData()); - } - - /** - * two configmaps are deployed (name:blue-configmap, name:another-blue-configmap) and - * labels "color=blue" (on both). we search with the same labels, find them, and - * assert that name of the SourceData (it must use its name, not its labels) and - * values in the SourceData must be prefixed (since we have provided a delayed - * prefix). - * - * Also notice that the prefix is made up from both configmap names. - * - */ - @Test - void testTwoConfigmapsWithPrefix() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("blue-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("first", "blue").build(); - - V1ConfigMap two = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("another-blue-configmap").withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()) - .addToData("second", "blue").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one).addItemsItem(two); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, - ConfigUtils.Prefix.DELAYED, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.another-blue-configmap.blue-configmap.default"); - - Map properties = sourceData.sourceData(); - Assertions.assertEquals(2, properties.size()); - Iterator keys = properties.keySet().iterator(); - String firstKey = keys.next(); - String secondKey = keys.next(); - - if (firstKey.contains("first")) { - Assertions.assertEquals(firstKey, "another-blue-configmap.blue-configmap.first"); - } - - Assertions.assertEquals(secondKey, "another-blue-configmap.blue-configmap.second"); - Assertions.assertEquals(properties.get(firstKey), "blue"); - Assertions.assertEquals(properties.get(secondKey), "blue"); - } - - /** - * two configmaps are deployed: "color-configmap" with label: "{color:blue}" and - * "color-configmap-k8s" with no labels. We search by "{color:red}", do not find - * anything and thus have an empty SourceData. profile based sources are enabled, but - * it has no effect. - */ - @Test - void searchWithLabelsNoConfigmapsFound() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("color-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("one", "1").build(); - - V1ConfigMap two = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("color-config-k8s").withNamespace(NAMESPACE).build()) - .addToData("two", "2").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one).addItemsItem(two); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, RED_LABEL, true, - ConfigUtils.Prefix.DEFAULT, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertTrue(sourceData.sourceData().isEmpty()); - Assertions.assertEquals(sourceData.sourceName(), "configmap.color.default"); - - } - - /** - * two configmaps are deployed: "color-configmap" with label: "{color:blue}" and - * "shape-configmap" with label: "{shape:round}". We search by "{color:blue}" and find - * one configmap. profile based sources are enabled, but it has no effect. - */ - @Test - void searchWithLabelsOneConfigMapFound() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("color-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("one", "1").build(); - - V1ConfigMap two = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("shape-configmap").withNamespace(NAMESPACE).build()) - .addToData("two", "2").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one).addItemsItem(two); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, - ConfigUtils.Prefix.DEFAULT, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 1); - Assertions.assertEquals(sourceData.sourceData().get("one"), "1"); - Assertions.assertEquals(sourceData.sourceName(), "configmap.color-configmap.default"); - - } - - /** - * two configmaps are deployed: "color-configmap" with label: "{color:blue}" and - * "color-configmap-k8s" with label: "{color:red}". We search by "{color:blue}" and - * find one configmap. Since profiles are enabled, we will also be reading - * "color-configmap-k8s", even if its labels do not match provided ones. - */ - @Test - void searchWithLabelsOneConfigMapFoundAndOneFromProfileFound() { - - V1ConfigMap one = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("color-configmap") - .withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()).addToData("one", "1").build(); - - V1ConfigMap two = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("color-configmap-k8s").withLabels(RED_LABEL).withNamespace(NAMESPACE).build()) - .addToData("two", "2").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one).addItemsItem(two); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("k8s"); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, - ConfigUtils.Prefix.DELAYED, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("color-configmap.color-configmap-k8s.one"), "1"); - Assertions.assertEquals(sourceData.sourceData().get("color-configmap.color-configmap-k8s.two"), "2"); - Assertions.assertEquals(sourceData.sourceName(), "configmap.color-configmap.color-configmap-k8s.default"); - - } - - /** - *
-	 *     - configmap "color-configmap" with label "{color:blue}"
-	 *     - configmap "shape-configmap" with labels "{color:blue, shape:round}"
-	 *     - configmap "no-fit" with labels "{tag:no-fit}"
-	 *     - configmap "color-configmap-k8s" with label "{color:red}"
-	 *     - configmap "shape-configmap-k8s" with label "{shape:triangle}"
-	 * 
- */ - @Test - void searchWithLabelsTwoConfigMapsFoundAndOneFromProfileFound() { - - V1ConfigMap colorConfigMap = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("color-configmap").withLabels(BLUE_LABEL).withNamespace(NAMESPACE).build()) - .addToData("one", "1").build(); - - V1ConfigMap shapeConfigmap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("shape-configmap") - .withLabels(Map.of("color", "blue", "shape", "round")).withNamespace(NAMESPACE).build()) - .addToData("two", "2").build(); - - V1ConfigMap noFit = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("no-fit") - .withLabels(Map.of("tag", "no-fit")).withNamespace(NAMESPACE).build()).addToData("three", "3").build(); - - V1ConfigMap colorConfigmapK8s = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("color-configmap-k8s").withLabels(RED_LABEL).withNamespace(NAMESPACE).build()) - .addToData("four", "4").build(); - - V1ConfigMap shapeConfigmapK8s = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("shape-configmap-k8s") - .withLabels(Map.of("shape", "triangle")).withNamespace(NAMESPACE).build()) - .addToData("five", "5").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(colorConfigMap).addItemsItem(shapeConfigmap) - .addItemsItem(noFit).addItemsItem(colorConfigmapK8s).addItemsItem(shapeConfigmapK8s); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("k8s"); - - NormalizedSource source = new LabeledConfigMapNormalizedSource(NAMESPACE, BLUE_LABEL, true, - ConfigUtils.Prefix.DELAYED, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 4); - Assertions.assertEquals(sourceData.sourceData() - .get("color-configmap.color-configmap-k8s.shape-configmap.shape-configmap-k8s.one"), "1"); - Assertions.assertEquals(sourceData.sourceData() - .get("color-configmap.color-configmap-k8s.shape-configmap.shape-configmap-k8s.two"), "2"); - Assertions.assertEquals(sourceData.sourceData() - .get("color-configmap.color-configmap-k8s.shape-configmap.shape-configmap-k8s.four"), "4"); - Assertions.assertEquals(sourceData.sourceData() - .get("color-configmap.color-configmap-k8s.shape-configmap.shape-configmap-k8s.five"), "5"); - - Assertions.assertEquals(sourceData.sourceName(), - "configmap.color-configmap.color-configmap-k8s.shape-configmap.shape-configmap-k8s.default"); - - } - - /** - *
-	 *     - one configmap is deployed with label {"color", "red"}
-	 *     - one configmap is deployed with label {"color", "green"}
-	 *
-	 *     - we first search for "red" and find it, and it is retrieved from the cluster via the client.
-	 * 	   - we then search for the "green" one, and it is retrieved from the cache this time.
-	 * 
- */ - @Test - void cache(CapturedOutput output) { - V1ConfigMap red = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "red")).withNamespace(NAMESPACE).withName("red-configmap").build()) - .addToData("color", "red").build(); - - V1ConfigMap green = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "green")).withNamespace(NAMESPACE).withName("green-configmap").build()) - .addToData("color", "green").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red).addItemsItem(green); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource redSource = new LabeledConfigMapNormalizedSource(NAMESPACE, Map.of("color", "red"), false, - ConfigUtils.Prefix.DEFAULT, false); - KubernetesClientConfigContext redContext = new KubernetesClientConfigContext(api, redSource, NAMESPACE, - new MockEnvironment()); - KubernetesClientContextToSourceData redData = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData redSourceData = redData.apply(redContext); - - Assertions.assertEquals(redSourceData.sourceData().size(), 1); - Assertions.assertEquals(redSourceData.sourceData().get("color"), "red"); - Assertions.assertEquals(redSourceData.sourceName(), "configmap.red-configmap.default"); - Assertions.assertTrue(output.getAll().contains("Loaded all config maps in namespace '" + NAMESPACE + "'")); - - NormalizedSource greenSource = new LabeledConfigMapNormalizedSource(NAMESPACE, Map.of("color", "green"), false, - ConfigUtils.Prefix.DEFAULT, false); - KubernetesClientConfigContext greenContext = new KubernetesClientConfigContext(api, greenSource, NAMESPACE, - new MockEnvironment()); - KubernetesClientContextToSourceData greenData = new LabeledConfigMapContextToSourceDataProvider().get(); - SourceData greenSourceData = greenData.apply(greenContext); - - Assertions.assertEquals(greenSourceData.sourceData().size(), 1); - Assertions.assertEquals(greenSourceData.sourceData().get("color"), "green"); - Assertions.assertEquals(greenSourceData.sourceName(), "configmap.green-configmap.default"); - - // meaning there is a single entry with such a log statement - String[] out = output.getAll().split("Loaded all config maps in namespace"); - Assertions.assertEquals(out.length, 2); - - // meaning that the second read was done from the cache - out = output.getAll().split("Loaded \\(from cache\\) all config maps in namespace"); - Assertions.assertEquals(out.length, 2); - } - - private void stubCall(V1ConfigMapList list) { - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProviderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProviderTests.java deleted file mode 100644 index 804afeee3d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/LabeledSecretContextToSourceDataProviderTests.java +++ /dev/null @@ -1,507 +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.config; - -import java.util.Base64; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.SourceData; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class LabeledSecretContextToSourceDataProviderTests { - - private static final Map LABELS = new LinkedHashMap<>(); - - private static final Map RED_LABEL = Map.of("color", "red"); - - private static final String NAMESPACE = "default"; - - static { - LABELS.put("label2", "value2"); - LABELS.put("label1", "value1"); - } - - @BeforeAll - static void setup() { - WireMockServer wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - new KubernetesClientSecretsCache().discardAll(); - } - - /** - * we have a single secret deployed. it does not match our query. - */ - @Test - void noMatch() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withLabels(Collections.singletonMap("color", "red")) - .withNamespace(NAMESPACE).withName("red-secret").build()) - .addToData("color", Base64.getEncoder().encode("really-red".getBytes())).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(red); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - // blue does not match red - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, - Collections.singletonMap("color", "blue"), false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.color.default"); - Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap()); - - } - - /** - * we have a single secret deployed. it has two labels and these match against our - * queries. - */ - @Test - void singleSecretMatchAgainstLabels() { - - V1Secret red = new V1SecretBuilder().withMetadata( - new V1ObjectMetaBuilder().withLabels(LABELS).withNamespace(NAMESPACE).withName("test-secret").build()) - .addToData("color", "really-red".getBytes()).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(red); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, LABELS, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.test-secret.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red")); - - } - - /** - * we have two secrets deployed. both of them have labels that match (color=red). - */ - @Test - void twoSecretsMatchAgainstLabels() { - - V1Secret one = new V1SecretBuilder().withMetadata( - new V1ObjectMetaBuilder().withLabels(RED_LABEL).withNamespace(NAMESPACE).withName("color-one").build()) - .addToData("colorOne", "really-red-one".getBytes()).build(); - - V1Secret two = new V1SecretBuilder().withMetadata( - new V1ObjectMetaBuilder().withLabels(RED_LABEL).withNamespace(NAMESPACE).withName("color-two").build()) - .addToData("colorTwo", "really-red-two".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(one).addItemsItem(two); - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, RED_LABEL, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.color-one.color-two.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("colorOne"), "really-red-one"); - Assertions.assertEquals(sourceData.sourceData().get("colorTwo"), "really-red-two"); - - } - - @Test - void namespaceMatch() { - V1Secret one = new V1SecretBuilder().withMetadata( - new V1ObjectMetaBuilder().withLabels(LABELS).withNamespace(NAMESPACE).withName("test-secret").build()) - .addToData("color", "really-red".getBytes()).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(one); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE + "nope", LABELS, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.test-secret.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red")); - } - - /** - * one secret with name : "blue-secret" and labels "color=blue" is deployed. we search - * it with the same labels, find it, and assert that name of the SourceData (it must - * use its name, not its labels) and values in the SourceData must be prefixed (since - * we have provided an explicit prefix). - */ - @Test - void testWithPrefix() { - - V1Secret one = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withLabels(Map.of("color", "blue")) - .withNamespace(NAMESPACE).withName("blue-secret").build()) - .addToData("what-color", "blue-color".getBytes()).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(one); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("me", false, false, null); - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, prefix, - false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals("secret.blue-secret.default", sourceData.sourceName()); - Assertions.assertEquals(Map.of("me.what-color", "blue-color"), sourceData.sourceData()); - } - - /** - * two secrets are deployed (name:blue-secret, name:another-blue-secret) and labels - * "color=blue" (on both). we search with the same labels, find them, and assert that - * name of the SourceData (it must use its name, not its labels) and values in the - * SourceData must be prefixed (since we have provided a delayed prefix). - * - * Also notice that the prefix is made up from both secret names. - * - */ - @Test - void testTwoSecretsWithPrefix() { - - V1Secret one = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withLabels(Map.of("color", "blue")) - .withNamespace(NAMESPACE).withName("blue-secret").build()).addToData("first", "blue".getBytes()) - .build(); - - V1Secret two = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withLabels(Map.of("color", "blue")) - .withNamespace(NAMESPACE).withName("another-blue-secret").build()) - .addToData("second", "blue".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(one).addItemsItem(two); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, - ConfigUtils.Prefix.DELAYED, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - // maps don't have a defined order, so assert components separately - Assertions.assertEquals(46, sourceData.sourceName().length()); - Assertions.assertTrue(sourceData.sourceName().contains("secret")); - Assertions.assertTrue(sourceData.sourceName().contains("blue-secret")); - Assertions.assertTrue(sourceData.sourceName().contains("another-blue-secret")); - Assertions.assertTrue(sourceData.sourceName().contains("default")); - - Map properties = sourceData.sourceData(); - Assertions.assertEquals(2, properties.size()); - Iterator keys = properties.keySet().iterator(); - String firstKey = keys.next(); - String secondKey = keys.next(); - - if (firstKey.contains("first")) { - Assertions.assertEquals(firstKey, "another-blue-secret.blue-secret.first"); - } - - Assertions.assertEquals(secondKey, "another-blue-secret.blue-secret.second"); - Assertions.assertEquals(properties.get(firstKey), "blue"); - Assertions.assertEquals(properties.get(secondKey), "blue"); - } - - /** - * two secrets are deployed: secret "color-secret" with label: "{color:blue}" and - * "shape-secret" with label: "{shape:round}". We search by "{color:blue}" and find - * one secret. profile based sources are enabled, but it has no effect. - */ - @Test - void searchWithLabelsOneSecretFound() { - - V1Secret colorSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "blue")).withNamespace(NAMESPACE).withName("color-secret").build()) - .addToData("one", "1".getBytes()).build(); - - V1Secret shapeSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("shape", "round")).withNamespace(NAMESPACE).withName("shape-secret").build()) - .addToData("two", "2".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(colorSecret).addItemsItem(shapeSecret); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, - ConfigUtils.Prefix.DEFAULT, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 1); - Assertions.assertEquals(sourceData.sourceData().get("one"), "1"); - Assertions.assertEquals(sourceData.sourceName(), "secret.color-secret.default"); - - } - - /** - * two secrets are deployed: secret "color-secret" with label: "{color:blue}" and - * "color-secret-k8s" with label: "{color:red}". We search by "{color:blue}" and find - * one secret. Since profiles are enabled, we will also be reading "color-secret-k8s", - * even if its labels do not match provided ones. - */ - @Test - void searchWithLabelsOneSecretFoundAndOneFromProfileFound() { - - V1Secret colorSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "blue")).withNamespace(NAMESPACE).withName("color-secret").build()) - .addToData("one", "1".getBytes()).build(); - - V1Secret shapeSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "red")).withNamespace(NAMESPACE).withName("color-secret-k8s").build()) - .addToData("two", "2".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(colorSecret).addItemsItem(shapeSecret); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("k8s"); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, - ConfigUtils.Prefix.DELAYED, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("color-secret.color-secret-k8s.one"), "1"); - Assertions.assertEquals(sourceData.sourceData().get("color-secret.color-secret-k8s.two"), "2"); - Assertions.assertEquals(sourceData.sourceName(), "secret.color-secret.color-secret-k8s.default"); - - } - - /** - *
-	 *     - secret "color-secret" with label "{color:blue}"
-	 *     - secret "shape-secret" with labels "{color:blue, shape:round}"
-	 *     - secret "no-fit" with labels "{tag:no-fit}"
-	 *     - secret "color-secret-k8s" with label "{color:red}"
-	 *     - secret "shape-secret-k8s" with label "{shape:triangle}"
-	 * 
- */ - @Test - void searchWithLabelsTwoSecretsFoundAndOneFromProfileFound() { - - V1Secret colorSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "blue")).withNamespace(NAMESPACE).withName("color-secret").build()) - .addToData("one", "1".getBytes()).build(); - - V1Secret shapeSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withLabels(Map.of("color", "blue", "shape", "round")) - .withNamespace(NAMESPACE).withName("shape-secret").build()) - .addToData("two", "2".getBytes()).build(); - - V1Secret noFit = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("tag", "no-fit")).withNamespace(NAMESPACE).withName("no-fit").build()) - .addToData("three", "3".getBytes()).build(); - - V1Secret colorSecretK8s = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "red")).withNamespace(NAMESPACE).withName("color-secret-k8s").build()) - .addToData("four", "4".getBytes()).build(); - - V1Secret shapeSecretK8s = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("shape", "triangle")).withNamespace(NAMESPACE).withName("shape-secret-k8s").build()) - .addToData("five", "5".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(colorSecret).addItemsItem(shapeSecret) - .addItemsItem(noFit).addItemsItem(colorSecretK8s).addItemsItem(shapeSecretK8s); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("k8s"); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, - ConfigUtils.Prefix.DELAYED, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 4); - Assertions.assertEquals( - sourceData.sourceData().get("color-secret.color-secret-k8s.shape-secret.shape-secret-k8s.one"), "1"); - Assertions.assertEquals( - sourceData.sourceData().get("color-secret.color-secret-k8s.shape-secret.shape-secret-k8s.two"), "2"); - Assertions.assertEquals( - sourceData.sourceData().get("color-secret.color-secret-k8s.shape-secret.shape-secret-k8s.four"), "4"); - Assertions.assertEquals( - sourceData.sourceData().get("color-secret.color-secret-k8s.shape-secret.shape-secret-k8s.five"), "5"); - - Assertions.assertEquals(sourceData.sourceName(), - "secret.color-secret.color-secret-k8s.shape-secret.shape-secret-k8s.default"); - - } - - /** - * yaml/properties gets special treatment - */ - @Test - void testYaml() { - V1Secret colorSecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "blue")).withNamespace(NAMESPACE).withName("color-secret").build()) - .addToData("test.yaml", "color: blue".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(colorSecret); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "blue"), false, - ConfigUtils.Prefix.DEFAULT, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceData().size(), 1); - Assertions.assertEquals(sourceData.sourceData().get("color"), "blue"); - Assertions.assertEquals(sourceData.sourceName(), "secret.color-secret.default"); - } - - /** - *
-	 *     - one secret is deployed with label {"color", "red"}
-	 *     - one secret is deployed with label {"color", "green"}
-	 *
-	 *     - we first search for "red" and find it, and it is retrieved from the cluster via the client.
-	 * 	   - we then search for the "green" one, and it is retrieved from the cache this time.
-	 * 
- */ - @Test - void cache(CapturedOutput output) { - V1Secret red = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withLabels(Map.of("color", "red")) - .withNamespace(NAMESPACE).withName("red").build()).addToData("color", "red".getBytes()).build(); - - V1Secret green = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder() - .withLabels(Map.of("color", "green")).withNamespace(NAMESPACE).withName("green").build()) - .addToData("color", "green".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(red).addItemsItem(green); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource redSource = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "red"), false, - ConfigUtils.Prefix.DEFAULT, false); - KubernetesClientConfigContext redContext = new KubernetesClientConfigContext(api, redSource, NAMESPACE, - new MockEnvironment()); - KubernetesClientContextToSourceData redData = new LabeledSecretContextToSourceDataProvider().get(); - SourceData redSourceData = redData.apply(redContext); - - Assertions.assertEquals(redSourceData.sourceData().size(), 1); - Assertions.assertEquals(redSourceData.sourceData().get("color"), "red"); - Assertions.assertEquals(redSourceData.sourceName(), "secret.red.default"); - Assertions.assertTrue(output.getAll().contains("Loaded all secrets in namespace '" + NAMESPACE + "'")); - - NormalizedSource greenSource = new LabeledSecretNormalizedSource(NAMESPACE, Map.of("color", "green"), false, - ConfigUtils.Prefix.DEFAULT, false); - KubernetesClientConfigContext greenContext = new KubernetesClientConfigContext(api, greenSource, NAMESPACE, - new MockEnvironment()); - KubernetesClientContextToSourceData greenData = new LabeledSecretContextToSourceDataProvider().get(); - SourceData greenSourceData = greenData.apply(greenContext); - - Assertions.assertEquals(greenSourceData.sourceData().size(), 1); - Assertions.assertEquals(greenSourceData.sourceData().get("color"), "green"); - Assertions.assertEquals(greenSourceData.sourceName(), "secret.green.default"); - - // meaning there is a single entry with such a log statement - String[] out = output.getAll().split("Loaded all secrets in namespace"); - Assertions.assertEquals(out.length, 2); - - // meaning that the second read was done from the cache - out = output.getAll().split("Loaded \\(from cache\\) all secrets in namespace"); - Assertions.assertEquals(out.length, 2); - } - - private void stubCall(V1SecretList list) { - stubFor(get("/api/v1/namespaces/default/secrets") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProviderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProviderTests.java deleted file mode 100644 index 81d065e688..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedConfigMapContextToSourceDataProviderTests.java +++ /dev/null @@ -1,447 +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.config; - -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.SourceData; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class NamedConfigMapContextToSourceDataProviderTests { - - private static final String NAMESPACE = "default"; - - private static final String RED_CONFIG_MAP_NAME = "red"; - - private static final String RED_WITH_PROFILE_CONFIG_MAP_NAME = RED_CONFIG_MAP_NAME + "-with-profile"; - - private static final String BLUE_CONFIG_MAP_NAME = "blue"; - - private static final Map COLOR_REALLY_RED = Map.of("color", "really-red"); - - private static final Map TASTE_MANGO = Map.of("taste", "mango"); - - @BeforeAll - static void setup() { - WireMockServer wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - new KubernetesClientConfigMapsCache().discardAll(); - } - - /** - *
-	 *     one configmap deployed with name "red"
-	 *     we search by name, but for the "blue" one, as such not find it
-	 * 
- */ - @Test - void noMatch() { - V1ConfigMap redConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(redConfigMap); - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedConfigMapNormalizedSource(BLUE_CONFIG_MAP_NAME, NAMESPACE, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.blue.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of()); - - } - - /** - *
-	 *     one configmap deployed with name "red"
-	 *     we search by name, for the "red" one, as such we find it
-	 * 
- */ - @Test - void match() { - - V1ConfigMap configMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(configMap); - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default"); - Assertions.assertEquals(sourceData.sourceData(), COLOR_REALLY_RED); - - } - - /** - *
-	 *     - two configmaps deployed : "red" and "red-with-profile".
-	 *     - "red" is matched directly, "red-with-profile" is matched because we have an active profile
-	 *       "active-profile"
-	 * 
- */ - @Test - void matchIncludeSingleProfile() { - - V1ConfigMap red = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - - V1ConfigMap redWithProfile = new V1ConfigMapBuilder().withMetadata( - new V1ObjectMetaBuilder().withName(RED_WITH_PROFILE_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(TASTE_MANGO).build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red).addItemsItem(redWithProfile); - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, true); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("with-profile"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("taste"), "mango"); - - } - - /** - *
-	 *     - two configmaps deployed : "red" and "red-with-profile".
-	 *     - "red" is matched directly, "red-with-profile" is matched because we have an active profile
-	 *       "active-profile"
-	 *     -  This takes into consideration the prefix, that we explicitly specify.
-	 *        Notice that prefix works for profile based config maps as well.
-	 * 
- */ - @Test - void matchIncludeSingleProfileWithPrefix() { - - V1ConfigMap red = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - - V1ConfigMap redWithTaste = new V1ConfigMapBuilder().withMetadata( - new V1ObjectMetaBuilder().withName(RED_WITH_PROFILE_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(TASTE_MANGO).build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red).addItemsItem(redWithTaste); - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("some", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, prefix, - true); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("with-profile"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("some.color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("some.taste"), "mango"); - - } - - /** - *
-	 *     - three configmaps deployed : "red", "red-with-taste" and "red-with-shape"
-	 *     - "red" is matched directly, the other two are matched because of active profiles
-	 *     -  This takes into consideration the prefix, that we explicitly specify.
-	 *        Notice that prefix works for profile based config maps as well.
-	 * 
- */ - @Test - void matchIncludeTwoProfilesWithPrefix() { - - V1ConfigMap red = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - - V1ConfigMap redWithTaste = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME + "-with-taste") - .withNamespace(NAMESPACE).withResourceVersion("1").build()) - .addToData(TASTE_MANGO).build(); - - V1ConfigMap redWithShape = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName(RED_CONFIG_MAP_NAME + "-with-shape").withNamespace(NAMESPACE).build()) - .addToData("shape", "round").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red).addItemsItem(redWithTaste) - .addItemsItem(redWithShape); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("some", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, prefix, - true); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("with-taste", "with-shape"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-shape.red-with-taste.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 3); - Assertions.assertEquals(sourceData.sourceData().get("some.color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("some.taste"), "mango"); - Assertions.assertEquals(sourceData.sourceData().get("some.shape"), "round"); - - } - - /** - *
-	 * 		proves that an implicit configmap is going to be generated and read, even if
-	 * 	    we did not provide one
-	 * 
- */ - @Test - void matchWithName() { - - V1ConfigMap red = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("application").withNamespace(NAMESPACE).build()) - .addToData("color", "red").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix("some", false, false, null); - NormalizedSource source = new NamedConfigMapNormalizedSource("application", NAMESPACE, true, prefix, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.application.default"); - Assertions.assertEquals(sourceData.sourceData(), Collections.singletonMap("some.color", "red")); - } - - /** - *
-	 *     - NamedSecretContextToSourceDataProvider gets as input a KubernetesClientConfigContext.
-	 *     - This context has a namespace as well as a NormalizedSource, that has a namespace too.
-	 *     - This test makes sure that we use the proper one.
-	 * 
- */ - @Test - void namespaceMatch() { - - V1ConfigMap configMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData(COLOR_REALLY_RED).build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(configMap); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - String wrongNamespace = NAMESPACE + "nope"; - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, wrongNamespace, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default"); - Assertions.assertEquals(sourceData.sourceData(), COLOR_REALLY_RED); - } - - /** - *
-	 *     - proves that single yaml file gets special treatment
-	 * 
- */ - @Test - void testSingleYaml() { - V1ConfigMap singleYaml = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName(RED_CONFIG_MAP_NAME).withNamespace(NAMESPACE).build()) - .addToData("single.yaml", "key: value").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(singleYaml); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedConfigMapNormalizedSource(RED_CONFIG_MAP_NAME, NAMESPACE, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("key", "value")); - } - - /** - *
-	 *     - one configmap is deployed with name "one"
-	 *     - profile is enabled with name "k8s"
-	 *
-	 *     we assert that the name of the source is "one" and does not contain "one-dev"
-	 * 
- */ - @Test - void testCorrectNameWithProfile() { - V1ConfigMap one = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("one").withNamespace(NAMESPACE).build()) - .addToData("key", "value").build(); - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(one); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("k8s"); - - NormalizedSource source = new NamedConfigMapNormalizedSource("one", NAMESPACE, true, true); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "configmap.one.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("key", "value")); - } - - /** - *
-	 *     - one configmap is deployed with name "red"
-	 *     - one configmap is deployed with name "green"
-	 *
-	 *     - we first search for "red" and find it, and it is retrieved from the cluster via the client.
-	 * 	   - we then search for the "green" one, and it is retrieved from the cache this time.
-	 * 
- */ - @Test - void cache(CapturedOutput output) { - V1ConfigMap red = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("red").withNamespace(NAMESPACE).build()) - .addToData("color", "red").build(); - - V1ConfigMap green = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green").withNamespace(NAMESPACE).build()) - .addToData("color", "green").build(); - - V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(red).addItemsItem(green); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - MockEnvironment environment = new MockEnvironment(); - - NormalizedSource redSource = new NamedConfigMapNormalizedSource("red", NAMESPACE, true, false); - KubernetesClientConfigContext redContext = new KubernetesClientConfigContext(api, redSource, NAMESPACE, - environment); - KubernetesClientContextToSourceData redData = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData redSourceData = redData.apply(redContext); - - Assertions.assertEquals(redSourceData.sourceName(), "configmap.red.default"); - Assertions.assertEquals(redSourceData.sourceData(), Map.of("color", "red")); - Assertions.assertTrue(output.getAll().contains("Loaded all config maps in namespace '" + NAMESPACE + "'")); - - NormalizedSource greenSource = new NamedConfigMapNormalizedSource("green", NAMESPACE, true, true); - KubernetesClientConfigContext greenContext = new KubernetesClientConfigContext(api, greenSource, NAMESPACE, - environment); - KubernetesClientContextToSourceData greenData = new NamedConfigMapContextToSourceDataProvider().get(); - SourceData greenSourceData = greenData.apply(greenContext); - - Assertions.assertEquals(greenSourceData.sourceName(), "configmap.green.default"); - Assertions.assertEquals(greenSourceData.sourceData(), Map.of("color", "green")); - - // meaning there is a single entry with such a log statement - String[] out = output.getAll().split("Loaded all config maps in namespace"); - Assertions.assertEquals(out.length, 2); - - // meaning that the second read was done from the cache - out = output.getAll().split("Loaded \\(from cache\\) all config maps in namespace"); - Assertions.assertEquals(out.length, 2); - - } - - private void stubCall(V1ConfigMapList list) { - stubFor(get("/api/v1/namespaces/default/configmaps") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProviderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProviderTests.java deleted file mode 100644 index 9cb158b684..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/NamedSecretContextToSourceDataProviderTests.java +++ /dev/null @@ -1,401 +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.config; - -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.openapi.models.V1SecretListBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; -import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.SourceData; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -@ExtendWith(OutputCaptureExtension.class) -class NamedSecretContextToSourceDataProviderTests { - - private static final ConfigUtils.Prefix PREFIX = ConfigUtils.findPrefix("some", false, false, "irrelevant"); - - private static final String NAMESPACE = "default"; - - private static final Map COLOR_REALLY_RED = Map.of("color", "really-red".getBytes()); - - @BeforeAll - static void setup() { - WireMockServer wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - new KubernetesClientSecretsCache().discardAll(); - } - - /** - * we have a single secret deployed. it matched the name in our queries - */ - @Test - void singleSecretMatchAgainstLabels() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(red); - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - // blue does not match red - NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red")); - - } - - /** - * we have three secrets deployed. one of them has a name that matches (red), the - * other two have different names, thus no match. - */ - @Test - void twoSecretMatchAgainstLabels() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1Secret blue = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("blue").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1Secret pink = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("pink").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1SecretList secretList = new V1SecretListBuilder().addToItems(red).addToItems(blue).addToItems(pink).build(); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - // blue does not match red, nor pink - NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 1); - Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red"); - - } - - /** - * one secret deployed (pink), does not match our query (blue). - */ - @Test - void testSecretNoMatch() { - - V1Secret secret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(secret); - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - // blue does not match red - NormalizedSource source = new NamedSecretNormalizedSource("blue", NAMESPACE, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.blue.default"); - Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap()); - } - - /** - *
-	 *     - LabeledSecretContextToSourceDataProvider gets as input a KubernetesClientConfigContext.
-	 *     - This context has a namespace as well as a NormalizedSource, that has a namespace too.
-	 *     - This test makes sure that we use the proper one.
-	 * 
- */ - @Test - void namespaceMatch() { - - V1Secret secret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(secret); - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - String wrongNamespace = NAMESPACE + "nope"; - NormalizedSource source = new NamedSecretNormalizedSource("red", wrongNamespace, false, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red")); - } - - /** - * we have two secrets deployed. one matches the query name. the other matches the - * active profile + name, thus is taken also. - */ - @Test - void matchIncludeSingleProfile() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1Secret mango = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red-with-profile").build()) - .addToData("taste", "mango".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(red).addItemsItem(mango); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, true); - MockEnvironment environment = new MockEnvironment(); - environment.addActiveProfile("with-profile"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.red-with-profile.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("taste"), "mango"); - - } - - /** - * we have two secrets deployed. one matches the query name. the other matches the - * active profile + name, thus is taken also. This takes into consideration the - * prefix, that we explicitly specify. Notice that prefix works for profile based - * secrets as well. - */ - @Test - void matchIncludeSingleProfileWithPrefix() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1Secret mango = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red-with-taste").build()) - .addToData("taste", "mango".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(red).addItemsItem(mango); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, true, PREFIX, true); - MockEnvironment environment = new MockEnvironment(); - environment.addActiveProfile("with-taste"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.red-with-taste.default"); - Assertions.assertEquals(sourceData.sourceData().size(), 2); - Assertions.assertEquals(sourceData.sourceData().get("some.color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("some.taste"), "mango"); - - } - - /** - * we have three secrets deployed. one matches the query name. the other two match the - * active profile + name, thus are taken also. This takes into consideration the - * prefix, that we explicitly specify. Notice that prefix works for profile based - * config maps as well. - */ - @Test - void matchIncludeTwoProfilesWithPrefix() { - - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red").build()) - .addToData(COLOR_REALLY_RED).build(); - - V1Secret mango = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red-with-taste").build()) - .addToData("taste", "mango".getBytes()).build(); - - V1Secret shape = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withNamespace(NAMESPACE).withName("red-with-shape").build()) - .addToData("shape", "round".getBytes()).build(); - - V1SecretList secretList = new V1SecretList().addItemsItem(red).addItemsItem(mango).addItemsItem(shape); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, true, PREFIX, true); - MockEnvironment environment = new MockEnvironment(); - environment.setActiveProfiles("with-taste", "with-shape"); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.red.red-with-shape.red-with-taste.default"); - - Assertions.assertEquals(sourceData.sourceData().size(), 3); - Assertions.assertEquals(sourceData.sourceData().get("some.color"), "really-red"); - Assertions.assertEquals(sourceData.sourceData().get("some.taste"), "mango"); - Assertions.assertEquals(sourceData.sourceData().get("some.shape"), "round"); - - } - - /** - *
-	 *     - proves that single yaml file gets special treatment
-	 * 
- */ - @Test - void testSingleYaml() { - V1Secret singleYaml = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("single-yaml").withNamespace(NAMESPACE).build()) - .addToData("single.yaml", "key: value".getBytes()).build(); - V1SecretList secretList = new V1SecretList().addItemsItem(singleYaml); - - stubCall(secretList); - CoreV1Api api = new CoreV1Api(); - - NormalizedSource source = new NamedSecretNormalizedSource("single-yaml", NAMESPACE, true, false); - KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, - new MockEnvironment()); - - KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get(); - SourceData sourceData = data.apply(context); - - Assertions.assertEquals(sourceData.sourceName(), "secret.single-yaml.default"); - Assertions.assertEquals(sourceData.sourceData(), Map.of("key", "value")); - } - - /** - *
-	 *     - one secret is deployed with name "red"
-	 *     - one secret is deployed with name "green"
-	 *
-	 *     - we first search for "red" and find it, and it is retrieved from the cluster via the client.
-	 * 	   - we then search for the "green" one, and it is retrieved from the cache this time.
-	 * 
- */ - @Test - void cache(CapturedOutput output) { - V1Secret red = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("red").withNamespace(NAMESPACE).build()) - .addToData("color", "red".getBytes()).build(); - - V1Secret green = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green").withNamespace(NAMESPACE).build()) - .addToData("color", "green".getBytes()).build(); - - V1SecretList configMapList = new V1SecretList().addItemsItem(red).addItemsItem(green); - - stubCall(configMapList); - CoreV1Api api = new CoreV1Api(); - - MockEnvironment environment = new MockEnvironment(); - - NormalizedSource redSource = new NamedSecretNormalizedSource("red", NAMESPACE, true, false); - KubernetesClientConfigContext redContext = new KubernetesClientConfigContext(api, redSource, NAMESPACE, - environment); - KubernetesClientContextToSourceData redData = new NamedSecretContextToSourceDataProvider().get(); - SourceData redSourceData = redData.apply(redContext); - - Assertions.assertEquals(redSourceData.sourceName(), "secret.red.default"); - Assertions.assertEquals(redSourceData.sourceData(), Map.of("color", "red")); - Assertions.assertTrue(output.getAll().contains("Loaded all secrets in namespace '" + NAMESPACE + "'")); - - NormalizedSource greenSource = new NamedSecretNormalizedSource("green", NAMESPACE, true, true); - KubernetesClientConfigContext greenContext = new KubernetesClientConfigContext(api, greenSource, NAMESPACE, - environment); - KubernetesClientContextToSourceData greenData = new NamedSecretContextToSourceDataProvider().get(); - SourceData greenSourceData = greenData.apply(greenContext); - - Assertions.assertEquals(greenSourceData.sourceName(), "secret.green.default"); - Assertions.assertEquals(greenSourceData.sourceData(), Map.of("color", "green")); - - // meaning there is a single entry with such a log statement - String[] out = output.getAll().split("Loaded all secrets in namespace"); - Assertions.assertEquals(out.length, 2); - - // meaning that the second read was done from the cache - out = output.getAll().split("Loaded \\(from cache\\) all secrets in namespace"); - Assertions.assertEquals(out.length, 2); - - } - - private void stubCall(V1SecretList list) { - stubFor(get("/api/v1/namespaces/default/secrets") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixApp.java deleted file mode 100644 index d80949f597..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixApp.java +++ /dev/null @@ -1,35 +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.config.applications.labeled_config_map_with_prefix; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Four; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Two; - -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class, Four.class }) -public class LabeledConfigMapWithPrefixApp { - - public static void main(String[] args) { - SpringApplication.run(LabeledConfigMapWithPrefixApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixBootstrapTests.java deleted file mode 100644 index c6778d647b..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixBootstrapTests.java +++ /dev/null @@ -1,31 +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.config.applications.labeled_config_map_with_prefix; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = LabeledConfigMapWithPrefixApp.class, - properties = { "spring.cloud.bootstrap.name=labeled-configmap-with-prefix", - "labeled.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }) -class LabeledConfigMapWithPrefixBootstrapTests extends LabeledConfigMapWithPrefixTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixConfigDataTests.java deleted file mode 100644 index c4e0fe404b..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixConfigDataTests.java +++ /dev/null @@ -1,65 +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.config.applications.labeled_config_map_with_prefix; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub.stubData; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = LabeledConfigMapWithPrefixApp.class, - properties = { "spring.cloud.application.name=labeled-configmap-with-prefix", - "labeled.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./labeled-configmap-with-prefix.yaml" }) -class LabeledConfigMapWithPrefixConfigDataTests extends LabeledConfigMapWithPrefixTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixTests.java deleted file mode 100644 index 647e3cb6c3..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/LabeledConfigMapWithPrefixTests.java +++ /dev/null @@ -1,113 +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.config.applications.labeled_config_map_with_prefix; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * Stud data is in - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub} - * - * @author wind57 - */ -abstract class LabeledConfigMapWithPrefixTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.configmap.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.configmap.sources[0].useNameAsPrefix=false'
-	 * 	 ("one.property", "one")
-	 *
-	 * 	 As such: @ConfigurationProperties("one")
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/labeled-configmap/prefix/one").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("one")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[1].explicitPrefix=two'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two")
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/labeled-configmap/prefix/two").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[2].labels=letter:c'
-	 * 	 ("property", "three")
-	 *
-	 *   We find the configmap by labels, and use it's name as the prefix.
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "configmap-three")
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/labeled-configmap/prefix/three").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("three")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[3].labels=letter:d'
-	 * 	 ("property", "four")
-	 *
-	 *   We find the configmap by labels, and use it's name as the prefix.
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "configmap-four")
-	 * 
- */ - @Test - void testFour() { - this.webClient.get().uri("/labeled-configmap/prefix/four").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("four")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/controller/LabeledConfigMapWithPrefixController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/controller/LabeledConfigMapWithPrefixController.java deleted file mode 100644 index 5e16b04b38..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/controller/LabeledConfigMapWithPrefixController.java +++ /dev/null @@ -1,64 +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.config.applications.labeled_config_map_with_prefix.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Four; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_prefix.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class LabeledConfigMapWithPrefixController { - - private final One one; - - private final Two two; - - private final Three three; - - private final Four four; - - public LabeledConfigMapWithPrefixController(One one, Two two, Three three, Four four) { - this.one = one; - this.two = two; - this.three = three; - this.four = four; - } - - @GetMapping("/labeled-configmap/prefix/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/labeled-configmap/prefix/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/labeled-configmap/prefix/three") - public String three() { - return three.getProperty(); - } - - @GetMapping("/labeled-configmap/prefix/four") - public String four() { - return four.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Four.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Four.java deleted file mode 100644 index 9e87586053..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Four.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "configmap-four") -public class Four { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/One.java deleted file mode 100644 index 23bbec8696..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Three.java deleted file mode 100644 index 03ab598e73..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "configmap-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Two.java deleted file mode 100644 index 3f0c26823e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_prefix/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileApp.java deleted file mode 100644 index 6135608b5d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileApp.java +++ /dev/null @@ -1,36 +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.config.applications.labeled_config_map_with_profile; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_profile.properties.Blue; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_profile.properties.Green; - -/** - * @author wind57 - */ -@SpringBootApplication -@EnableConfigurationProperties({ Blue.class, Green.class }) -public class LabeledConfigMapWithProfileApp { - - public static void main(String[] args) { - SpringApplication.run(LabeledConfigMapWithProfileApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileBootstrapTests.java deleted file mode 100644 index 770f618d15..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileBootstrapTests.java +++ /dev/null @@ -1,33 +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.config.applications.labeled_config_map_with_profile; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -/** - * @author wind57 - */ -@ActiveProfiles({ "k8s", "prod" }) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = LabeledConfigMapWithProfileApp.class, - properties = { "spring.cloud.bootstrap.name=labeled-configmap-with-profile", - "labeled.config.map.with.profile.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true", "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class LabeledConfigMapWithProfileBootstrapTests extends LabeledConfigMapWithProfileTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileConfigDataTests.java deleted file mode 100644 index 4e3991b126..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileConfigDataTests.java +++ /dev/null @@ -1,67 +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.config.applications.labeled_config_map_with_profile; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub.stubData; - -/** - * @author wind57 - */ -@ActiveProfiles({ "k8s", "prod" }) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = LabeledConfigMapWithProfileApp.class, - properties = { "spring.cloud.application.name=labeled-configmap-with-profile", - "labeled.config.map.with.profile.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./labeled-configmap-with-profile.yaml" }) -class LabeledConfigMapWithProfileConfigDataTests extends LabeledConfigMapWithProfileTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileTests.java deleted file mode 100644 index 4a206dab65..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/LabeledConfigMapWithProfileTests.java +++ /dev/null @@ -1,76 +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.config.applications.labeled_config_map_with_profile; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * Stud data is in - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub} - * - * @author wind57 - */ -abstract class LabeledConfigMapWithProfileTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *     this one is taken from : "blue.one". We find "color-configmap" by labels, and
-	 *     "color-configmap-k8s" exists, but "includeProfileSpecificSources=false", thus not taken.
-	 *     Since "explicitPrefix=blue", we take "blue.one"
-	 * 
- */ - @Test - void testBlue() { - this.webClient.get().uri("/labeled-configmap/profile/blue").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("1")); - } - - /** - *
-	 *   this one is taken from : ""green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s"".
-	 *   We find "green-configmap" by labels, also "green-configmap-k8s", "green-configmap-prod" exists,
-	 *   because "includeProfileSpecificSources=true" is set. Also "green-purple-configmap" and "green-purple-configmap-k8s"
-	 *   are found.
-	 * 
- */ - @Test - void testGreen() { - this.webClient.get().uri("/labeled-configmap/profile/green").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/controller/LabeledConfigMapWithProfileController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/controller/LabeledConfigMapWithProfileController.java deleted file mode 100644 index e81f6678b4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/controller/LabeledConfigMapWithProfileController.java +++ /dev/null @@ -1,46 +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.config.applications.labeled_config_map_with_profile.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_profile.properties.Blue; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_config_map_with_profile.properties.Green; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class LabeledConfigMapWithProfileController { - - private final Blue blue; - - private final Green green; - - public LabeledConfigMapWithProfileController(Blue blue, Green green) { - this.blue = blue; - this.green = green; - } - - @GetMapping("/labeled-configmap/profile/blue") - public String blue() { - return blue.getOne(); - } - - @GetMapping("/labeled-configmap/profile/green") - public String green() { - return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Blue.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Blue.java deleted file mode 100644 index e1cad9515e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Blue.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_config_map_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("blue") -public class Blue { - - private String one; - - public String getOne() { - return one; - } - - public void setOne(String one) { - this.one = one; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Green.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Green.java deleted file mode 100644 index 7e8807f411..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_config_map_with_profile/properties/Green.java +++ /dev/null @@ -1,64 +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.config.applications.labeled_config_map_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s") -public class Green { - - private String two; - - private String six; - - private String seven; - - private String eight; - - public String getTwo() { - return two; - } - - public void setTwo(String two) { - this.two = two; - } - - public String getSix() { - return six; - } - - public void setSix(String six) { - this.six = six; - } - - public String getSeven() { - return seven; - } - - public void setSeven(String seven) { - this.seven = seven; - } - - public String getEight() { - return eight; - } - - public void setEight(String eight) { - this.eight = eight; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixApp.java deleted file mode 100644 index 28484bcc14..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixApp.java +++ /dev/null @@ -1,35 +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.config.applications.labeled_secret_with_prefix; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Four; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Two; - -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class, Four.class }) -public class LabeledSecretWithPrefixApp { - - public static void main(String[] args) { - SpringApplication.run(LabeledSecretWithPrefixApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixBootstrapTests.java deleted file mode 100644 index 0987907d92..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixBootstrapTests.java +++ /dev/null @@ -1,30 +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.config.applications.labeled_secret_with_prefix; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = LabeledSecretWithPrefixApp.class, - properties = { "spring.cloud.bootstrap.name=labeled-secret-with-prefix", "labeled.secret.with.prefix.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true", - "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class LabeledSecretWithPrefixBootstrapTests extends LabeledSecretWithPrefixTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixConfigDataTests.java deleted file mode 100644 index 42cbe38aa6..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixConfigDataTests.java +++ /dev/null @@ -1,64 +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.config.applications.labeled_secret_with_prefix; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub.stubData; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = LabeledSecretWithPrefixApp.class, - properties = { "spring.cloud.application.name=labeled-secret-with-prefix", - "labeled.secret.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./labeled-secret-with-prefix.yaml" }) -class LabeledSecretWithPrefixConfigDataTests extends LabeledSecretWithPrefixTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixTests.java deleted file mode 100644 index 6300f24f2d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/LabeledSecretWithPrefixTests.java +++ /dev/null @@ -1,113 +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.config.applications.labeled_secret_with_prefix; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : {@link LabeledSecretWithPrefixConfigurationStub} - * - * @author wind57 - */ -abstract class LabeledSecretWithPrefixTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[0].useNameAsPrefix=false'
-	 * 	 ("one.property", "one")
-	 *
-	 * 	 As such: @ConfigurationProperties("one")
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/labeled-secret/prefix/one").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("one")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[1].explicitPrefix=two'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two")
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/labeled-secret/prefix/two").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[2].labels=letter:c'
-	 * 	 ("property", "three")
-	 *
-	 *   We find the secret by labels, and use it's name as the prefix.
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "secret-three")
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/labeled-secret/prefix/three").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("three")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[3].labels=letter:d'
-	 * 	 ("property", "four")
-	 *
-	 *   We find the secret by labels, and use it's name as the prefix.
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "secret-four")
-	 * 
- */ - @Test - void testFour() { - this.webClient.get().uri("/labeled-secret/prefix/four").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("four")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/controller/LabeledSecretWithPrefixController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/controller/LabeledSecretWithPrefixController.java deleted file mode 100644 index b6c6066bfb..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/controller/LabeledSecretWithPrefixController.java +++ /dev/null @@ -1,64 +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.config.applications.labeled_secret_with_prefix.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Four; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_prefix.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class LabeledSecretWithPrefixController { - - private final One one; - - private final Two two; - - private final Three three; - - private final Four four; - - public LabeledSecretWithPrefixController(One one, Two two, Three three, Four four) { - this.one = one; - this.two = two; - this.three = three; - this.four = four; - } - - @GetMapping("/labeled-secret/prefix/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/labeled-secret/prefix/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/labeled-secret/prefix/three") - public String three() { - return three.getProperty(); - } - - @GetMapping("/labeled-secret/prefix/four") - public String four() { - return four.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Four.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Four.java deleted file mode 100644 index aefd225d21..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Four.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "secret-four") -public class Four { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/One.java deleted file mode 100644 index 6ad8b4346d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Three.java deleted file mode 100644 index ca661c7c77..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "secret-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Two.java deleted file mode 100644 index 265b17e5be..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_prefix/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileApp.java deleted file mode 100644 index eae8cd695a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileApp.java +++ /dev/null @@ -1,33 +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.config.applications.labeled_secret_with_profile; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_profile.properties.Blue; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_profile.properties.Green; - -@SpringBootApplication -@EnableConfigurationProperties({ Blue.class, Green.class }) -public class LabeledSecretWithProfileApp { - - public static void main(String[] args) { - SpringApplication.run(LabeledSecretWithProfileApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileBootstrapTests.java deleted file mode 100644 index 76ac55925a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileBootstrapTests.java +++ /dev/null @@ -1,32 +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.config.applications.labeled_secret_with_profile; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -/** - * @author wind57 - */ -@ActiveProfiles({ "k8s", "prod" }) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = LabeledSecretWithProfileApp.class, - properties = { "spring.cloud.bootstrap.name=labeled-secret-with-profile", - "labeled.secret.with.profile.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true", "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class LabeledSecretWithProfileBootstrapTests extends LabeledSecretWithProfileTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileConfigDataTests.java deleted file mode 100644 index 14cff5d216..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileConfigDataTests.java +++ /dev/null @@ -1,66 +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.config.applications.labeled_secret_with_profile; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub.stubData; - -/** - * @author wind57 - */ -@ActiveProfiles({ "k8s", "prod" }) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = LabeledSecretWithProfileApp.class, - properties = { "spring.application.name=labeled-secret-with-profile", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./labeled-secret-with-profile.yaml", - "spring.cloud.kubernetes.config.enabled=false" }) -class LabeledSecretWithProfileConfigDataTests extends LabeledSecretWithProfileTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileTests.java deleted file mode 100644 index fbcb546a78..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/LabeledSecretWithProfileTests.java +++ /dev/null @@ -1,88 +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.config.applications.labeled_secret_with_profile; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/* - *
- *   - secret with name "color-secret", with labels: "{color: blue}" and "explicitPrefix: blue"
- *   - secret with name "green-secret", with labels: "{color: green}" and "explicitPrefix: blue-again"
- *   - secret with name "red-secret", with labels "{color: not-red}" and "useNameAsPrefix: true"
- *   - secret with name "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true
- *   - secret with name "color-secret-k8s", with labels : "{color: not-blue}"
- *   - secret with name "green-secret-k8s", with labels : "{color: green-k8s}"
- *   - secret with name "green-secret-prod", with labels : "{color: green-prod}"
- * 
- */ - -/** - * Stubs for this test are in - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub} - * - * @author wind57 - */ -abstract class LabeledSecretWithProfileTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *     this one is taken from : "blue.one". We find "color-secret" by labels, and
-	 *     "color-secrets-k8s" exists, but "includeProfileSpecificSources=false", thus not taken.
-	 *     Since "explicitPrefix=blue", we take "blue.one"
-	 * 
- */ - @Test - void testBlue() { - this.webClient.get().uri("/labeled-secret/profile/blue").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("1")); - } - - /** - *
-	 *   this one is taken from : "green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod".
-	 *   We find "green-secret" by labels, also "green-secrets-k8s" and "green-secrets-prod" exists,
-	 *   because "includeProfileSpecificSources=true" is set. Also "green-purple-secret" and "green-purple-secret-k8s"
-	 * 	 are found.
-	 * 
- */ - @Test - void testGreen() { - this.webClient.get().uri("/labeled-secret/profile/green").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/controller/LabeledSecretWithProfileController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/controller/LabeledSecretWithProfileController.java deleted file mode 100644 index 97f6a06ebc..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/controller/LabeledSecretWithProfileController.java +++ /dev/null @@ -1,46 +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.config.applications.labeled_secret_with_profile.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_profile.properties.Blue; -import org.springframework.cloud.kubernetes.client.config.applications.labeled_secret_with_profile.properties.Green; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class LabeledSecretWithProfileController { - - private final Blue blue; - - private final Green green; - - public LabeledSecretWithProfileController(Blue blue, Green green) { - this.blue = blue; - this.green = green; - } - - @GetMapping("/labeled-secret/profile/blue") - public String blue() { - return blue.getOne(); - } - - @GetMapping("/labeled-secret/profile/green") - public String green() { - return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Blue.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Blue.java deleted file mode 100644 index 7231da17ac..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Blue.java +++ /dev/null @@ -1,34 +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.config.applications.labeled_secret_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("blue") -public class Blue { - - private String one; - - public String getOne() { - return one; - } - - public void setOne(String one) { - this.one = one; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Green.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Green.java deleted file mode 100644 index 851f229ed4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/labeled_secret_with_profile/properties/Green.java +++ /dev/null @@ -1,64 +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.config.applications.labeled_secret_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod") -public class Green { - - private String two; - - private String six; - - private String seven; - - private String eight; - - public String getTwo() { - return two; - } - - public void setTwo(String two) { - this.two = two; - } - - public String getSix() { - return six; - } - - public void setSix(String six) { - this.six = six; - } - - public String getSeven() { - return seven; - } - - public void setSeven(String seven) { - this.seven = seven; - } - - public String getEight() { - return eight; - } - - public void setEight(String eight) { - this.eight = eight; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixApp.java deleted file mode 100644 index d6457a5bc8..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixApp.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_prefix; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Two; - -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class }) -public class NamedConfigMapWithPrefixApp { - - public static void main(String[] args) { - SpringApplication.run(NamedConfigMapWithPrefixApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixBootstrapTests.java deleted file mode 100644 index a7600c8e39..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixBootstrapTests.java +++ /dev/null @@ -1,30 +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.config.applications.named_config_map_with_prefix; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class, - properties = { "spring.cloud.bootstrap.name=named-configmap-with-prefix", - "named.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true", "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class NamedConfigMapWithPrefixBootstrapTests extends NamedConfigMapWithPrefixTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixConfigDataTests.java deleted file mode 100644 index 4bd5cdbd85..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixConfigDataTests.java +++ /dev/null @@ -1,64 +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.config.applications.named_config_map_with_prefix; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub.stubData; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class, - properties = { "spring.cloud.application.name=named-configmap-with-prefix", - "named.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./named-configmap-with-prefix.yaml" }) -class NamedConfigMapWithPrefixConfigDataTests extends NamedConfigMapWithPrefixTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixTests.java deleted file mode 100644 index 881b628416..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/NamedConfigMapWithPrefixTests.java +++ /dev/null @@ -1,94 +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.config.applications.named_config_map_with_prefix; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub} - * - * @author wind57 - */ -abstract class NamedConfigMapWithPrefixTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[0].useNameAsPrefix=false'
-	 * 	 ("one.property", "one")
-	 *
-	 * 	 As such: @ConfigurationProperties("one")
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/named-configmap/prefix/one").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("one")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[1].explicitPrefix=two'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two")
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/named-configmap/prefix/two").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[2].name=config-map-three'
-	 * 	 ("property", "three")
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "config-map-three")
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/named-configmap/prefix/three").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("three")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/controller/NamedConfigWithPrefixController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/controller/NamedConfigWithPrefixController.java deleted file mode 100644 index 6702619367..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/controller/NamedConfigWithPrefixController.java +++ /dev/null @@ -1,55 +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.config.applications.named_config_map_with_prefix.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class NamedConfigWithPrefixController { - - private final One one; - - private final Two two; - - private final Three three; - - public NamedConfigWithPrefixController(One one, Two two, Three three) { - this.one = one; - this.two = two; - this.three = three; - } - - @GetMapping("/named-configmap/prefix/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/named-configmap/prefix/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/named-configmap/prefix/three") - public String three() { - return three.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/One.java deleted file mode 100644 index 82c2a7f42c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Three.java deleted file mode 100644 index 30c592243c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "config-map-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Two.java deleted file mode 100644 index 0f45b685c2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_prefix/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileApp.java deleted file mode 100644 index 81db4b8077..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileApp.java +++ /dev/null @@ -1,40 +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.config.applications.named_config_map_with_profile; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.Two; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub} - * - * @author wind57 - */ -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class }) -class NamedConfigMapWithProfileApp { - - public static void main(String[] args) { - SpringApplication.run(NamedConfigMapWithProfileApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileBootstrapTests.java deleted file mode 100644 index 9e569f5c70..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileBootstrapTests.java +++ /dev/null @@ -1,30 +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.config.applications.named_config_map_with_profile; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = NamedConfigMapWithProfileApp.class, - properties = { "spring.cloud.bootstrap.name=named-configmap-with-profile", - "named.config.map.with.profile.stub=true", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true", "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -@ActiveProfiles("k8s") -class NamedConfigMapWithProfileBootstrapTests extends NamedConfigMapWithProfileTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileConfigDataTests.java deleted file mode 100644 index d3c660d3d0..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileConfigDataTests.java +++ /dev/null @@ -1,67 +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.config.applications.named_config_map_with_profile; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub.stubData; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = NamedConfigMapWithProfileApp.class, - properties = { "spring.application.name=named-config-map-with-profile", "include.profile.specific.sources=true", - "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./named-configmap-with-profile.yaml" }) -@ActiveProfiles("k8s") -class NamedConfigMapWithProfileConfigDataTests extends NamedConfigMapWithProfileTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - public static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileTests.java deleted file mode 100644 index a997b4e037..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/NamedConfigMapWithProfileTests.java +++ /dev/null @@ -1,101 +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.config.applications.named_config_map_with_profile; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub} - * - * @author wind57 - */ -abstract class NamedConfigMapWithProfileTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[0].useNameAsPrefix=false'
-	 *   'spring.cloud.kubernetes.config.sources[0].includeProfileSpecificSources=true'
-	 * 	 ("one.property", "one-from-k8s")
-	 *
-	 * 	 As such: @ConfigurationProperties("one"), value is overridden by the one that we read from
-	 * 	 the profile based source.
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/named-configmap/profile/one").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("one-from-k8s")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[1].explicitPrefix=two'
-	 *   'spring.cloud.kubernetes.config.sources[1].includeProfileSpecificSources=false'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two").
-	 *
-	 * 	 Even if there is a profile based source, we disabled reading it.
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/named-configmap/profile/two").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.config.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.config.sources[2].name=configmap-three'
-	 *   'spring.cloud.kubernetes.config.sources[1].includeProfileSpecificSources=true'
-	 * 	 ("property", "three")
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "config-three"), value is overridden by the one that we read from
-	 * 	 the profile based source
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/named-configmap/profile/three").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("three-from-k8s")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/controller/NamedConfigMapWithProfileController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/controller/NamedConfigMapWithProfileController.java deleted file mode 100644 index 3a1bd2b1d2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/controller/NamedConfigMapWithProfileController.java +++ /dev/null @@ -1,55 +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.config.applications.named_config_map_with_profile.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_profile.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class NamedConfigMapWithProfileController { - - private final One one; - - private final Two two; - - private final Three three; - - public NamedConfigMapWithProfileController(One one, Two two, Three three) { - this.one = one; - this.two = two; - this.three = three; - } - - @GetMapping("/named-configmap/profile/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/named-configmap/profile/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/named-configmap/profile/three") - public String three() { - return three.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/One.java deleted file mode 100644 index ac8e271586..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Three.java deleted file mode 100644 index 77d6656dc8..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("configmap-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Two.java deleted file mode 100644 index 3d5bbb80d0..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_config_map_with_profile/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.named_config_map_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixApp.java deleted file mode 100644 index 036776a6ac..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixApp.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_prefix; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Two; - -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class }) -public class NamedSecretWithPrefixApp { - - public static void main(String[] args) { - SpringApplication.run(NamedSecretWithPrefixApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixBootstrapTests.java deleted file mode 100644 index 9c11d631b2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixBootstrapTests.java +++ /dev/null @@ -1,30 +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.config.applications.named_secret_with_prefix; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class, - properties = { "spring.cloud.bootstrap.name=named-secret-with-prefix", "named.secret.with.prefix.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true", - "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class NamedSecretWithPrefixBootstrapTests extends NamedSecretWithPrefixTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixConfigDataTests.java deleted file mode 100644 index bacf92cb44..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixConfigDataTests.java +++ /dev/null @@ -1,65 +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.config.applications.named_secret_with_prefix; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub.stubData; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class, - properties = { "spring.cloud.application.name=named-secret-with-prefix", "named.secret.with.prefix.stub=true", - "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./named-secret-with-prefix.yaml", - "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class NamedSecretWithPrefixConfigDataTests extends NamedSecretWithPrefixTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixTests.java deleted file mode 100644 index 58a6545d2a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/NamedSecretWithPrefixTests.java +++ /dev/null @@ -1,94 +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.config.applications.named_secret_with_prefix; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub} - * - * @author wind57 - */ -abstract class NamedSecretWithPrefixTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[0].useNameAsPrefix=false'
-	 * 	 ("one.property", "one")
-	 *
-	 * 	 As such: @ConfigurationProperties("one")
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/named-secret/prefix/one").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("one")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[1].explicitPrefix=two'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two")
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/named-secret/prefix/two").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[2].name=config-map-three'
-	 * 	 ("property", "three")
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "config-map-three")
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/named-secret/prefix/three").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("three")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/controller/NamedSecretWithPrefixController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/controller/NamedSecretWithPrefixController.java deleted file mode 100644 index facc299a6e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/controller/NamedSecretWithPrefixController.java +++ /dev/null @@ -1,55 +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.config.applications.named_secret_with_prefix.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class NamedSecretWithPrefixController { - - private final One one; - - private final Two two; - - private final Three three; - - public NamedSecretWithPrefixController(One one, Two two, Three three) { - this.one = one; - this.two = two; - this.three = three; - } - - @GetMapping("/named-secret/prefix/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/named-secret/prefix/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/named-secret/prefix/three") - public String three() { - return three.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/One.java deleted file mode 100644 index 80127c1bc7..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Three.java deleted file mode 100644 index 658e23d903..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "secret-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Two.java deleted file mode 100644 index a28aca72c4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_prefix/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_prefix.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithLabelApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithLabelApp.java deleted file mode 100644 index 64c7643cae..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithLabelApp.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_profile; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.Two; - -@SpringBootApplication -@EnableConfigurationProperties({ One.class, Two.class, Three.class }) -public class NamedSecretWithLabelApp { - - public static void main(String[] args) { - SpringApplication.run(NamedSecretWithLabelApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileBootstrapTests.java deleted file mode 100644 index 50cbd8837c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileBootstrapTests.java +++ /dev/null @@ -1,31 +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.config.applications.named_secret_with_profile; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -/** - * @author wind57 - */ -@ActiveProfiles("k8s") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithLabelApp.class, - properties = { "spring.cloud.bootstrap.name=named-secret-with-profile", "named.secret.with.profile.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }) -class NamedSecretWithProfileBootstrapTests extends NamedSecretWithProfileTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileConfigDataTests.java deleted file mode 100644 index 327af36374..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileConfigDataTests.java +++ /dev/null @@ -1,67 +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.config.applications.named_secret_with_profile; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub.stubData; - -/** - * @author wind57 - */ -@ActiveProfiles("k8s") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithLabelApp.class, - properties = { "spring.cloud.application.name=named-secret-with-profile", "named.secret.with.profile.stub=true", - "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./named-secret-with-profile.yaml", - "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class NamedSecretWithProfileConfigDataTests extends NamedSecretWithProfileTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileTests.java deleted file mode 100644 index 20093f5dc5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/NamedSecretWithProfileTests.java +++ /dev/null @@ -1,101 +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.config.applications.named_secret_with_profile; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub} - * - * @author wind57 - */ -abstract class NamedSecretWithProfileTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[0].useNameAsPrefix=false'
-	 *   'spring.cloud.kubernetes.secrets.sources[0].includeProfileSpecificSources=true'
-	 * 	 ("one.property", "one-from-k8s")
-	 *
-	 * 	 As such: @ConfigurationProperties("one"), value is overridden by the one that we read from
-	 * 	 the profile based source.
-	 * 
- */ - @Test - void testOne() { - this.webClient.get().uri("/named-secret/profile/one").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("one-from-k8s")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[1].explicitPrefix=two'
-	 *   'spring.cloud.kubernetes.secrets.sources[1].includeProfileSpecificSources=false'
-	 * 	 ("property", "two")
-	 *
-	 * 	 As such: @ConfigurationProperties("two").
-	 *
-	 * 	 Even if there is a profile based source, we disabled reading it.
-	 * 
- */ - @Test - void testTwo() { - this.webClient.get().uri("/named-secret/profile/two").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("two")); - } - - /** - *
-	 *   'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
-	 *   'spring.cloud.kubernetes.secrets.sources[2].name=secret-three'
-	 *   'spring.cloud.kubernetes.secrets.sources[1].includeProfileSpecificSources=true'
-	 * 	 ("property", "three")
-	 *
-	 * 	 As such: @ConfigurationProperties(prefix = "secret-three"), value is overridden by the one that we read from
-	 * 	 * 	 the profile based source
-	 * 
- */ - @Test - void testThree() { - this.webClient.get().uri("/named-secret/profile/three").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("three-from-k8s")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/controller/NamedSecretWithProfileController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/controller/NamedSecretWithProfileController.java deleted file mode 100644 index 93758cc0bf..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/controller/NamedSecretWithProfileController.java +++ /dev/null @@ -1,55 +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.config.applications.named_secret_with_profile.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.One; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.Three; -import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_profile.properties.Two; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class NamedSecretWithProfileController { - - private final One one; - - private final Two two; - - private final Three three; - - public NamedSecretWithProfileController(One one, Two two, Three three) { - this.one = one; - this.two = two; - this.three = three; - } - - @GetMapping("/named-secret/profile/one") - public String one() { - return one.getProperty(); - } - - @GetMapping("/named-secret/profile/two") - public String two() { - return two.getProperty(); - } - - @GetMapping("/named-secret/profile/three") - public String three() { - return three.getProperty(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/One.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/One.java deleted file mode 100644 index f2d558ef98..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/One.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("one") -public class One { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Three.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Three.java deleted file mode 100644 index d4418e3278..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Three.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "secret-three") -public class Three { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Two.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Two.java deleted file mode 100644 index 64a8f67ecc..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/named_secret_with_profile/properties/Two.java +++ /dev/null @@ -1,34 +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.config.applications.named_secret_with_profile.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("two") -public class Two { - - private String property; - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesApp.java deleted file mode 100644 index 17f7d3c768..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesApp.java +++ /dev/null @@ -1,35 +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.config.applications.single_source_multiple_files; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Color; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Name; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Shape; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Type; - -@SpringBootApplication -@EnableConfigurationProperties({ Name.class, Shape.class, Color.class, Type.class }) -public class SingleSourceMultipleFilesApp { - - public static void main(String[] args) { - SpringApplication.run(SingleSourceMultipleFilesApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesBootstrapTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesBootstrapTests.java deleted file mode 100644 index c5f3fb1a54..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesBootstrapTests.java +++ /dev/null @@ -1,33 +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.config.applications.single_source_multiple_files; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -/** - * @author wind57 - */ -@ActiveProfiles("color") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = SingleSourceMultipleFilesApp.class, - properties = { "spring.cloud.bootstrap.name=single-source-multiple-files", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true", - "spring.cloud.kubernetes.client.namespace=spring-k8s", "single.source.multiple.files.stub=true" }) -class SingleSourceMultipleFilesBootstrapTests extends SingleSourceMultipleFilesTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesConfigDataTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesConfigDataTests.java deleted file mode 100644 index fa56b6811b..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesConfigDataTests.java +++ /dev/null @@ -1,65 +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.config.applications.single_source_multiple_files; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub.stubData; - -/** - * @author wind57 - */ -@ActiveProfiles("color") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = SingleSourceMultipleFilesApp.class, properties = { "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./single-source-multiple-files.yaml" }) -class SingleSourceMultipleFilesConfigDataTests extends SingleSourceMultipleFilesTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesTests.java deleted file mode 100644 index 6ba97caee4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/SingleSourceMultipleFilesTests.java +++ /dev/null @@ -1,98 +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.config.applications.single_source_multiple_files; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author wind57 - * - * Stub for this test is here : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub} - * - * issue: https://github.com/spring-cloud/spring-cloud-kubernetes/issues/640 - * - */ -abstract class SingleSourceMultipleFilesTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *   "fruit-color.properties" is taken since "spring.application.name=fruit" and
-	 *   "color" is an active profile
-	 * 
- */ - @Test - void color() { - this.webClient.get().uri("/single_source-multiple-files/color").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("raw:green###ripe:yellow")); - } - - /** - *
-	 *   "fruit.properties" is read, since it matches "spring.application.name"
-	 * 
- */ - @Test - void name() { - this.webClient.get().uri("/single_source-multiple-files/name").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("banana")); - } - - /** - *
-	 *   shape profile is not active, thus property "fruit-shape.properties" is skipped
-	 *   and as such, a null comes here.
-	 * 
- */ - @Test - void shape() { - this.webClient.get().uri("/single_source-multiple-files/shape").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.nullValue()); - } - - /** - *
-	 *   this is a non-file property in the configmap
-	 * 
- */ - @Test - void type() { - this.webClient.get().uri("/single_source-multiple-files/type").exchange().expectStatus().isOk() - .expectBody(String.class).value(Matchers.equalTo("yummy")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/controller/SingleSourceMultipleFilesController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/controller/SingleSourceMultipleFilesController.java deleted file mode 100644 index 8fb655618c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/controller/SingleSourceMultipleFilesController.java +++ /dev/null @@ -1,64 +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.config.applications.single_source_multiple_files.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Color; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Name; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Shape; -import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Type; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class SingleSourceMultipleFilesController { - - private final Name name; - - private final Shape shape; - - private final Color color; - - private final Type type; - - public SingleSourceMultipleFilesController(Name name, Shape shape, Color color, Type type) { - this.name = name; - this.shape = shape; - this.color = color; - this.type = type; - } - - @GetMapping("/single_source-multiple-files/type") - public String type() { - return type.getType(); - } - - @GetMapping("/single_source-multiple-files/shape") - public String shape() { - return shape.getRaw(); - } - - @GetMapping("/single_source-multiple-files/color") - public String color() { - return "raw:" + color.getRaw() + "###" + "ripe:" + color.getRipe(); - } - - @GetMapping("/single_source-multiple-files/name") - public String name() { - return name.getName(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Color.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Color.java deleted file mode 100644 index 8d5cb2d44d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Color.java +++ /dev/null @@ -1,44 +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.config.applications.single_source_multiple_files.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "color.when") -public class Color { - - private String raw; - - private String ripe; - - public String getRaw() { - return raw; - } - - public void setRaw(String raw) { - this.raw = raw; - } - - public String getRipe() { - return ripe; - } - - public void setRipe(String ripe) { - this.ripe = ripe; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Name.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Name.java deleted file mode 100644 index 21df50111a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Name.java +++ /dev/null @@ -1,34 +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.config.applications.single_source_multiple_files.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("cool") -public class Name { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Shape.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Shape.java deleted file mode 100644 index 3a041536d8..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Shape.java +++ /dev/null @@ -1,44 +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.config.applications.single_source_multiple_files.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("shape.when") -public class Shape { - - private String raw; - - private String ripe; - - public String getRaw() { - return raw; - } - - public void setRaw(String raw) { - this.raw = raw; - } - - public String getRipe() { - return ripe; - } - - public void setRipe(String ripe) { - this.ripe = ripe; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Type.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Type.java deleted file mode 100644 index a8e4338b74..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/single_source_multiple_files/properties/Type.java +++ /dev/null @@ -1,34 +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.config.applications.single_source_multiple_files.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("fruit") -public class Type { - - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapRetryableSourcesOrderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapRetryableSourcesOrderTests.java deleted file mode 100644 index ad0bfa9ef4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapRetryableSourcesOrderTests.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SourcesOrderApp.class, - properties = { "spring.cloud.bootstrap.name=retryable-sources-order", "sources.order.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }) -class BootstrapRetryableSourcesOrderTests extends SourcesOrderTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapSourcesOrderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapSourcesOrderTests.java deleted file mode 100644 index 412e72c276..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/BootstrapSourcesOrderTests.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SourcesOrderApp.class, - properties = { "spring.cloud.bootstrap.name=sources-order", "sources.order.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }) -class BootstrapSourcesOrderTests extends SourcesOrderTests { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataRetryableSourcesOrderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataRetryableSourcesOrderTests.java deleted file mode 100644 index f8c23716bb..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataRetryableSourcesOrderTests.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubSecretsData; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub} - * - * @author wind57 - */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SourcesOrderApp.class, - properties = { "spring.cloud.bootstrap.name=retryable-sources-order", "sources.order.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }) -@AutoConfigureWebTestClient -class ConfigDataRetryableSourcesOrderTests extends SourcesOrderTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubConfigMapData(); - stubSecretsData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataSourcesOrderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataSourcesOrderTests.java deleted file mode 100644 index 1aea3d0290..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/ConfigDataSourcesOrderTests.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mockStatic; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData; -import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubSecretsData; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SourcesOrderApp.class, - properties = { "spring.cloud.application.name=sources-order", "sources.order.stub=true", - "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:,classpath:./sources-order.yaml", - "spring.cloud.kubernetes.client.namespace=spring-k8s" }) -class ConfigDataSourcesOrderTests extends SourcesOrderTests { - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("spring-k8s"); - stubConfigMapData(); - stubSecretsData(); - } - - @AfterAll - static void teardown() { - clientUtilsMock.close(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderApp.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderApp.java deleted file mode 100644 index 757ddb63ab..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderApp.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.client.config.applications.sources_order.properties.Properties; - -/** - * @author wind57 - */ -@SpringBootApplication -@EnableConfigurationProperties(Properties.class) -public class SourcesOrderApp { - - public static void main(String[] args) { - SpringApplication.run(SourcesOrderApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderTests.java deleted file mode 100644 index 7e7d59f2ba..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/SourcesOrderTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * The stub data for this test is in : - * {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub} - * - * @author wind57 - */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SourcesOrderApp.class, - properties = { "spring.cloud.bootstrap.name=sources-order", "sources.order.stub=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }) -@AutoConfigureWebTestClient -abstract class SourcesOrderTests { - - @Autowired - private WebTestClient webClient; - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @AfterAll - static void afterAll() { - WireMock.shutdownServer(); - } - - /** - *
-	 *	 1. There is one secret deployed: my-secret. It has two properties: {my.one=one, my.key=from-secret}
-	 *	 2. There is one configmap deployed: my-configmap. It has two properties: {my.two=two, my.key=from-configmap}
-	 *
-	 *	 We invoke three endpoints: /one, /two, /key.
-	 *	 The first two prove that both the secret and configmap have been read, the last one proves that
-	 *	 config maps have a higher precedence.
-	 * 
- */ - @Test - void test() { - this.webClient.get().uri("/one").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("one")); - this.webClient.get().uri("/two").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("two")); - - this.webClient.get().uri("/key").exchange().expectStatus().isOk().expectBody(String.class) - .value(Matchers.equalTo("from-configmap")); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/controller/SourcesOrderController.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/controller/SourcesOrderController.java deleted file mode 100644 index e5288511ed..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/controller/SourcesOrderController.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order.controller; - -import org.springframework.cloud.kubernetes.client.config.applications.sources_order.properties.Properties; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author wind57 - */ -@RestController -public class SourcesOrderController { - - private final Properties properties; - - SourcesOrderController(Properties properties) { - this.properties = properties; - } - - @GetMapping("/key") - String key() { - return properties.getKey(); - } - - @GetMapping("/one") - String one() { - return properties.getOne(); - } - - @GetMapping("/two") - String two() { - return properties.getTwo(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/properties/Properties.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/properties/Properties.java deleted file mode 100644 index 14b55ddba5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/applications/sources_order/properties/Properties.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2023 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.config.applications.sources_order.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * @author wind57 - */ -@ConfigurationProperties("my") -public class Properties { - - private String key; - - private String one; - - private String two; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getOne() { - return one; - } - - public void setOne(String one) { - this.one = one; - } - - public String getTwo() { - return two; - } - - public void setTwo(String two) { - this.two = two; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithPrefixConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithPrefixConfigurationStub.java deleted file mode 100644 index c55e19164a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithPrefixConfigurationStub.java +++ /dev/null @@ -1,100 +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.config.boostrap.stubs; - -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("labeled.config.map.with.prefix.stub") -public class LabeledConfigMapWithPrefixConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - public static void stubData() { - - V1ConfigMap one = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-one").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "a")).build()) - .addToData(Collections.singletonMap("one.property", "one")).build(); - - V1ConfigMap two = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-two").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "b")).build()) - .addToData(Collections.singletonMap("property", "two")).build(); - - V1ConfigMap three = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-three").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "c")).build()) - .addToData(Collections.singletonMap("property", "three")).build(); - - V1ConfigMap four = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-four").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "d")).build()) - .addToData(Collections.singletonMap("property", "four")).build(); - - // the actual stub for CoreV1Api calls - V1ConfigMapList configMapList = new V1ConfigMapList(); - configMapList.addItemsItem(one); - configMapList.addItemsItem(two); - configMapList.addItemsItem(three); - configMapList.addItemsItem(four); - - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(configMapList)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithProfileConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithProfileConfigurationStub.java deleted file mode 100644 index 09205f36e6..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledConfigMapWithProfileConfigurationStub.java +++ /dev/null @@ -1,154 +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.config.boostrap.stubs; - -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("labeled.config.map.with.profile.stub") -public class LabeledConfigMapWithProfileConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - /** - *
-	 *     - configmap with name "color-configmap", with labels: "{color: blue}" and "explicitPrefix: blue"
-	 *     - configmap with name "green-configmap", with labels: "{color: green}" and "explicitPrefix: blue-again"
-	 *     - configmap with name "red-configmap", with labels "{color: not-red}" and "useNameAsPrefix: true"
-	 *     - configmap with name "yellow-configmap" with labels "{color: not-yellow}" and useNameAsPrefix: true
-	 *     - configmap with name "color-configmap-k8s", with labels : "{color: not-blue}"
-	 *     - configmap with name "green-configmap-k8s", with labels : "{color: green-k8s}"
-	 *     - configmap with name "green-configmap-prod", with labels : "{color: green-prod}"
-	 *
-	 *     # a test that proves order: first read non-profile based configmaps, thus profile based
-	 *     # configmaps override non-profile ones.
-	 *     - configmap with name "green-purple-configmap", labels "{color: green, shape: round}", data: "{eight: 8}"
-	 *     - configmap with name "green-purple-configmap-k8s", labels "{color: black}", data: "{eight: eight-ish}"
-	 * 
- */ - public static void stubData() { - - // is found by labels - V1ConfigMap colorConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("color-configmap").withNamespace("spring-k8s") - .withLabels(Map.of("color", "blue")).build()) - .addToData(Collections.singletonMap("one", "1")).build(); - - // is not taken, since "profileSpecificSources=false" for the above - V1ConfigMap colorConfigMapK8s = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("color-configmap-k8s").withNamespace("spring-k8s") - .withLabels(Map.of("color", "not-blue")).build()) - .addToData(Collections.singletonMap("five", "5")).build(); - - // is found by labels - V1ConfigMap greenConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-configmap").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green")).build()) - .addToData(Collections.singletonMap("two", "2")).build(); - - V1ConfigMap greenConfigMapK8s = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-configmap-k8s").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green-k8s")).build()) - .addToData(Collections.singletonMap("six", "6")).build(); - - // is taken because prod profile is active and "profileSpecificSources=true" - V1ConfigMap greenConfigMapProd = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-configmap-prod").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green-prod")).build()) - .addToData(Collections.singletonMap("seven", "7")).build(); - - // not taken - V1ConfigMap redConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("red-configmap").withNamespace("spring-k8s") - .withLabels(Map.of("color", "red")).build()) - .addToData(Collections.singletonMap("three", "3")).build(); - - // not taken - V1ConfigMap yellowConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("yellow-configmap").withNamespace("spring-k8s") - .withLabels(Map.of("color", "yellow")).build()) - .addToData(Collections.singletonMap("four", "4")).build(); - - // is found by labels - V1ConfigMap greenPurpleConfigMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-purple-configmap").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green", "shape", "round")).build()) - .addToData(Collections.singletonMap("eight", "8")).build(); - - // is taken and thus overrides the above - V1ConfigMap greenPurpleConfigMapK8s = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-purple-configmap-k8s") - .withNamespace("spring-k8s").withLabels(Map.of("color", "black")).build()) - .addToData(Collections.singletonMap("eight", "eight-ish")).build(); - - // the actual stub for CoreV1Api calls - V1ConfigMapList configMaps = new V1ConfigMapList(); - configMaps.addItemsItem(colorConfigMap); - configMaps.addItemsItem(colorConfigMapK8s); - configMaps.addItemsItem(greenConfigMap); - configMaps.addItemsItem(greenConfigMapK8s); - configMaps.addItemsItem(greenConfigMapProd); - configMaps.addItemsItem(redConfigMap); - configMaps.addItemsItem(yellowConfigMap); - configMaps.addItemsItem(greenPurpleConfigMap); - configMaps.addItemsItem(greenPurpleConfigMapK8s); - - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(configMaps)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithPrefixConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithPrefixConfigurationStub.java deleted file mode 100644 index ea30c86b88..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithPrefixConfigurationStub.java +++ /dev/null @@ -1,99 +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.config.boostrap.stubs; - -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("labeled.secret.with.prefix.stub") -public class LabeledSecretWithPrefixConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - public static void stubData() { - V1Secret one = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-one").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "a")).withResourceVersion("1").build()) - .addToData(Collections.singletonMap("one.property", "one".getBytes())).build(); - - V1Secret two = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-two").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "b")).withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "two".getBytes())).build(); - - V1Secret three = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-three").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "c")).withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "three".getBytes())).build(); - - V1Secret four = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-four").withNamespace("spring-k8s") - .withLabels(Map.of("letter", "d")).withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "four".getBytes())).build(); - - // the actual stub for CoreV1Api calls - V1SecretList secrets = new V1SecretList(); - secrets.addItemsItem(one); - secrets.addItemsItem(two); - secrets.addItemsItem(three); - secrets.addItemsItem(four); - - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(secrets)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithProfileConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithProfileConfigurationStub.java deleted file mode 100644 index 813d37d54e..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/LabeledSecretWithProfileConfigurationStub.java +++ /dev/null @@ -1,155 +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.config.boostrap.stubs; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("labeled.secret.with.profile.stub") -public class LabeledSecretWithProfileConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - /** - *
-	 *     - secret with name "color-secret", with labels: "{color: blue}" and "explicitPrefix: blue"
-	 *     - secret with name "green-secret", with labels: "{color: green}" and "explicitPrefix: blue-again"
-	 *     - secret with name "red-secret", with labels "{color: not-red}" and "useNameAsPrefix: true"
-	 *     - secret with name "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true
-	 *     - secret with name "color-secret-k8s", with labels : "{color: not-blue}"
-	 *     - secret with name "green-secret-k8s", with labels : "{color: green-k8s}"
-	 *     - secret with name "green-secret-prod", with labels : "{color: green-prod}"
-	 *
-	 *     # a test that proves order: first read non-profile based secrets, thus profile based
-	 *     # secrets override non-profile ones.
-	 *     - secret with name "green-purple-secret", labels "{color: green, shape: round}", data: "{eight: 8}"
-	 *     - secret with name "green-purple-secret-k8s", labels "{color: black}", data: "{eight: eight-ish}"
-	 * 
- */ - public static void stubData() { - - // is found by labels - V1Secret colorSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("color-secret").withNamespace("spring-k8s") - .withLabels(Map.of("color", "blue")).build()) - .addToData(Collections.singletonMap("one", "1".getBytes(StandardCharsets.UTF_8))).build(); - - // is not taken, since "profileSpecificSources=false" for the above - V1Secret colorSecretK8s = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("color-secret-k8s").withNamespace("spring-k8s") - .withLabels(Map.of("color", "not-blue")).build()) - .addToData(Collections.singletonMap("five", "5".getBytes(StandardCharsets.UTF_8))).build(); - - // is found by labels - V1Secret greenSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-secret").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green")).build()) - .addToData(Collections.singletonMap("two", "2".getBytes(StandardCharsets.UTF_8))).build(); - - V1Secret greenSecretK8s = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-secret-k8s").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green-k8s")).build()) - .addToData(Collections.singletonMap("six", "6".getBytes(StandardCharsets.UTF_8))).build(); - - // is taken because prod profile is active and "profileSpecificSources=true" - V1Secret shapeSecretProd = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-secret-prod").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green-prod")).build()) - .addToData(Collections.singletonMap("seven", "7".getBytes(StandardCharsets.UTF_8))).build(); - - // not taken - V1Secret redSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("red-secret").withNamespace("spring-k8s") - .withLabels(Map.of("color", "not-red")).build()) - .addToData(Collections.singletonMap("three", "3".getBytes(StandardCharsets.UTF_8))).build(); - - // not taken - V1Secret yellowSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("yellow-secret").withNamespace("spring-k8s") - .withLabels(Map.of("color", "not-yellow")).build()) - .addToData(Collections.singletonMap("four", "4".getBytes(StandardCharsets.UTF_8))).build(); - - // is found by labels - V1Secret greenPurpleSecret = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-purple-secret").withNamespace("spring-k8s") - .withLabels(Map.of("color", "green", "shape", "round")).build()) - .addToData(Collections.singletonMap("eight", "8".getBytes(StandardCharsets.UTF_8))).build(); - - // is taken and thus overrides the above - V1Secret greenPurpleSecretK8s = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("green-purple-secret-k8s").withNamespace("spring-k8s") - .withLabels(Map.of("color", "black")).build()) - .addToData(Collections.singletonMap("eight", "eight-ish".getBytes(StandardCharsets.UTF_8))).build(); - - // the actual stub for CoreV1Api calls - V1SecretList secrets = new V1SecretList(); - secrets.addItemsItem(colorSecret); - secrets.addItemsItem(colorSecretK8s); - secrets.addItemsItem(greenSecret); - secrets.addItemsItem(greenSecretK8s); - secrets.addItemsItem(shapeSecretProd); - secrets.addItemsItem(redSecret); - secrets.addItemsItem(yellowSecret); - secrets.addItemsItem(greenPurpleSecret); - secrets.addItemsItem(greenPurpleSecretK8s); - - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(secrets)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithPrefixConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithPrefixConfigurationStub.java deleted file mode 100644 index c021349cd1..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithPrefixConfigurationStub.java +++ /dev/null @@ -1,91 +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.config.boostrap.stubs; - -import java.util.Arrays; -import java.util.Collections; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("named.config.map.with.prefix.stub") -public class NamedConfigMapWithPrefixConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - public static void stubData() { - V1ConfigMap one = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("config-map-one").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("one.property", "one")).build(); - - V1ConfigMap two = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("config-map-two").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "two")).build(); - - V1ConfigMap three = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("config-map-three").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "three")).build(); - - V1ConfigMapList allConfigMaps = new V1ConfigMapList(); - allConfigMaps.setItems(Arrays.asList(one, two, three)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithProfileConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithProfileConfigurationStub.java deleted file mode 100644 index 8e2147c9ef..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedConfigMapWithProfileConfigurationStub.java +++ /dev/null @@ -1,109 +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.config.boostrap.stubs; - -import java.util.Arrays; -import java.util.Collections; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("named.config.map.with.profile.stub") -public class NamedConfigMapWithProfileConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubData(); - return apiClient; - } - - public static void stubData() { - - // "one" and "oneFromK8s" also prove the fact that the right order is preserved: - // first non-profile based - // and only after profile based sources. Thus, properties from "one" are - // overridden by the ones from "oneFromK8s". - // We have a test that asserts this. - V1ConfigMap one = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-one").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("one.property", "one")).build(); - - V1ConfigMap oneFromK8s = new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName("configmap-one-k8s").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("one.property", "one-from-k8s")).build(); - - V1ConfigMap two = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-two").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("property", "two")).build(); - - V1ConfigMap twoFromK8s = new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName("configmap-two-k8s").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("property", "two-from-k8s")).build(); - - V1ConfigMap three = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("configmap-three").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("property", "three")).build(); - - V1ConfigMap threeFromK8s = new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName("configmap-three-k8s").withNamespace("spring-k8s").build()) - .addToData(Collections.singletonMap("property", "three-from-k8s")).build(); - - V1ConfigMapList allConfigMaps = new V1ConfigMapList(); - allConfigMaps.setItems(Arrays.asList(one, oneFromK8s, two, twoFromK8s, three, threeFromK8s)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithPrefixConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithPrefixConfigurationStub.java deleted file mode 100644 index dc8ab3dfd5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithPrefixConfigurationStub.java +++ /dev/null @@ -1,90 +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.config.boostrap.stubs; - -import java.util.Arrays; -import java.util.Collections; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("named.secret.with.prefix.stub") -public class NamedSecretWithPrefixConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - stubData(); - return apiClient; - } - - public static void stubData() { - V1Secret one = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-one").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("one.property", "one".getBytes())).build(); - - V1Secret two = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-two").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "two".getBytes())).build(); - - V1Secret three = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-three").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "three".getBytes())).build(); - - V1SecretList allSecrets = new V1SecretList(); - allSecrets.setItems(Arrays.asList(one, two, three)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allSecrets)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithProfileConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithProfileConfigurationStub.java deleted file mode 100644 index b1e1a19542..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/NamedSecretWithProfileConfigurationStub.java +++ /dev/null @@ -1,111 +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.config.boostrap.stubs; - -import java.util.Arrays; -import java.util.Collections; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("named.secret.with.profile.stub") -public class NamedSecretWithProfileConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - stubData(); - return apiClient; - } - - public static void stubData() { - - // "one" and "oneWithProfile" also prove the fact that the right order is - // preserved: first non-profile based - // and only after profile based sources. Thus, properties from "one" are - // overridden by the ones from "oneWithProfile". - // We have a test that asserts this. - V1Secret one = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-one").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("one.property", "one".getBytes())).build(); - - V1Secret oneWithProfile = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-one-k8s").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("one.property", "one-from-k8s".getBytes())).build(); - - V1Secret two = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-two").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "two".getBytes())).build(); - - V1Secret twoWithProfile = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-two-k8s").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "two-from-k8s".getBytes())).build(); - - V1Secret three = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-three").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "three".getBytes())).build(); - - V1Secret threeFromProfile = new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("secret-three-k8s").withNamespace("spring-k8s") - .withResourceVersion("1").build()) - .addToData(Collections.singletonMap("property", "three-from-k8s".getBytes())).build(); - - V1SecretList allSecrets = new V1SecretList(); - allSecrets.setItems(Arrays.asList(one, oneWithProfile, two, twoWithProfile, three, threeFromProfile)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allSecrets)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SingleSourceMultipleFilesConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SingleSourceMultipleFilesConfigurationStub.java deleted file mode 100644 index e92948d747..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SingleSourceMultipleFilesConfigurationStub.java +++ /dev/null @@ -1,88 +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.config.boostrap.stubs; - -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap - * context; with some stub data already present. - * - * @author wind57 - */ -@Order(0) -@Configuration -@ConditionalOnProperty("single.source.multiple.files.stub") -public class SingleSourceMultipleFilesConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - stubData(); - return apiClient; - } - - public static void stubData() { - - Map one = new HashMap<>(); - one.put("fruit.type", "yummy"); - one.put("fruit.properties", "cool.name=banana"); - one.put("fruit-color.properties", "color.when.raw=green\ncolor.when.ripe=yellow"); - - // this is not taken, since "shape" is not an active profile - one.put("fruit-shape.properties", "shape.when.raw=small-sphere\nshape.when.ripe=bigger-sphere"); - - V1ConfigMap configMap = new V1ConfigMapBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("my-configmap").withNamespace("spring-k8s").build()) - .addToData(one).build(); - - V1ConfigMapList allConfigMaps = new V1ConfigMapList(); - allConfigMaps.addItemsItem(configMap); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SourcesOrderConfigurationStub.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SourcesOrderConfigurationStub.java deleted file mode 100644 index 9b6bd8587a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap/stubs/SourcesOrderConfigurationStub.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013-2023 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.config.boostrap.stubs; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -@Order(0) -@Configuration -@ConditionalOnProperty("sources.order.stub") -public class SourcesOrderConfigurationStub { - - @Bean - public WireMockServer wireMock() { - WireMockServer server = new WireMockServer(options().dynamicPort()); - server.start(); - WireMock.configureFor("localhost", server.port()); - return server; - } - - @Bean - public ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient); - apiClient.setDebugging(true); - stubConfigMapData(); - stubSecretsData(); - return apiClient; - } - - public static void stubConfigMapData() { - - Map configMapData = new HashMap<>(); - configMapData.put("my.key", "from-configmap"); - configMapData.put("my.two", "two"); - - V1ConfigMap myConfigMap = new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder() - .withName("my-configmap").withNamespace("spring-k8s").withResourceVersion("1").build()) - .addToData(configMapData).build(); - - V1ConfigMapList allConfigMaps = new V1ConfigMapList(); - allConfigMaps.setItems(Collections.singletonList(myConfigMap)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps)))); - } - - public static void stubSecretsData() { - - Map secretData = new HashMap<>(); - secretData.put("my.key", "from-secret".getBytes(StandardCharsets.UTF_8)); - secretData.put("my.one", "one".getBytes(StandardCharsets.UTF_8)); - - V1Secret mySecret = new V1SecretBuilder().withMetadata(new V1ObjectMetaBuilder().withName("my-secret") - .withNamespace("spring-k8s").withResourceVersion("1").build()).addToData(secretData).build(); - - V1SecretList allConfigMaps = new V1SecretList(); - allConfigMaps.setItems(Collections.singletonList(mySecret)); - - // the actual stub for CoreV1Api calls - WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets") - .willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps)))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationInsideK8s.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationInsideK8s.java deleted file mode 100644 index 898d664fa9..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationInsideK8s.java +++ /dev/null @@ -1,49 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=abc", - "spring.cloud.bootstrap.enabled=true" }) -class KubernetesClientBootstrapConfigurationInsideK8s { - - @Autowired - private ConfigurableApplicationContext context; - - // tests that @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) has the desired - // effect, meaning when it is enabled, both property sources are present - @Test - public void bothPresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationNotInsideK8s.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationNotInsideK8s.java deleted file mode 100644 index b84ef3c7e5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesClientBootstrapConfigurationNotInsideK8s.java +++ /dev/null @@ -1,45 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "kubernetes.manifests.enabled=false" }) -class KubernetesClientBootstrapConfigurationNotInsideK8s { - - @Autowired - private ConfigurableApplicationContext context; - - // tests that @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) has the desired - // effect, meaning when it is disabled, no property source bean is present - @Test - void bothMissing() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesDisabled.java deleted file mode 100644 index bfe295c45d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesDisabled.java +++ /dev/null @@ -1,46 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "kubernetes.informer.enabled=false", "kubernetes.manifests.enabled=false" }) -class KubernetesDisabled { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void configAndSecretsBeansAreNotPresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabled.java deleted file mode 100644 index fc43330fe9..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabled.java +++ /dev/null @@ -1,44 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.cloud.kubernetes.client.namespace=default", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }) -class KubernetesEnabled { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void configAndSecretsBeansArePresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledConfigDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledConfigDisabled.java deleted file mode 100644 index e8ee40b554..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledConfigDisabled.java +++ /dev/null @@ -1,47 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.cloud.kubernetes.config.enabled=false", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }) -class KubernetesEnabledConfigDisabled { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void secretsOnlyPresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledOnPurpose.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledOnPurpose.java deleted file mode 100644 index 821d15e2c1..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledOnPurpose.java +++ /dev/null @@ -1,48 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.cloud.kubernetes.secrets.enabled=true", - "spring.cloud.kubernetes.client.namespace=default", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }) -class KubernetesEnabledOnPurpose { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void configAndSecretsBeansArePresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsAndConfigDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsAndConfigDisabled.java deleted file mode 100644 index 52c8f9a515..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsAndConfigDisabled.java +++ /dev/null @@ -1,47 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.cloud.kubernetes.secrets.enabled=false", "spring.cloud.kubernetes.config.enabled=false", - "spring.main.cloud-platform=KUBERNETES" }) -class KubernetesEnabledSecretsAndConfigDisabled { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void secretsOnlyPresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsDisabled.java deleted file mode 100644 index db268a9683..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/boostrap_configuration/KubernetesEnabledSecretsDisabled.java +++ /dev/null @@ -1,48 +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.config.boostrap_configuration; - -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.config.Application; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author wind57 - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, - properties = { "spring.cloud.kubernetes.secrets.enabled=false", - "spring.cloud.kubernetes.client.namespace=default", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }) -class KubernetesEnabledSecretsDisabled { - - @Autowired - private ConfigurableApplicationContext context; - - @Test - void secretsOnlyPresent() { - assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1); - assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/App.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/App.java deleted file mode 100644 index a0bf1df111..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/App.java +++ /dev/null @@ -1,24 +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.config.configmap_retry; - -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -class App { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastDisabled.java deleted file mode 100644 index f94ff5ecf0..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastDisabled.java +++ /dev/null @@ -1,30 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }, - classes = App.class) -class BootstrapConfigFailFastDisabled extends ConfigFailFastDisabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastEnabledButRetryDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastEnabledButRetryDisabled.java deleted file mode 100644 index ae261f67e5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigFailFastEnabledButRetryDisabled.java +++ /dev/null @@ -1,31 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.config.fail-fast=true", - "spring.cloud.kubernetes.config.retry.enabled=false", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }, - classes = App.class) -class BootstrapConfigFailFastEnabledButRetryDisabled extends ConfigFailFastEnabledButRetryDisabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryDisabledButSecretsRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryDisabledButSecretsRetryEnabled.java deleted file mode 100644 index cae7e2ed78..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryDisabledButSecretsRetryEnabled.java +++ /dev/null @@ -1,31 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.config.fail-fast=true", - "spring.cloud.kubernetes.config.retry.enabled=false", "spring.cloud.kubernetes.secrets.fail-fast=true", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" }, - classes = App.class) -class BootstrapConfigRetryDisabledButSecretsRetryEnabled extends ConfigRetryDisabledButSecretsRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryEnabled.java deleted file mode 100644 index 02e5542079..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/BootstrapConfigRetryEnabled.java +++ /dev/null @@ -1,31 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.config.fail-fast=true", - "spring.cloud.kubernetes.config.retry.max-attempts=5", "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.bootstrap.enabled=true" }, - classes = App.class) -class BootstrapConfigRetryEnabled extends ConfigRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastDisabled.java deleted file mode 100644 index 33051f0239..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastDisabled.java +++ /dev/null @@ -1,30 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:" }, - classes = App.class) -class ConfigDataConfigFailFastDisabled extends ConfigFailFastDisabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastEnabledButRetryDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastEnabledButRetryDisabled.java deleted file mode 100644 index 5fc1b2d38d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigFailFastEnabledButRetryDisabled.java +++ /dev/null @@ -1,31 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", - "spring.cloud.kubernetes.config.fail-fast=true", "spring.cloud.kubernetes.config.retry.enabled=false", - "spring.main.cloud-platform=KUBERNETES", "spring.config.import=kubernetes:" }, - classes = App.class) -class ConfigDataConfigFailFastEnabledButRetryDisabled extends ConfigFailFastEnabledButRetryDisabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryDisabledButSecretsRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryDisabledButSecretsRetryEnabled.java deleted file mode 100644 index 60ced494e4..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryDisabledButSecretsRetryEnabled.java +++ /dev/null @@ -1,32 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", - "spring.cloud.kubernetes.config.fail-fast=true", "spring.cloud.kubernetes.config.retry.enabled=false", - "spring.cloud.kubernetes.secrets.fail-fast=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:" }, - classes = App.class) -class ConfigDataConfigRetryDisabledButSecretsRetryEnabled extends ConfigRetryDisabledButSecretsRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryEnabled.java deleted file mode 100644 index db2a2c96ec..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigDataConfigRetryEnabled.java +++ /dev/null @@ -1,31 +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.config.configmap_retry; - -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", - "spring.cloud.kubernetes.config.fail-fast=true", "spring.cloud.kubernetes.config.retry.max-attempts=5", - "spring.main.cloud-platform=KUBERNETES", "spring.config.import=kubernetes:" }, - classes = App.class) -class ConfigDataConfigRetryEnabled extends ConfigRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastDisabled.java deleted file mode 100644 index ddb6ecef7b..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastDisabled.java +++ /dev/null @@ -1,100 +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.config.configmap_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -abstract class ConfigFailFastDisabled { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientConfigMapPropertySourceLocator propertySourceLocator; - - @Test - void locateShouldNotRetry() { - propertySourceLocator = spy(propertySourceLocator); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - Assertions.assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastEnabledButRetryDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastEnabledButRetryDisabled.java deleted file mode 100644 index ebea1330bd..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigFailFastEnabledButRetryDisabled.java +++ /dev/null @@ -1,111 +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.config.configmap_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -abstract class ConfigFailFastEnabledButRetryDisabled { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientConfigMapPropertySourceLocator propertySourceLocator; - - @Autowired - private ApplicationContext context; - - @Test - void locateShouldFailWithoutRetrying() { - propertySourceLocator = spy(propertySourceLocator); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - assertThat(context.containsBean("kubernetesConfigRetryInterceptor")).isFalse(); - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify that propertySourceLocator.locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigMapEnableRetryWithoutFailFastTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigMapEnableRetryWithoutFailFastTest.java deleted file mode 100644 index ffac804563..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigMapEnableRetryWithoutFailFastTest.java +++ /dev/null @@ -1,129 +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.config.configmap_retry; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; -import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientBootstrapConfiguration; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientRetryBootstrapConfiguration; -import org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientConfigReloadAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.retry.annotation.RetryConfiguration; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mockStatic; - -/** - * @author Ryan Baxter - */ -public class ConfigMapEnableRetryWithoutFailFastTest { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static final String SECRETS_API = "/api/v1/namespaces/default/secrets"; - - private ConfigurableApplicationContext context; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - stubFor(get(SECRETS_API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - } - - @AfterAll - public static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - protected void setup(String... env) { - List envList = (env != null) ? new ArrayList<>(Arrays.asList(env)) : new ArrayList<>(); - envList.add("spring.cloud.kubernetes.client.namespace=default"); - String[] envArray = envList.toArray(new String[0]); - - context = new SpringApplicationBuilder(RetryConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - ConfigReloadAutoConfiguration.class, RefreshAutoConfiguration.class, EndpointAutoConfiguration.class, - InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class, - ConfigurationPropertiesBindingPostProcessor.class, - ConfigurationPropertiesRebinderAutoConfiguration.class, KubernetesClientBootstrapConfiguration.class, - KubernetesClientRetryBootstrapConfiguration.class, KubernetesBootstrapConfiguration.class, - KubernetesClientConfigReloadAutoConfiguration.class) - .web(org.springframework.boot.WebApplicationType.NONE).properties(envArray).run(); - } - - @AfterEach - public void afterEach() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void doesNotContainRetryableConfigMapPropertySourceLocator() throws Exception { - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - setup("debug=true", "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.test.enable-retry=true"); - assertThat(context.containsBean("retryableConfigMapPropertySourceLocator")).isFalse(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryDisabledButSecretsRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryDisabledButSecretsRetryEnabled.java deleted file mode 100644 index f5fbe2036f..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryDisabledButSecretsRetryEnabled.java +++ /dev/null @@ -1,123 +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.config.configmap_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -abstract class ConfigRetryDisabledButSecretsRetryEnabled { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static final String SECRETS_API = "/api/v1/namespaces/default/secrets"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - stubFor(get(SECRETS_API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientConfigMapPropertySourceLocator propertySourceLocator; - - @Autowired - private ApplicationContext context; - - @Test - void locateShouldFailWithoutRetrying() { - propertySourceLocator = spy(propertySourceLocator); - /* - * Enabling secrets retry causes Spring Retry to be enabled and a - * RetryOperationsInterceptor bean with NeverRetryPolicy for config maps to be - * defined. ConfigMapPropertySourceLocator should not retry even Spring Retry is - * enabled. - */ - - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - // TODO not in bootstrap - // assertThat(context.containsBean("kubernetesConfigRetryInterceptor")).isTrue(); - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify that propertySourceLocator.locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryEnabled.java deleted file mode 100644 index c638853f33..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/configmap_retry/ConfigRetryEnabled.java +++ /dev/null @@ -1,172 +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.config.configmap_retry; - -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.core.env.PropertySource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; - -/** - * @author Isik Erhan - */ -abstract class ConfigRetryEnabled { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private ConfigMapPropertySourceLocator retryablePl; - - @Test - void locateShouldNotRetryWhenThereIsNoFailure() { - ConfigMapPropertySourceLocator propertySourceLocator = spy(retryablePl); - Map data = new HashMap<>(); - data.put("some.prop", "theValue"); - data.put("some.number", "0"); - - V1ConfigMapList configMapList = new V1ConfigMapList() - .addItemsItem(new V1ConfigMap().metadata(new V1ObjectMeta().name("application")).data(data)); - - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(configMapList)))); - - PropertySource propertySource = Assertions - .assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify locate is called only once - WireMock.verify(1, getRequestedFor(urlEqualTo(API))); - - // validate the contents of the property source - assertThat(propertySource.getProperty("some.prop")).isEqualTo("theValue"); - assertThat(propertySource.getProperty("some.number")).isEqualTo("0"); - } - - @Test - void locateShouldRetryAndRecover() { - ConfigMapPropertySourceLocator propertySourceLocator = spy(retryablePl); - Map data = new HashMap<>(); - data.put("some.prop", "theValue"); - data.put("some.number", "0"); - - V1ConfigMapList configMapList = new V1ConfigMapList() - .addItemsItem(new V1ConfigMap().metadata(new V1ObjectMeta().name("application")).data(data)); - - // fail 3 times - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs(STARTED) - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed once")); - - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed once") - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed twice")); - - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed twice") - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed thrice")); - - // then succeed - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed thrice") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(configMapList)))); - - PropertySource propertySource = Assertions - .assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify the request was retried 4 times, 5 total request - WireMock.verify(5, getRequestedFor(urlEqualTo(API))); - - // validate the contents of the property source - assertThat(propertySource.getProperty("some.prop")).isEqualTo("theValue"); - assertThat(propertySource.getProperty("some.number")).isEqualTo("0"); - } - - @Test - void locateShouldRetryAndFail() { - ConfigMapPropertySourceLocator propertySourceLocator = spy(retryablePl); - // fail all the 5 requests - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify the request was retried 5 times - WireMock.verify(5, getRequestedFor(urlEqualTo(API))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetectorTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetectorTests.java deleted file mode 100644 index f4d3449c6c..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetectorTests.java +++ /dev/null @@ -1,189 +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.config.reload; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.time.Duration; -import java.time.OffsetDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import io.kubernetes.client.informer.EventType; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ListMeta; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.util.ClientBuilder; -import io.kubernetes.client.util.Watch; -import okhttp3.OkHttpClient; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; -import org.springframework.mock.env.MockPropertySource; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static org.awaitility.Awaitility.await; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -class KubernetesClientEventBasedConfigMapChangeDetectorTests { - - private static WireMockServer wireMockServer; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @Test - void watch() { - GsonBuilder builder = new GsonBuilder(); - builder.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE) - .registerTypeAdapter(OffsetDateTime.class, new GsonOffsetDateTimeAdapter()); - Gson gson = builder.create(); - - Map data = new HashMap<>(); - data.put("application.properties", "spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n" - + "logging.level.org.springframework.cloud.kubernetes=TRACE"); - Map updateData = new HashMap<>(); - updateData.put("application.properties", "spring.cloud.kubernetes.configuration.watcher.refreshDelay=1\n" - + "logging.level.org.springframework.cloud.kubernetes=TRACE"); - V1ConfigMap applicationConfig = new V1ConfigMap().kind("ConfigMap") - .metadata(new V1ObjectMeta().namespace("default").name("bar1")).data(data); - V1ConfigMapList configMapList = new V1ConfigMapList().metadata(new V1ListMeta().resourceVersion("0")) - .items(List.of(applicationConfig)); - stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch") - .whenScenarioStateIs(STARTED).withQueryParam("watch", equalTo("false")) - .willReturn(aResponse().withStatus(200).withBody(gson.toJson(configMapList))).willSetStateTo("update")); - - Watch.Response watchResponse = new Watch.Response<>(EventType.MODIFIED.name(), new V1ConfigMap() - .kind("ConfigMap").metadata(new V1ObjectMeta().namespace("default").name("bar1")).data(updateData)); - stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch") - .whenScenarioStateIs("update").withQueryParam("watch", equalTo("true")) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(watchResponse))) - .willSetStateTo("add")); - - stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch") - .whenScenarioStateIs("add").withQueryParam("watch", equalTo("true")) - .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new Watch.Response<>(EventType.ADDED.name(), - new V1ConfigMap().kind("ConfigMap") - .metadata(new V1ObjectMeta().namespace("default").name("bar3")) - .putDataItem("application.properties", "debug=true"))))) - .willSetStateTo("delete")); - - stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch") - .whenScenarioStateIs("delete").withQueryParam("watch", equalTo("true")) - .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new Watch.Response<>(EventType.DELETED.name(), - new V1ConfigMap().kind("ConfigMap") - .metadata(new V1ObjectMeta().namespace("default").name("bar1")) - .putDataItem("application.properties", "debug=true"))))) - .willSetStateTo("done")); - - stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch") - .whenScenarioStateIs("done").withQueryParam("watch", equalTo("true")) - .willReturn(aResponse().withStatus(200))); - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build(); - apiClient.setHttpClient(httpClient); - CoreV1Api coreV1Api = new CoreV1Api(apiClient); - - int[] howMany = new int[1]; - Runnable run = () -> { - ++howMany[0]; - }; - ConfigurationUpdateStrategy strategy = new ConfigurationUpdateStrategy("strategy", run); - - KubernetesMockEnvironment environment = new KubernetesMockEnvironment( - mock(KubernetesClientConfigMapPropertySource.class)).withProperty("debug", "true"); - KubernetesClientConfigMapPropertySourceLocator locator = mock( - KubernetesClientConfigMapPropertySourceLocator.class); - when(locator.locate(environment)).thenAnswer(x -> new MockPropertySource().withProperty("debug", "false")); - KubernetesNamespaceProvider kubernetesNamespaceProvider = mock(KubernetesNamespaceProvider.class); - when(kubernetesNamespaceProvider.getNamespace()).thenReturn("default"); - - KubernetesClientEventBasedConfigMapChangeDetector changeDetector = new KubernetesClientEventBasedConfigMapChangeDetector( - coreV1Api, environment, ConfigReloadProperties.DEFAULT, strategy, locator, kubernetesNamespaceProvider); - - Thread controllerThread = new Thread(changeDetector::inform); - controllerThread.setDaemon(true); - controllerThread.start(); - - await().timeout(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(2)).until(() -> howMany[0] >= 4); - } - - // This is needed when using JDK17 because GSON uses reflection to construct an - // OffsetDateTime but that constructor - // is protected. - public final static class GsonOffsetDateTimeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter jsonWriter, OffsetDateTime localDateTime) throws IOException { - jsonWriter.value(OffsetDateTime.now().toString()); - } - - @Override - public OffsetDateTime read(JsonReader jsonReader) { - return OffsetDateTime.now(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetectorTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetectorTests.java deleted file mode 100644 index 98bfef6cf1..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetectorTests.java +++ /dev/null @@ -1,283 +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.config.reload; - -import java.time.Duration; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; -import io.kubernetes.client.informer.EventType; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ListMeta; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import io.kubernetes.client.util.Watch; -import okhttp3.OkHttpClient; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; -import org.springframework.mock.env.MockPropertySource; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static org.awaitility.Awaitility.await; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -class KubernetesClientEventBasedSecretsChangeDetectorTests { - - private static final Map WATCH_FALSE = Map.of("watch", equalTo("false")); - - private static final Map WATCH_TRUE = Map.of("watch", equalTo("true")); - - private static final String SCENARIO = "watch"; - - private static WireMockServer wireMockServer; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @Test - void watch() { - - V1Secret dbPassword = new V1Secret().metadata(new V1ObjectMeta().name("db-password")) - .putStringDataItem("password", Base64.getEncoder().encodeToString("p455w0rd".getBytes())) - .putDataItem("password", Base64.getEncoder().encode("p455w0rd".getBytes())) - .putStringDataItem("username", Base64.getEncoder().encodeToString("user".getBytes())) - .putDataItem("username", Base64.getEncoder().encode("user".getBytes())); - V1SecretList secretList = new V1SecretList().metadata(new V1ListMeta().resourceVersion("0")) - .items(List.of(dbPassword)); - - V1Secret dbPasswordUpdated = new V1Secret().metadata(new V1ObjectMeta().name("db-password")) - .putStringDataItem("password", Base64.getEncoder().encodeToString("p455w0rd2".getBytes())) - .putDataItem("password", Base64.getEncoder().encode("p455w0rd2".getBytes())) - .putStringDataItem("username", Base64.getEncoder().encodeToString("user".getBytes())) - .putDataItem("username", Base64.getEncoder().encode("user".getBytes())); - Watch.Response watchResponse = new Watch.Response<>(EventType.MODIFIED.name(), dbPasswordUpdated); - - stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario(SCENARIO) - .whenScenarioStateIs(STARTED).withQueryParams(WATCH_FALSE) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))) - .willSetStateTo("update")); - - stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario(SCENARIO) - .whenScenarioStateIs("update").withQueryParams(WATCH_TRUE) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(watchResponse))) - .willSetStateTo("add")); - - stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario(SCENARIO).whenScenarioStateIs("add") - .withQueryParams(WATCH_TRUE) - .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new Watch.Response<>(EventType.ADDED.name(), - new V1Secret().metadata(new V1ObjectMeta().name("rabbit-password")) - .putDataItem("rabbit-pw", Base64.getEncoder().encode("password".getBytes())))))) - .willSetStateTo("delete")); - - stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario(SCENARIO) - .whenScenarioStateIs("delete").withQueryParams(WATCH_TRUE) - .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new Watch.Response<>(EventType.DELETED.name(), - new V1Secret().metadata(new V1ObjectMeta().name("rabbit-password")) - .putDataItem("rabbit-pw", Base64.getEncoder().encode("password".getBytes())))))) - .willSetStateTo("done")); - - stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario("watch").whenScenarioStateIs("done") - .withQueryParam("watch", equalTo("true")).willReturn(aResponse().withStatus(200))); - - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build(); - apiClient.setHttpClient(httpClient); - CoreV1Api coreV1Api = new CoreV1Api(apiClient); - - int[] howMany = new int[1]; - Runnable run = () -> { - ++howMany[0]; - }; - ConfigurationUpdateStrategy strategy = new ConfigurationUpdateStrategy("strategy", run); - - KubernetesMockEnvironment environment = new KubernetesMockEnvironment( - mock(KubernetesClientSecretsPropertySource.class)).withProperty("db-password", "p455w0rd"); - KubernetesClientSecretsPropertySourceLocator locator = mock(KubernetesClientSecretsPropertySourceLocator.class); - when(locator.locate(environment)) - .thenAnswer(ignoreMe -> new MockPropertySource().withProperty("db-password", "p455w0rd2")); - ConfigReloadProperties properties = new ConfigReloadProperties(false, false, true, - ConfigReloadProperties.ReloadStrategy.REFRESH, ConfigReloadProperties.ReloadDetectionMode.EVENT, - Duration.ofMillis(15000), Set.of(), false, Duration.ofSeconds(2)); - KubernetesNamespaceProvider kubernetesNamespaceProvider = mock(KubernetesNamespaceProvider.class); - when(kubernetesNamespaceProvider.getNamespace()).thenReturn("default"); - KubernetesClientEventBasedSecretsChangeDetector changeDetector = new KubernetesClientEventBasedSecretsChangeDetector( - coreV1Api, environment, properties, strategy, locator, kubernetesNamespaceProvider); - - Thread controllerThread = new Thread(changeDetector::inform); - controllerThread.setDaemon(true); - controllerThread.start(); - - await().timeout(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(2)).until(() -> howMany[0] >= 4); - } - - /** - * both are null, treat that as no change. - */ - @Test - void equalsOne() { - Map left = null; - Map right = null; - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertTrue(result); - } - - /** - * - left is empty map - right is null - * - * treat as equal, that is: no change - */ - @Test - void equalsTwo() { - Map left = Map.of(); - Map right = null; - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertTrue(result); - } - - /** - * - left is empty map - right is null - * - * treat as equal, that is: no change - */ - @Test - void equalsThree() { - Map left = Map.of(); - Map right = null; - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertTrue(result); - } - - /** - * - left is null - right is empty map - * - * treat as equal, that is: no change - */ - @Test - void equalsFour() { - Map left = null; - Map right = Map.of(); - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertTrue(result); - } - - /** - * - left is empty map - right is empty map - * - * treat as equal, that is: no change - */ - @Test - void equalsFive() { - Map left = Map.of(); - Map right = Map.of(); - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertTrue(result); - } - - /** - * - left is empty map - right is [1, b] - * - * treat as non-equal, that is change - */ - @Test - void equalsSix() { - Map left = Map.of(); - Map right = Map.of("1", "b".getBytes()); - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertFalse(result); - } - - /** - * - left is [1, a] - right is [1, b] - * - * treat as non-equal, that is change - */ - @Test - void equalsSeven() { - Map left = Map.of("1", "a".getBytes()); - Map right = Map.of("1", "b".getBytes()); - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertFalse(result); - } - - /** - * - left is [1, a, 2 aa] - right is [1, b, 2, aa] - * - * treat as non-equal, that is change - */ - @Test - void equalsEight() { - Map left = Map.of("1", "a".getBytes(), "2", "aa".getBytes()); - Map right = Map.of("1", "b".getBytes(), "2", "aa".getBytes()); - - boolean result = KubernetesClientEventBasedSecretsChangeDetector.equals(left, right); - Assertions.assertFalse(result); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesMockEnvironment.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesMockEnvironment.java deleted file mode 100644 index f951f627d2..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesMockEnvironment.java +++ /dev/null @@ -1,55 +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.config.reload; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource; -import org.springframework.core.env.AbstractEnvironment; -import org.springframework.core.env.PropertySource; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -public class KubernetesMockEnvironment extends AbstractEnvironment { - - private PropertySource propertySource = mock(KubernetesClientSecretsPropertySource.class); - - private Map map = new HashMap<>(); - - public KubernetesMockEnvironment(PropertySource mockPropertySource) { - this.propertySource = mockPropertySource; - this.getPropertySources().addLast(this.propertySource); - when(propertySource.getSource()).thenReturn(map); - } - - public void setProperty(String key, String value) { - map.put(key, value); - when(propertySource.getProperty(eq(key))).thenReturn(value); - } - - public KubernetesMockEnvironment withProperty(String key, String value) { - this.setProperty(key, value); - return this; - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsEnableRetryWithoutFailFastTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsEnableRetryWithoutFailFastTest.java deleted file mode 100644 index e0312b4892..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsEnableRetryWithoutFailFastTest.java +++ /dev/null @@ -1,130 +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.config.secrets_retry; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; -import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; -import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientBootstrapConfiguration; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientRetryBootstrapConfiguration; -import org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientConfigReloadAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration; -import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.retry.annotation.RetryConfiguration; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mockStatic; - -/** - * @author Ryan Baxter - */ -public class SecretsEnableRetryWithoutFailFastTest { - - private static final String API = "/api/v1/namespaces/default/configmaps"; - - private static final String SECRETS_API = "/api/v1/namespaces/default/secrets"; - - private ConfigurableApplicationContext context; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - stubFor(get(SECRETS_API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - } - - @AfterAll - public static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - protected void setup(String... env) { - List envList = (env != null) ? new ArrayList<>(Arrays.asList(env)) : new ArrayList<>(); - envList.add("spring.cloud.kubernetes.client.namespace=default"); - String[] envArray = envList.toArray(new String[0]); - - context = new SpringApplicationBuilder(RetryConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - ConfigReloadAutoConfiguration.class, RefreshAutoConfiguration.class, EndpointAutoConfiguration.class, - InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class, - ConfigurationPropertiesBindingPostProcessor.class, - ConfigurationPropertiesRebinderAutoConfiguration.class, KubernetesClientBootstrapConfiguration.class, - KubernetesClientRetryBootstrapConfiguration.class, KubernetesBootstrapConfiguration.class, - KubernetesClientConfigReloadAutoConfiguration.class) - .web(org.springframework.boot.WebApplicationType.NONE).properties(envArray).run(); - } - - @AfterEach - public void afterEach() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void doesNotContainRetryableSecretsPropertySourceLocator() throws Exception { - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - setup("debug=true", "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.test.enable-retry=true", - "spring.cloud.kubernetes.secrets.name=my-secret", "spring.cloud.kubernetes.secrets.enable-api=true"); - assertThat(context.containsBean("retryableSecretsPropertySourceLocator")).isFalse(); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastDisabled.java deleted file mode 100644 index dd23fe1a53..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastDisabled.java +++ /dev/null @@ -1,106 +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.config.secrets_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.client.namespace=default", - "spring.cloud.kubernetes.secrets.name=my-secret", "spring.cloud.kubernetes.secrets.enable-api=true", - "spring.main.cloud-platform=KUBERNETES", "spring.config.import=kubernetes:" }, - classes = SecretsRetryApplication.class) -class SecretsFailFastDisabled { - - private static final String API = "/api/v1/namespaces/default/secrets"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientSecretsPropertySourceLocator psl; - - @Test - void locateShouldNotRetry() { - KubernetesClientSecretsPropertySourceLocator propertySourceLocator = spy(psl); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - Assertions.assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastEnabledButRetryDisabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastEnabledButRetryDisabled.java deleted file mode 100644 index b536c300f5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsFailFastEnabledButRetryDisabled.java +++ /dev/null @@ -1,123 +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.config.secrets_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.secrets.fail-fast=true", - "spring.cloud.kubernetes.secrets.retry.enabled=false", "spring.cloud.kubernetes.secrets.name=my-secret", - "spring.cloud.kubernetes.secrets.enable-api=true", "spring.main.cloud-platform=KUBERNETES", - "spring.config.import=kubernetes:" }, - classes = SecretsRetryApplication.class) -class SecretsFailFastEnabledButRetryDisabled { - - private static final String API = "/api/v1/namespaces/default/secrets"; - - private static final String CONFIG_MAPS_API = "/api/v1/namespaces/default/configmaps"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - stubFor(get(CONFIG_MAPS_API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientSecretsPropertySourceLocator psl; - - @Autowired - private ApplicationContext context; - - @Test - void locateShouldFailWithoutRetrying() { - KubernetesClientSecretsPropertySourceLocator propertySourceLocator = spy(psl); - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - assertThat(context.containsBean("kubernetesSecretsRetryInterceptor")).isFalse(); - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify that propertySourceLocator.locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryApplication.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryApplication.java deleted file mode 100644 index 36a541b9f5..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryApplication.java +++ /dev/null @@ -1,24 +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.config.secrets_retry; - -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -class SecretsRetryApplication { - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryDisabledButConfigRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryDisabledButConfigRetryEnabled.java deleted file mode 100644 index 1791fef951..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryDisabledButConfigRetryEnabled.java +++ /dev/null @@ -1,130 +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.config.secrets_retry; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.secrets.fail-fast=true", - "spring.cloud.kubernetes.secrets.retry.enabled=false", "spring.cloud.kubernetes.config.fail-fast=true", - "spring.cloud.kubernetes.secrets.name=my-secret", "spring.cloud.kubernetes.secrets.enable-api=true", - "spring.main.cloud-platform=KUBERNETES", "spring.config.import=kubernetes:" }, - classes = SecretsRetryApplication.class) -class SecretsRetryDisabledButConfigRetryEnabled { - - private static final String API = "/api/v1/namespaces/default/secrets"; - - private static final String CONFIG_MAPS_API = "/api/v1/namespaces/default/configmaps"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - stubFor(get(CONFIG_MAPS_API) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ConfigMapList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Autowired - private KubernetesClientSecretsPropertySourceLocator psl; - - @Autowired - private ApplicationContext context; - - @Test - void locateShouldFailWithoutRetrying() { - KubernetesClientSecretsPropertySourceLocator propertySourceLocator = spy(psl); - /* - * Enabling config retry causes Spring Retry to be enabled and a - * RetryOperationsInterceptor bean with NeverRetryPolicy for secrets to be - * defined. SecretsPropertySourceLocator should not retry even Spring Retry is - * enabled. - */ - - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - // TODO not in bootstrap - // assertThat(context.containsBean("kubernetesSecretsRetryInterceptor")).isTrue(); - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify that propertySourceLocator.locate is called only once - verify(propertySourceLocator, times(1)).locate(any()); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryEnabled.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryEnabled.java deleted file mode 100644 index bda4f7b481..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/secrets_retry/SecretsRetryEnabled.java +++ /dev/null @@ -1,179 +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.config.secrets_retry; - -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretList; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; -import org.springframework.core.env.PropertySource; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; - -/** - * @author Isik Erhan - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { "spring.cloud.kubernetes.secrets.fail-fast=true", - "spring.cloud.kubernetes.secrets.retry.max-attempts=5", - "spring.cloud.kubernetes.secrets.name=my-secret", "spring.cloud.kubernetes.secrets.enable-api=true", - "spring.main.cloud-platform=KUBERNETES", "spring.config.import=kubernetes:" }, - classes = SecretsRetryApplication.class) -class SecretsRetryEnabled { - - private static final String API = "/api/v1/namespaces/default/secrets"; - - private static WireMockServer wireMockServer; - - private static MockedStatic clientUtilsMock; - - @BeforeAll - static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - clientUtilsMock - .when(() -> KubernetesClientUtils.getApplicationNamespace(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn("default"); - stubConfigMapAndSecretsDefaults(); - } - - private static void stubConfigMapAndSecretsDefaults() { - // return empty config map / secret list to not fail context creation - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1SecretList())))); - } - - @AfterAll - static void teardown() { - wireMockServer.stop(); - clientUtilsMock.close(); - } - - @Autowired - private SecretsPropertySourceLocator psl; - - @BeforeEach - void afterEach() { - WireMock.reset(); - stubConfigMapAndSecretsDefaults(); - } - - @Test - void locateShouldNotRetryWhenThereIsNoFailure() { - SecretsPropertySourceLocator propertySourceLocator = spy(psl); - Map data = new HashMap<>(); - data.put("some.sensitive.prop", "theSensitiveValue".getBytes()); - data.put("some.sensitive.number", "1".getBytes()); - - V1SecretList secretList = new V1SecretList() - .addItemsItem(new V1Secret().metadata(new V1ObjectMeta().name("my-secret")).data(data)); - - stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList)))); - - PropertySource propertySource = Assertions - .assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify locate is called only once - WireMock.verify(1, getRequestedFor(urlEqualTo(API))); - - // validate the contents of the property source - assertThat(propertySource.getProperty("some.sensitive.prop")).isEqualTo("theSensitiveValue"); - assertThat(propertySource.getProperty("some.sensitive.number")).isEqualTo("1"); - } - - @Test - void locateShouldRetryAndRecover() { - SecretsPropertySourceLocator propertySourceLocator = spy(psl); - Map data = new HashMap<>(); - data.put("some.sensitive.prop", "theSensitiveValue".getBytes()); - data.put("some.sensitive.number", "1".getBytes()); - - V1SecretList secretList = new V1SecretList() - .addItemsItem(new V1Secret().metadata(new V1ObjectMeta().name("my-secret")).data(data)); - - // fail 3 times - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs(STARTED) - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed once")); - - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed once") - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed twice")); - - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed twice") - .willReturn(aResponse().withStatus(500)).willSetStateTo("Failed thrice")); - - // then succeed - stubFor(get(API).inScenario("Retry and Recover").whenScenarioStateIs("Failed thrice") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList)))); - - PropertySource propertySource = Assertions - .assertDoesNotThrow(() -> propertySourceLocator.locate(new MockEnvironment())); - - // verify retried 4 times - WireMock.verify(4, getRequestedFor(urlEqualTo(API))); - - // validate the contents of the property source - assertThat(propertySource.getProperty("some.sensitive.prop")).isEqualTo("theSensitiveValue"); - assertThat(propertySource.getProperty("some.sensitive.number")).isEqualTo("1"); - } - - @Test - void locateShouldRetryAndFail() { - SecretsPropertySourceLocator propertySourceLocator = spy(psl); - // fail all the 5 requests - stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))); - - assertThatThrownBy(() -> propertySourceLocator.locate(new MockEnvironment())) - .isInstanceOf(IllegalStateException.class).hasMessage("Internal Server Error"); - - // verify retried 5 times until failure - WireMock.verify(5, getRequestedFor(urlEqualTo(API))); - } - -} diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/META-INF/spring.factories b/spring-cloud-kubernetes-client-config/src/test/resources/META-INF/spring.factories deleted file mode 100644 index 00abb43956..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/META-INF/spring.factories +++ /dev/null @@ -1,14 +0,0 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.IncludeProfileSpecificSourcesConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.ConfigMapNameAsPrefixConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub, \ -org.springframework.cloud.kubernetes.client.config.EnableRetryBootstrapConfiguration diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/include-profile-specific-sources.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/include-profile-specific-sources.yaml deleted file mode 100644 index 54999aaa3a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/include-profile-specific-sources.yaml +++ /dev/null @@ -1,14 +0,0 @@ -spring: - application: - name: include-profile-specific-sources - cloud: - kubernetes: - config: - includeProfileSpecificSources: false - namespace: spring-k8s - sources: - - name: config-map-one - includeProfileSpecificSources: true - - name: config-map-two - includeProfileSpecificSources: false - - name: config-map-three diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-prefix.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-prefix.yaml deleted file mode 100644 index 40bea776b8..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-prefix.yaml +++ /dev/null @@ -1,21 +0,0 @@ -spring: - application: - name: labeled-configmap-with-prefix - cloud: - kubernetes: - config: - 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 diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-profile.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-profile.yaml deleted file mode 100644 index 8aa88d2deb..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-configmap-with-profile.yaml +++ /dev/null @@ -1,22 +0,0 @@ -spring: - application: - name: labeled-configmap-with-profile - cloud: - kubernetes: - config: - enableApi: true - useNameAsPrefix: true - namespace: spring-k8s - includeProfileSpecificSources: true - sources: - - labels: - color: blue - explicitPrefix: blue - includeProfileSpecificSources: false - - labels: - color: green - - labels: - color: red - - labels: - color: yellow - useNameAsPrefix: true diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-prefix.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-prefix.yaml deleted file mode 100644 index fa6cb72d0f..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-prefix.yaml +++ /dev/null @@ -1,21 +0,0 @@ -spring: - application: - name: labeled-secret-with-prefix - 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 diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-profile.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-profile.yaml deleted file mode 100644 index 89255f0810..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/labeled-secret-with-profile.yaml +++ /dev/null @@ -1,22 +0,0 @@ -spring: - application: - name: labeled-secret-with-profile - cloud: - kubernetes: - secrets: - enableApi: true - useNameAsPrefix: true - namespace: spring-k8s - includeProfileSpecificSources: true - sources: - - labels: - color: blue - explicitPrefix: blue - includeProfileSpecificSources: false - - labels: - color: green - - labels: - color: red - - labels: - color: yellow - useNameAsPrefix: true diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/logback-test.xml b/spring-cloud-kubernetes-client-config/src/test/resources/logback-test.xml deleted file mode 100644 index c947209d9a..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/logback-test.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-prefix.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-prefix.yaml deleted file mode 100644 index cb7bd5af86..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-prefix.yaml +++ /dev/null @@ -1,14 +0,0 @@ -spring: - application: - name: named-config-map-with-prefix - cloud: - kubernetes: - config: - useNameAsPrefix: true - namespace: spring-k8s - sources: - - name: config-map-one - useNameAsPrefix: false - - name: config-map-two - explicitPrefix: two - - name: config-map-three diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-profile.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-profile.yaml deleted file mode 100644 index da49651040..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/named-configmap-with-profile.yaml +++ /dev/null @@ -1,17 +0,0 @@ -spring: - application: - name: named-configmap-with-profile - cloud: - kubernetes: - config: - enableApi: true - useNameAsPrefix: true - namespace: spring-k8s - includeProfileSpecificSources: true - sources: - - name: configmap-one - useNameAsPrefix: false - - name: configmap-two - explicitPrefix: two - includeProfileSpecificSources: false - - name: configmap-three diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-prefix.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-prefix.yaml deleted file mode 100644 index 8bfda9beaa..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-prefix.yaml +++ /dev/null @@ -1,16 +0,0 @@ -spring: - application: - name: named-secret-with-prefix - cloud: - kubernetes: - client: - namespace: spring-k8s - secrets: - enableApi: true - useNameAsPrefix: true - sources: - - name: secret-one - useNameAsPrefix: false - - name: secret-two - explicitPrefix: two - - name: secret-three diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-profile.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-profile.yaml deleted file mode 100644 index 6d52b01f1d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/named-secret-with-profile.yaml +++ /dev/null @@ -1,18 +0,0 @@ -spring: - application: - name: named-secret-with-prefix - cloud: - kubernetes: - client: - namespace: spring-k8s - secrets: - enableApi: true - useNameAsPrefix: true - includeProfileSpecificSources: true - sources: - - name: secret-one - useNameAsPrefix: false - - name: secret-two - explicitPrefix: two - includeProfileSpecificSources: false - - name: secret-three diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/retryable-sources-order.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/retryable-sources-order.yaml deleted file mode 100644 index 06afb7ca70..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/retryable-sources-order.yaml +++ /dev/null @@ -1,17 +0,0 @@ -spring: - application: - name: sources-order - cloud: - kubernetes: - secrets: - fail-fast: true - enabled: true - enableApi: true - namespace: spring-k8s - sources: - - name: my-secret - config: - fail-fast: true - namespace: spring-k8s - sources: - - name: my-configmap diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/single-source-multiple-files.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/single-source-multiple-files.yaml deleted file mode 100644 index 571e90a02d..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/single-source-multiple-files.yaml +++ /dev/null @@ -1,9 +0,0 @@ -spring: - application: - name: fruit - cloud: - kubernetes: - config: - namespace: spring-k8s - sources: - - name: my-configmap diff --git a/spring-cloud-kubernetes-client-config/src/test/resources/sources-order.yaml b/spring-cloud-kubernetes-client-config/src/test/resources/sources-order.yaml deleted file mode 100644 index c76cb73369..0000000000 --- a/spring-cloud-kubernetes-client-config/src/test/resources/sources-order.yaml +++ /dev/null @@ -1,15 +0,0 @@ -spring: - application: - name: sources-order - cloud: - kubernetes: - secrets: - enabled: true - enableApi: true - namespace: spring-k8s - sources: - - name: my-secret - config: - namespace: spring-k8s - sources: - - name: my-configmap diff --git a/spring-cloud-kubernetes-client-discovery/.flattened-pom.xml b/spring-cloud-kubernetes-client-discovery/.flattened-pom.xml new file mode 100644 index 0000000000..b4d4f2f5f4 --- /dev/null +++ b/spring-cloud-kubernetes-client-discovery/.flattened-pom.xml @@ -0,0 +1,128 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-client-discovery + 3.0.4-SNAPSHOT + Spring Cloud Kubernetes :: Kubernetes Client Discovery + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io/spring-cloud-kubernetes-client-discovery + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-discovery + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-discovery + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-client-discovery + + + + org.springframework.cloud + spring-cloud-kubernetes-client-autoconfig + 3.0.4-SNAPSHOT + compile + + + org.springframework.cloud + spring-cloud-commons + 4.0.4-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-actuator + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-autoconfigure + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-starter-webflux + 3.0.7 + compile + true + + + org.springframework.cloud + spring-cloud-config-client + 4.0.4-SNAPSHOT + compile + true + + + diff --git a/spring-cloud-kubernetes-client-discovery/pom.xml b/spring-cloud-kubernetes-client-discovery/pom.xml deleted file mode 100644 index db48e67fca..0000000000 --- a/spring-cloud-kubernetes-client-discovery/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - spring-cloud-kubernetes - org.springframework.cloud - 3.1.0-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-client-discovery - Spring Cloud Kubernetes :: Kubernetes Client Discovery - - - - org.springframework.cloud - spring-cloud-kubernetes-client-autoconfig - ${project.version} - - - org.springframework.cloud - spring-cloud-commons - ${spring-cloud-commons.version} - - - org.springframework.boot - spring-boot-actuator - true - - - org.springframework.boot - spring-boot-autoconfigure - true - - - org.springframework.boot - spring-boot-starter-webflux - true - - - org.springframework.cloud - spring-cloud-config-client - true - - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - io.projectreactor - reactor-test - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - - diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnBlockingOrReactiveEnabled.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnBlockingOrReactiveEnabled.java deleted file mode 100644 index 6bb44aa493..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnBlockingOrReactiveEnabled.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; -import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled; -import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled; -import org.springframework.context.annotation.Conditional; - -/** - * Conditional that is resolved to active when either - * {@link ConditionalOnBlockingOrReactiveEnabled} or - * {@link ConditionalOnReactiveDiscoveryEnabled} matches. - * - * @author wind57 - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnBlockingOrReactiveEnabled.OnBlockingOrReactiveEnabled.class) -public @interface ConditionalOnBlockingOrReactiveEnabled { - - class OnBlockingOrReactiveEnabled extends AnyNestedCondition { - - OnBlockingOrReactiveEnabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnBlockingDiscoveryEnabled - static class OnBlockingEnabled { - - } - - @ConditionalOnReactiveDiscoveryEnabled - static class OnReactiveEnabled { - - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesMissing.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesMissing.java deleted file mode 100644 index 5f1815d0b1..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesMissing.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.Set; - -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.ConfigurationCondition; -import org.springframework.core.log.LogAccessor; -import org.springframework.core.type.AnnotatedTypeMetadata; - -/** - * Conditional that checks if our discovery is _not_ based on selective namespaces, i.e.: - * 'spring.cloud.kubernetes.discovery.namespaces' is not set. - * - * @author wind57 - */ -public final class ConditionalOnSelectiveNamespacesMissing implements ConfigurationCondition { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(ConditionalOnSelectiveNamespacesMissing.class)); - - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - - Set selectiveNamespaces = Binder.get(context.getEnvironment()) - .bind("spring.cloud.kubernetes.discovery.namespaces", Bindable.setOf(String.class)).orElse(Set.of()); - boolean selectiveNamespacesMissing = selectiveNamespaces.isEmpty(); - if (selectiveNamespacesMissing) { - LOG.debug(() -> "selective namespaces not present"); - } - else { - LOG.debug(() -> "found selective namespaces : " + selectiveNamespaces.stream().sorted().toList()); - } - return selectiveNamespacesMissing; - } - - @Override - public ConfigurationPhase getConfigurationPhase() { - return ConfigurationPhase.REGISTER_BEAN; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesPresent.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesPresent.java deleted file mode 100644 index 6832287d74..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesPresent.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.Set; - -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.ConfigurationCondition; -import org.springframework.core.log.LogAccessor; -import org.springframework.core.type.AnnotatedTypeMetadata; - -/** - * Conditional that checks if our discovery is based on selective namespaces, i.e.: - * 'spring.cloud.kubernetes.discovery.namespaces' is set. - * - * @author wind57 - */ -public final class ConditionalOnSelectiveNamespacesPresent implements ConfigurationCondition { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(ConditionalOnSelectiveNamespacesPresent.class)); - - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - - Set selectiveNamespaces = Binder.get(context.getEnvironment()) - .bind("spring.cloud.kubernetes.discovery.namespaces", Bindable.setOf(String.class)).orElse(Set.of()); - boolean selectiveNamespacesPresent = !selectiveNamespaces.isEmpty(); - if (selectiveNamespacesPresent) { - LOG.debug(() -> "found selective namespaces : " + selectiveNamespaces.stream().sorted().toList()); - } - else { - LOG.debug(() -> "selective namespaces not present"); - } - return selectiveNamespacesPresent; - } - - @Override - public ConfigurationCondition.ConfigurationPhase getConfigurationPhase() { - return ConfigurationPhase.REGISTER_BEAN; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapper.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapper.java deleted file mode 100644 index 282b843817..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapper.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2019-2023 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.discovery; - -import java.util.Collections; -import java.util.List; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.util.Namespaces; -import io.kubernetes.client.util.generic.GenericKubernetesApi; -import org.apache.commons.logging.Log; - -import org.springframework.boot.BootstrapContext; -import org.springframework.boot.BootstrapRegistry; -import org.springframework.boot.context.properties.bind.BindHandler; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.config.client.ConfigServerInstanceProvider; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerBootstrapper; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigServerInstanceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.core.env.AbstractEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.util.ClassUtils; - -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient; - -/** - * @author Ryan Baxter - */ -class KubernetesClientConfigServerBootstrapper extends KubernetesConfigServerBootstrapper { - - @Override - public void initialize(BootstrapRegistry registry) { - if (!ClassUtils.isPresent("org.springframework.cloud.config.client.ConfigServerInstanceProvider", null)) { - return; - } - // We need to pass a lambda here rather than create a new instance of - // ConfigServerInstanceProvider.Function - // or else we will get ClassNotFoundExceptions if Spring Cloud Config is not on - // the classpath - registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, KubernetesFunction::create); - } - - final static class KubernetesFunction implements ConfigServerInstanceProvider.Function { - - private final BootstrapContext context; - - private KubernetesFunction(BootstrapContext context) { - this.context = context; - } - - static KubernetesFunction create(BootstrapContext context) { - return new KubernetesFunction(context); - } - - @Override - public List apply(String serviceId, Binder binder, BindHandler bindHandler, Log log) { - if (binder == null || bindHandler == null || !getDiscoveryEnabled(binder, bindHandler)) { - // If we don't have the Binder or BinderHandler from the - // ConfigDataLocationResolverContext - // we won't be able to create the necessary configuration - // properties to configure the - // Kubernetes DiscoveryClient - return Collections.emptyList(); - } - KubernetesDiscoveryProperties discoveryProperties = createKubernetesDiscoveryProperties(binder, - bindHandler); - KubernetesClientProperties clientProperties = createKubernetesClientProperties(binder, bindHandler); - return getInstanceProvider(discoveryProperties, clientProperties, context, binder, bindHandler, log) - .getInstances(serviceId); - } - - protected KubernetesConfigServerInstanceProvider getInstanceProvider( - KubernetesDiscoveryProperties discoveryProperties, KubernetesClientProperties clientProperties, - BootstrapContext context, Binder binder, BindHandler bindHandler, Log log) { - if (context.isRegistered(KubernetesInformerDiscoveryClient.class)) { - KubernetesInformerDiscoveryClient client = context.get(KubernetesInformerDiscoveryClient.class); - return client::getInstances; - } - else { - - ApiClient defaultApiClient = kubernetesApiClient(); - defaultApiClient.setUserAgent(binder.bind("spring.cloud.kubernetes.client.user-agent", String.class) - .orElse(KubernetesClientProperties.DEFAULT_USER_AGENT)); - KubernetesClientAutoConfiguration clientAutoConfiguration = new KubernetesClientAutoConfiguration(); - ApiClient apiClient = context.getOrElseSupply(ApiClient.class, () -> defaultApiClient); - - KubernetesNamespaceProvider kubernetesNamespaceProvider = clientAutoConfiguration - .kubernetesNamespaceProvider(getNamespaceEnvironment(binder, bindHandler)); - - String namespace = getInformerNamespace(kubernetesNamespaceProvider, discoveryProperties); - SharedInformerFactory sharedInformerFactory = new SharedInformerFactory(apiClient); - final GenericKubernetesApi servicesApi = new GenericKubernetesApi<>( - V1Service.class, V1ServiceList.class, "", "v1", "services", apiClient); - SharedIndexInformer serviceSharedIndexInformer = sharedInformerFactory - .sharedIndexInformerFor(servicesApi, V1Service.class, 0L, namespace); - Lister serviceLister = new Lister<>(serviceSharedIndexInformer.getIndexer()); - final GenericKubernetesApi endpointsApi = new GenericKubernetesApi<>( - V1Endpoints.class, V1EndpointsList.class, "", "v1", "endpoints", apiClient); - SharedIndexInformer endpointsSharedIndexInformer = sharedInformerFactory - .sharedIndexInformerFor(endpointsApi, V1Endpoints.class, 0L, namespace); - Lister endpointsLister = new Lister<>(endpointsSharedIndexInformer.getIndexer()); - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - sharedInformerFactory, serviceLister, endpointsLister, serviceSharedIndexInformer, - endpointsSharedIndexInformer, discoveryProperties); - try { - discoveryClient.afterPropertiesSet(); - return discoveryClient::getInstances; - } - catch (Exception e) { - if (log != null) { - log.warn("Error initiating informer discovery client", e); - } - return (serviceId) -> Collections.emptyList(); - } - finally { - sharedInformerFactory.stopAllRegisteredInformers(); - } - } - } - - private String getInformerNamespace(KubernetesNamespaceProvider kubernetesNamespaceProvider, - KubernetesDiscoveryProperties discoveryProperties) { - return discoveryProperties.allNamespaces() ? Namespaces.NAMESPACE_ALL - : kubernetesNamespaceProvider.getNamespace() == null ? Namespaces.NAMESPACE_DEFAULT - : kubernetesNamespaceProvider.getNamespace(); - } - - private Environment getNamespaceEnvironment(Binder binder, BindHandler bindHandler) { - return new AbstractEnvironment() { - @Override - public String getProperty(String key) { - return binder.bind(key, Bindable.of(String.class), bindHandler).orElse(super.getProperty(key)); - } - }; - } - - // This method should never be called, but is there for backward - // compatibility purposes - @Override - public List apply(String serviceId) { - return apply(serviceId, null, null, null); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java deleted file mode 100644 index 2b73621095..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.util.generic.GenericKubernetesApi; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.client.CommonsClientAutoConfiguration; -import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; - -import static io.kubernetes.client.util.Namespaces.NAMESPACE_ALL; -import static io.kubernetes.client.util.Namespaces.NAMESPACE_DEFAULT; -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace; - -/** - * @author wind57 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesDiscoveryEnabled -@ConditionalOnBlockingOrReactiveEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@Conditional(ConditionalOnSelectiveNamespacesMissing.class) -@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) -@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class }) -public class KubernetesClientInformerAutoConfiguration { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesClientInformerAutoConfiguration.class)); - - @Bean - @ConditionalOnMissingBean - public SharedInformerFactory sharedInformerFactory(ApiClient client) { - LOG.debug(() -> "registering sharedInformerFactory for non-selective namespaces"); - return new SharedInformerFactory(client); - } - - @Bean - public String kubernetesClientNamespace(KubernetesDiscoveryProperties properties, - KubernetesNamespaceProvider provider) { - String namespace; - if (properties.allNamespaces()) { - namespace = NAMESPACE_ALL; - LOG.debug(() -> "serviceSharedInformer will use all-namespaces"); - } - else { - try { - namespace = getApplicationNamespace(null, "kubernetes client discovery", provider); - } - catch (NamespaceResolutionFailedException ex) { - LOG.warn(() -> "failed to resolve namespace, defaulting to :" + NAMESPACE_DEFAULT - + ". This will fail in a future release."); - namespace = NAMESPACE_DEFAULT; - } - LOG.debug("serviceSharedInformer will use namespace : " + namespace); - } - - return namespace; - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = SharedIndexInformer.class) - public SharedIndexInformer servicesSharedIndexInformer(SharedInformerFactory sharedInformerFactory, - ApiClient apiClient, String kubernetesClientNamespace) { - - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Service.class, - V1ServiceList.class, "", "v1", "services", apiClient); - - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Service.class, 0L, - kubernetesClientNamespace); - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = SharedIndexInformer.class) - public SharedIndexInformer endpointsSharedIndexInformer(SharedInformerFactory sharedInformerFactory, - ApiClient apiClient, String kubernetesClientNamespace) { - - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Endpoints.class, - V1EndpointsList.class, "", "v1", "endpoints", apiClient); - - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Endpoints.class, 0L, - kubernetesClientNamespace); - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = Lister.class) - public Lister servicesLister(SharedIndexInformer servicesSharedIndexInformer, - String kubernetesClientNamespace) { - return new Lister<>(servicesSharedIndexInformer.getIndexer(), kubernetesClientNamespace); - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = Lister.class) - public Lister endpointsLister(SharedIndexInformer endpointsSharedIndexInformer, - String kubernetesClientNamespace) { - return new Lister<>(endpointsSharedIndexInformer.getIndexer(), kubernetesClientNamespace); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerSelectiveNamespacesAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerSelectiveNamespacesAutoConfiguration.java deleted file mode 100644 index 5f44ed9b21..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerSelectiveNamespacesAutoConfiguration.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.ArrayList; -import java.util.List; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.util.generic.GenericKubernetesApi; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.client.CommonsClientAutoConfiguration; -import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; - -/** - * Auto-configuration to be used when "spring.cloud.kubernetes.discovery.namespaces" is - * defined. - * - * @author wind57 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesDiscoveryEnabled -@ConditionalOnBlockingOrReactiveEnabled -@Conditional(ConditionalOnSelectiveNamespacesPresent.class) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) -@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class }) -public class KubernetesClientInformerSelectiveNamespacesAutoConfiguration { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class)); - - // we rely on the order of namespaces to enable listers, as such provide a bean of - // namespaces - // as a list, instead of the incoming Set. - @Bean - @ConditionalOnMissingBean - public List selectiveNamespaces(KubernetesDiscoveryProperties properties) { - List selectiveNamespaces = properties.namespaces().stream().sorted().toList(); - LOG.debug(() -> "using selective namespaces : " + selectiveNamespaces); - return selectiveNamespaces; - } - - @Bean - @ConditionalOnMissingBean(value = SharedInformerFactory.class, parameterizedContainer = List.class) - public List sharedInformerFactories(ApiClient apiClient, List selectiveNamespaces) { - - int howManyNamespaces = selectiveNamespaces.size(); - List sharedInformerFactories = new ArrayList<>(howManyNamespaces); - for (int i = 0; i < howManyNamespaces; ++i) { - sharedInformerFactories.add(new SharedInformerFactory(apiClient)); - } - return sharedInformerFactories; - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, - parameterizedContainer = { List.class, SharedIndexInformer.class }) - public List> serviceSharedIndexInformers( - List sharedInformerFactories, List selectiveNamespaces, - ApiClient apiClient) { - - int howManyNamespaces = selectiveNamespaces.size(); - List> serviceSharedIndexedInformers = new ArrayList<>(howManyNamespaces); - for (int i = 0; i < howManyNamespaces; ++i) { - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Service.class, - V1ServiceList.class, "", "v1", "services", apiClient); - SharedIndexInformer sharedIndexInformer = sharedInformerFactories.get(i) - .sharedIndexInformerFor(servicesApi, V1Service.class, 0L, selectiveNamespaces.get(i)); - serviceSharedIndexedInformers.add(sharedIndexInformer); - } - return serviceSharedIndexedInformers; - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = { List.class, Lister.class }) - public List> serviceListers(List selectiveNamespaces, - List> serviceSharedIndexInformers) { - - int howManyNamespaces = selectiveNamespaces.size(); - List> serviceListers = new ArrayList<>(howManyNamespaces); - - for (int i = 0; i < howManyNamespaces; ++i) { - String namespace = selectiveNamespaces.get(i); - Lister lister = new Lister<>(serviceSharedIndexInformers.get(i).getIndexer(), namespace); - LOG.debug(() -> "registering lister (for services) in namespace : " + namespace); - serviceListers.add(lister); - } - - return serviceListers; - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, - parameterizedContainer = { List.class, SharedIndexInformer.class }) - public List> endpointsSharedIndexInformers( - List sharedInformerFactories, List selectiveNamespaces, - ApiClient apiClient) { - - int howManyNamespaces = selectiveNamespaces.size(); - List> endpointsSharedIndexedInformers = new ArrayList<>(howManyNamespaces); - for (int i = 0; i < howManyNamespaces; ++i) { - GenericKubernetesApi endpointsApi = new GenericKubernetesApi<>( - V1Endpoints.class, V1EndpointsList.class, "", "v1", "endpoints", apiClient); - SharedIndexInformer sharedIndexInformer = sharedInformerFactories.get(i) - .sharedIndexInformerFor(endpointsApi, V1Endpoints.class, 0L, selectiveNamespaces.get(i)); - endpointsSharedIndexedInformers.add(sharedIndexInformer); - } - return endpointsSharedIndexedInformers; - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = { List.class, Lister.class }) - public List> endpointsListers(List selectiveNamespaces, - List> serviceSharedIndexInformers) { - - int howManyNamespaces = selectiveNamespaces.size(); - List> endpointsListers = new ArrayList<>(howManyNamespaces); - - for (int i = 0; i < howManyNamespaces; ++i) { - String namespace = selectiveNamespaces.get(i); - Lister lister = new Lister<>(serviceSharedIndexInformers.get(i).getIndexer()); - LOG.debug(() -> "registering lister (for endpoints) in namespace : " + namespace); - endpointsListers.add(lister); - } - - return endpointsListers; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfiguration.java deleted file mode 100644 index 954c1c1471..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.discovery; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -@Configuration(proxyBeanMethods = false) -@ConditionalOnProperty("spring.cloud.config.discovery.enabled") -@Import({ KubernetesClientAutoConfiguration.class, KubernetesInformerDiscoveryClientAutoConfiguration.class }) -public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration { - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtils.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtils.java deleted file mode 100644 index 9e0a88aeae..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtils.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.time.Duration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceSpec; -import io.kubernetes.client.util.wait.Wait; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.core.log.LogAccessor; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.SimpleEvaluationContext; - -import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.keysWithPrefix; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.NAMESPACE_METADATA_KEY; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SERVICE_TYPE; - -/** - * @author wind57 - */ -final class KubernetesDiscoveryClientUtils { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesDiscoveryClientUtils.class)); - - private static final SpelExpressionParser PARSER = new SpelExpressionParser(); - - private static final SimpleEvaluationContext EVALUATION_CONTEXT = SimpleEvaluationContext.forReadOnlyDataBinding() - .withInstanceMethods().build(); - - private KubernetesDiscoveryClientUtils() { - - } - - static boolean matchesServiceLabels(V1Service service, KubernetesDiscoveryProperties properties) { - - Map propertiesServiceLabels = properties.serviceLabels(); - Map serviceLabels = Optional.ofNullable(service.getMetadata()).map(V1ObjectMeta::getLabels) - .orElse(Map.of()); - - if (propertiesServiceLabels.isEmpty()) { - LOG.debug(() -> "service labels from properties are empty, service with name : '" - + service.getMetadata().getName() + "' will match"); - return true; - } - - if (serviceLabels.isEmpty()) { - LOG.debug(() -> "service with name : '" + service.getMetadata().getName() + "' does not have labels"); - return false; - } - - LOG.debug(() -> "Service labels from properties : " + propertiesServiceLabels); - LOG.debug(() -> "Service labels from service : " + serviceLabels); - - return serviceLabels.entrySet().containsAll(propertiesServiceLabels.entrySet()); - - } - - /** - * This adds the following metadata.
-	 *     - labels (if requested)
-	 *     - annotations (if requested)
-	 *     - metadata
-	 *     - service type
-	 * 
- */ - static Map serviceMetadata(KubernetesDiscoveryProperties properties, V1Service service, - String serviceId) { - - Map serviceMetadata = new HashMap<>(); - KubernetesDiscoveryProperties.Metadata metadataProps = properties.metadata(); - if (metadataProps.addLabels()) { - Map labelMetadata = keysWithPrefix(service.getMetadata().getLabels(), - metadataProps.labelsPrefix()); - LOG.debug(() -> "Adding labels metadata: " + labelMetadata + " for serviceId: " + serviceId); - serviceMetadata.putAll(labelMetadata); - } - if (metadataProps.addAnnotations()) { - Map annotationMetadata = keysWithPrefix(service.getMetadata().getAnnotations(), - metadataProps.annotationsPrefix()); - LOG.debug(() -> "Adding annotations metadata: " + annotationMetadata + " for serviceId: " + serviceId); - serviceMetadata.putAll(annotationMetadata); - } - - serviceMetadata.put(NAMESPACE_METADATA_KEY, - Optional.ofNullable(service.getMetadata()).map(V1ObjectMeta::getNamespace).orElse(null)); - serviceMetadata.put(SERVICE_TYPE, - Optional.ofNullable(service.getSpec()).map(V1ServiceSpec::getType).orElse(null)); - - return serviceMetadata; - } - - static Predicate filter(KubernetesDiscoveryProperties properties) { - String spelExpression = properties.filter(); - Predicate predicate; - if (spelExpression == null || spelExpression.isEmpty()) { - LOG.debug(() -> "filter not defined, returning always true predicate"); - predicate = service -> true; - } - else { - Expression filterExpr = PARSER.parseExpression(spelExpression); - predicate = service -> { - Boolean include = filterExpr.getValue(EVALUATION_CONTEXT, service, Boolean.class); - return Optional.ofNullable(include).orElse(false); - }; - LOG.debug(() -> "returning predicate based on filter expression: " + spelExpression); - } - return predicate; - } - - static void postConstruct(List sharedInformerFactories, - KubernetesDiscoveryProperties properties, Supplier informersReadyFunc, - List> serviceListers) { - - sharedInformerFactories.forEach(SharedInformerFactory::startAllRegisteredInformers); - if (!Wait.poll(Duration.ofSeconds(1), Duration.ofSeconds(properties.cacheLoadingTimeoutSeconds()), () -> { - LOG.info(() -> "Waiting for the cache of informers to be fully loaded.."); - return informersReadyFunc.get(); - })) { - if (properties.waitCacheReady()) { - throw new IllegalStateException( - "Timeout waiting for informers cache to be ready, is the kubernetes service up?"); - } - else { - LOG.warn(() -> "Timeout waiting for informers cache to be ready, " - + "ignoring the failure because waitForInformerCacheReady property is false"); - } - } - else { - LOG.info(() -> "Cache fully loaded (total " + serviceListers.stream().mapToLong(x -> x.list().size()).sum() - + " services), discovery client is now available"); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerAutoConfiguration.java deleted file mode 100644 index e504eb3219..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerAutoConfiguration.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.util.generic.GenericKubernetesApi; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.client.CommonsClientAutoConfiguration; -import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; - -import static io.kubernetes.client.util.Namespaces.NAMESPACE_ALL; -import static io.kubernetes.client.util.Namespaces.NAMESPACE_DEFAULT; - -/** - * This configuration is not used by us internally and will be removed in a future - * release. Use it at your own risk. - * - * @author wind57 - */ -@Deprecated(forRemoval = true) -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesDiscoveryEnabled -@ConditionalOnBlockingOrReactiveEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@Conditional(ConditionalOnSelectiveNamespacesMissing.class) -@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) -@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class }) -public class KubernetesInformerAutoConfiguration { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesInformerAutoConfiguration.class)); - - @Bean - @ConditionalOnMissingBean - public SharedInformerFactory sharedInformerFactory(ApiClient client) { - return new SharedInformerFactory(client); - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = SharedIndexInformer.class) - public SharedIndexInformer servicesSharedIndexInformer(SharedInformerFactory sharedInformerFactory, - ApiClient apiClient, KubernetesNamespaceProvider kubernetesNamespaceProvider, - KubernetesDiscoveryProperties discoveryProperties) { - - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Service.class, - V1ServiceList.class, "", "v1", "services", apiClient); - - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Service.class, 0L, - namespace(discoveryProperties, kubernetesNamespaceProvider)); - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = SharedIndexInformer.class) - public SharedIndexInformer endpointsSharedIndexInformer(SharedInformerFactory sharedInformerFactory, - ApiClient apiClient, KubernetesNamespaceProvider kubernetesNamespaceProvider, - KubernetesDiscoveryProperties discoveryProperties) { - - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Endpoints.class, - V1EndpointsList.class, "", "v1", "endpoints", apiClient); - - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Endpoints.class, 0L, - namespace(discoveryProperties, kubernetesNamespaceProvider)); - } - - @Bean - @ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = Lister.class) - public Lister servicesLister(SharedIndexInformer servicesSharedIndexInformer) { - return new Lister<>(servicesSharedIndexInformer.getIndexer()); - } - - @Bean - @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = Lister.class) - public Lister endpointsLister(SharedIndexInformer endpointsSharedIndexInformer) { - return new Lister<>(endpointsSharedIndexInformer.getIndexer()); - } - - private String namespace(KubernetesDiscoveryProperties discoveryProperties, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - String namespace; - if (discoveryProperties.allNamespaces()) { - namespace = NAMESPACE_ALL; - } - else if (kubernetesNamespaceProvider.getNamespace() == null) { - namespace = NAMESPACE_DEFAULT; - } - else { - namespace = kubernetesNamespaceProvider.getNamespace(); - } - - LOG.debug(() -> "serviceSharedInformer will use namespace : " + namespace); - return namespace; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClient.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClient.java deleted file mode 100644 index 572ecd3510..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClient.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.discovery; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.kubernetes.client.informer.SharedInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.CoreV1EndpointPort; -import io.kubernetes.client.openapi.models.V1EndpointAddress; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1Service; -import jakarta.annotation.PostConstruct; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.core.log.LogAccessor; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.filter; -import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.matchesServiceLabels; -import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.postConstruct; -import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.serviceMetadata; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTP; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTPS; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SECURED; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.UNSET_PORT_NAME; - -/** - * @author Min Kim - * @author Ryan Baxter - * @author Tim Yysewyn - */ -public class KubernetesInformerDiscoveryClient implements DiscoveryClient { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesInformerDiscoveryClient.class)); - - private final List sharedInformerFactories; - - private final List> serviceListers; - - private final List> endpointsListers; - - private final Supplier informersReadyFunc; - - private final KubernetesDiscoveryProperties properties; - - private final Predicate filter; - - @Deprecated(forRemoval = true) - public KubernetesInformerDiscoveryClient(String namespace, SharedInformerFactory sharedInformerFactory, - Lister serviceLister, Lister endpointsLister, - SharedInformer serviceInformer, SharedInformer endpointsInformer, - KubernetesDiscoveryProperties properties) { - this.sharedInformerFactories = List.of(sharedInformerFactory); - this.serviceListers = List.of(serviceLister); - this.endpointsListers = List.of(endpointsLister); - this.informersReadyFunc = () -> serviceInformer.hasSynced() && endpointsInformer.hasSynced(); - this.properties = properties; - filter = filter(properties); - } - - public KubernetesInformerDiscoveryClient(SharedInformerFactory sharedInformerFactory, - Lister serviceLister, Lister endpointsLister, - SharedInformer serviceInformer, SharedInformer endpointsInformer, - KubernetesDiscoveryProperties properties) { - this.sharedInformerFactories = List.of(sharedInformerFactory); - this.serviceListers = List.of(serviceLister); - this.endpointsListers = List.of(endpointsLister); - this.informersReadyFunc = () -> serviceInformer.hasSynced() && endpointsInformer.hasSynced(); - this.properties = properties; - filter = filter(properties); - } - - public KubernetesInformerDiscoveryClient(List sharedInformerFactories, - List> serviceListers, List> endpointsListers, - List> serviceInformers, List> endpointsInformers, - KubernetesDiscoveryProperties properties) { - this.sharedInformerFactories = sharedInformerFactories; - - this.serviceListers = serviceListers; - this.endpointsListers = endpointsListers; - this.informersReadyFunc = () -> { - boolean serviceInformersReady = serviceInformers.isEmpty() || serviceInformers.stream() - .map(SharedInformer::hasSynced).reduce(Boolean::logicalAnd).orElse(false); - boolean endpointsInformersReady = endpointsInformers.isEmpty() || endpointsInformers.stream() - .map(SharedInformer::hasSynced).reduce(Boolean::logicalAnd).orElse(false); - return serviceInformersReady && endpointsInformersReady; - }; - - this.properties = properties; - filter = filter(properties); - } - - @Override - public String description() { - return "Kubernetes Client Discovery"; - } - - @Override - public List getInstances(String serviceId) { - Objects.requireNonNull(serviceId, "serviceId must be provided"); - - List services = serviceListers.stream().flatMap(x -> x.list().stream()) - .filter(scv -> scv.getMetadata() != null).filter(svc -> serviceId.equals(svc.getMetadata().getName())) - .filter(scv -> matchesServiceLabels(scv, properties)).filter(filter).toList(); - return services.stream().flatMap(service -> getServiceInstanceDetails(service, serviceId)).toList(); - } - - private Stream getServiceInstanceDetails(V1Service service, String serviceId) { - Map serviceMetadata = serviceMetadata(properties, service, serviceId); - - List endpoints = endpointsListers.stream() - .map(endpointsLister -> endpointsLister.namespace(service.getMetadata().getNamespace()) - .get(service.getMetadata().getName())) - .filter(Objects::nonNull).filter(ep -> ep.getSubsets() != null).toList(); - - Optional discoveredPrimaryPortName = Optional.empty(); - if (service.getMetadata() != null && service.getMetadata().getLabels() != null) { - discoveredPrimaryPortName = Optional - .ofNullable(service.getMetadata().getLabels().get(PRIMARY_PORT_NAME_LABEL_KEY)); - } - final String primaryPortName = discoveredPrimaryPortName.orElse(properties.primaryPortName()); - - final boolean secured = isSecured(service); - - return endpoints.stream() - .flatMap(ep -> ep.getSubsets().stream() - .filter(subset -> subset.getPorts() != null && subset.getPorts().size() > 0) // safeguard - .flatMap(subset -> { - Map metadata = new HashMap<>(serviceMetadata); - List endpointPorts = subset.getPorts(); - if (properties.metadata() != null && properties.metadata().addPorts()) { - endpointPorts.forEach(p -> metadata.put( - StringUtils.hasText(p.getName()) ? p.getName() : UNSET_PORT_NAME, - Integer.toString(p.getPort()))); - } - List addresses = subset.getAddresses(); - if (addresses == null) { - addresses = new ArrayList<>(); - } - if (properties.includeNotReadyAddresses() - && !CollectionUtils.isEmpty(subset.getNotReadyAddresses())) { - addresses.addAll(subset.getNotReadyAddresses()); - } - - final int port = findEndpointPort(endpointPorts, primaryPortName, serviceId); - return addresses.stream() - .map(addr -> new DefaultKubernetesServiceInstance( - addr.getTargetRef() != null ? addr.getTargetRef().getUid() : "", serviceId, - addr.getIp(), port, metadata, secured, service.getMetadata().getNamespace(), - // TODO find out how to get cluster name - // possibly from - // KubeConfig - null)); - })); - } - - private static boolean isSecured(V1Service service) { - Optional securedOpt = Optional.empty(); - if (service.getMetadata() != null && service.getMetadata().getAnnotations() != null) { - securedOpt = Optional.ofNullable(service.getMetadata().getAnnotations().get(SECURED)); - } - if (!securedOpt.isPresent() && service.getMetadata() != null && service.getMetadata().getLabels() != null) { - securedOpt = Optional.ofNullable(service.getMetadata().getLabels().get(SECURED)); - } - return Boolean.parseBoolean(securedOpt.orElse("false")); - } - - private int findEndpointPort(List endpointPorts, String primaryPortName, String serviceId) { - if (endpointPorts.size() == 1) { - return endpointPorts.get(0).getPort(); - } - else { - Map ports = endpointPorts.stream().filter(p -> StringUtils.hasText(p.getName())) - .collect(Collectors.toMap(CoreV1EndpointPort::getName, CoreV1EndpointPort::getPort)); - // This oneliner is looking for a port with a name equal to the primary port - // name specified in the service label - // or in spring.cloud.kubernetes.discovery.primary-port-name, equal to https, - // or equal to http. - // In case no port has been found return -1 to log a warning and fall back to - // the first port in the list. - int discoveredPort = ports.getOrDefault(primaryPortName, - ports.getOrDefault(HTTPS, ports.getOrDefault(HTTP, -1))); - - if (discoveredPort == -1) { - if (StringUtils.hasText(primaryPortName)) { - LOG.warn(() -> "Could not find a port named '" + primaryPortName - + "', 'https', or 'http' for service '" + serviceId + "'."); - } - else { - LOG.warn(() -> "Could not find a port named 'https' or 'http' for service '" + serviceId + "'."); - } - LOG.warn( - () -> "Make sure that either the primary-port-name label has been added to the service, or that spring.cloud.kubernetes.discovery.primary-port-name has been configured."); - LOG.warn(() -> "Alternatively name the primary port 'https' or 'http'"); - LOG.warn(() -> "An incorrect configuration may result in non-deterministic behaviour."); - discoveredPort = endpointPorts.get(0).getPort(); - } - return discoveredPort; - } - } - - @Override - public List getServices() { - List services = serviceListers.stream().flatMap(serviceLister -> serviceLister.list().stream()) - .filter(service -> matchesServiceLabels(service, properties)).filter(filter) - .map(s -> s.getMetadata().getName()).distinct().toList(); - LOG.debug(() -> "will return services : " + services); - return services; - } - - @PostConstruct - public void afterPropertiesSet() { - postConstruct(sharedInformerFactories, properties, informersReadyFunc, serviceListers); - } - - @Override - public int getOrder() { - return properties.order(); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfiguration.java deleted file mode 100644 index 57341b29b9..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfiguration.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.List; - -import io.kubernetes.client.informer.SharedInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1Service; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.client.CommonsClientAutoConfiguration; -import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled; -import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.client.ConditionalOnDiscoveryHealthIndicatorEnabled; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.PodUtils; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; - -/** - * @author wind57 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesDiscoveryEnabled -@ConditionalOnBlockingDiscoveryEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) -@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesClientInformerAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class }) -public class KubernetesInformerDiscoveryClientAutoConfiguration { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesInformerDiscoveryClientAutoConfiguration.class)); - - @Deprecated(forRemoval = true) - public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient( - KubernetesNamespaceProvider kubernetesNamespaceProvider, SharedInformerFactory sharedInformerFactory, - Lister serviceLister, Lister endpointsLister, - SharedInformer serviceInformer, SharedInformer endpointsInformer, - KubernetesDiscoveryProperties properties) { - return new KubernetesInformerDiscoveryClient(kubernetesNamespaceProvider.getNamespace(), sharedInformerFactory, - serviceLister, endpointsLister, serviceInformer, endpointsInformer, properties); - } - - /** - * Creation of this bean triggers publishing an InstanceRegisteredEvent. In turn, - * there is the CommonsClientAutoConfiguration::DiscoveryClientHealthIndicator, that - * implements 'ApplicationListener' that will catch this event. It also registers a - * bean of type DiscoveryClientHealthIndicator via ObjectProvider. - */ - @Bean - @ConditionalOnClass({ HealthIndicator.class }) - @ConditionalOnDiscoveryHealthIndicatorEnabled - public KubernetesDiscoveryClientHealthIndicatorInitializer indicatorInitializer( - ApplicationEventPublisher applicationEventPublisher, PodUtils podUtils) { - LOG.debug(() -> "Will publish InstanceRegisteredEvent from blocking implementation"); - return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher); - } - - @Bean - @ConditionalOnMissingBean - @Conditional(ConditionalOnSelectiveNamespacesMissing.class) - KubernetesInformerDiscoveryClient kubernetesClientInformerDiscoveryClient( - SharedInformerFactory sharedInformerFactory, Lister serviceLister, - Lister endpointsLister, SharedInformer serviceInformer, - SharedInformer endpointsInformer, KubernetesDiscoveryProperties properties) { - return new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, - serviceInformer, endpointsInformer, properties); - } - - @Bean - @ConditionalOnMissingBean - @Conditional(ConditionalOnSelectiveNamespacesPresent.class) - KubernetesInformerDiscoveryClient selectiveNamespacesKubernetesInformerDiscoveryClient( - List sharedInformerFactories, List> serviceListers, - List> endpointsListers, List> serviceInformers, - List> endpointsInformers, KubernetesDiscoveryProperties properties) { - return new KubernetesInformerDiscoveryClient(sharedInformerFactories, serviceListers, endpointsListers, - serviceInformers, endpointsInformers, properties); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatch.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatch.java deleted file mode 100644 index 2a3d5d44fb..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatch.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.List; -import java.util.function.Function; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.apis.CustomObjectsApi; -import io.kubernetes.client.openapi.models.V1APIResource; -import jakarta.annotation.PostConstruct; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.client.discovery.event.HeartbeatEvent; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; -import org.springframework.core.log.LogAccessor; -import org.springframework.scheduling.annotation.Scheduled; - -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.DISCOVERY_GROUP; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.DISCOVERY_VERSION; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.ENDPOINT_SLICE; - -/** - * Catalog watch implementation for kubernetes native client. - * - * @author wind57 - */ -class KubernetesCatalogWatch implements ApplicationEventPublisherAware { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesCatalogWatch.class)); - - private final KubernetesCatalogWatchContext context; - - private Function> stateGenerator; - - private volatile List catalogEndpointsState = null; - - private ApplicationEventPublisher publisher; - - KubernetesCatalogWatch(CoreV1Api coreV1Api, ApiClient apiClient, KubernetesDiscoveryProperties properties, - KubernetesNamespaceProvider namespaceProvider) { - context = new KubernetesCatalogWatchContext(coreV1Api, apiClient, properties, namespaceProvider); - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { - this.publisher = publisher; - } - - @Scheduled(fixedDelayString = "${spring.cloud.kubernetes.discovery.catalogServicesWatchDelay:30000}") - void catalogServicesWatch() { - try { - - List currentState = stateGenerator.apply(context); - - if (!currentState.equals(catalogEndpointsState)) { - LOG.debug(() -> "Received endpoints update from kubernetesClient: " + currentState); - publisher.publishEvent(new HeartbeatEvent(this, currentState)); - } - - catalogEndpointsState = currentState; - } - catch (Exception e) { - LOG.error(e, () -> "Error watching Kubernetes Services"); - } - } - - @PostConstruct - void postConstruct() { - stateGenerator = stateGenerator(); - } - - Function> stateGenerator() { - - Function> localStateGenerator; - - if (context.properties().useEndpointSlices()) { - // this emulates : 'kubectl api-resources | grep -i EndpointSlice' - ApiClient apiClient = context.apiClient(); - CustomObjectsApi customObjectsApi = new CustomObjectsApi(apiClient); - try { - List resources = customObjectsApi.getAPIResources(DISCOVERY_GROUP, DISCOVERY_VERSION) - .getResources(); - boolean found = resources.stream().map(V1APIResource::getKind).anyMatch(ENDPOINT_SLICE::equals); - if (!found) { - throw new IllegalArgumentException("EndpointSlices are not supported on the cluster"); - } - else { - localStateGenerator = new KubernetesEndpointSlicesCatalogWatch(); - } - } - catch (ApiException e) { - throw new RuntimeException(e); - } - - } - else { - localStateGenerator = new KubernetesEndpointsCatalogWatch(); - } - - LOG.debug(() -> "stateGenerator is of type: " + localStateGenerator.getClass().getSimpleName()); - - return localStateGenerator; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfiguration.java deleted file mode 100644 index c1b1e8cd10..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfiguration.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -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.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesCatalogEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; - -/** - * Auto configuration for catalog watcher. - * - * @author wind57 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesCatalogEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class }) -class KubernetesCatalogWatchAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - KubernetesCatalogWatch kubernetesCatalogWatch(CoreV1Api coreV1Api, ApiClient apiClient, - KubernetesDiscoveryProperties properties, Environment environment) { - return new KubernetesCatalogWatch(coreV1Api, apiClient, properties, - new KubernetesNamespaceProvider(environment)); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContext.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContext.java deleted file mode 100644 index 215931cac3..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContext.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012-2023 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.discovery.catalog; - -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectReference; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -/** - * A simple holder for some instances needed for either Endpoints or EndpointSlice catalog - * implementations. - * - * @author wind57 - */ -record KubernetesCatalogWatchContext(CoreV1Api coreV1Api, ApiClient apiClient, KubernetesDiscoveryProperties properties, - KubernetesNamespaceProvider namespaceProvider) { - - static List state(Stream references) { - return references.filter(Objects::nonNull).map(x -> new EndpointNameAndNamespace(x.getName(), x.getNamespace())) - .sorted(Comparator.comparing(EndpointNameAndNamespace::endpointName, String::compareTo)).toList(); - } - - static String labelSelector(Map labels) { - return labels.entrySet().stream().map(en -> en.getKey() + "=" + en.getValue()).collect(Collectors.joining("&")); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointSlicesCatalogWatch.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointSlicesCatalogWatch.java deleted file mode 100644 index 46deca3d1a..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointSlicesCatalogWatch.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2012-2023 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.discovery.catalog; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Stream; - -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.DiscoveryV1Api; -import io.kubernetes.client.openapi.models.V1Endpoint; -import io.kubernetes.client.openapi.models.V1EndpointSlice; -import io.kubernetes.client.openapi.models.V1ObjectReference; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.core.log.LogAccessor; - -import static org.springframework.cloud.kubernetes.client.discovery.catalog.KubernetesCatalogWatchContext.labelSelector; - -/** - * Implementation that is based on EndpointSlice V1. - * - * @author wind57 - */ -final class KubernetesEndpointSlicesCatalogWatch - implements Function> { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesEndpointSlicesCatalogWatch.class)); - - @Override - public List apply(KubernetesCatalogWatchContext context) { - - List endpointSlices; - DiscoveryV1Api api = new DiscoveryV1Api(context.apiClient()); - - if (context.properties().allNamespaces()) { - LOG.debug(() -> "discovering endpoint slices in all namespaces"); - endpointSlices = endpointSlices(api, context.properties().serviceLabels()); - } - else if (!context.properties().namespaces().isEmpty()) { - LOG.debug(() -> "discovering endpoint slices in " + context.properties().namespaces()); - List inner = new ArrayList<>(context.properties().namespaces().size()); - context.properties().namespaces().forEach(namespace -> inner - .addAll(namespacedEndpointSlices(api, namespace, context.properties().serviceLabels()))); - endpointSlices = inner; - } - else { - String namespace = KubernetesClientUtils.getApplicationNamespace(null, "catalog-watch", - context.namespaceProvider()); - LOG.debug(() -> "discovering endpoint slices in namespace : " + namespace); - endpointSlices = namespacedEndpointSlices(api, namespace, context.properties().serviceLabels()); - } - - Stream references = endpointSlices.stream().map(V1EndpointSlice::getEndpoints) - .flatMap(List::stream).map(V1Endpoint::getTargetRef); - - return KubernetesCatalogWatchContext.state(references); - - } - - private List endpointSlices(DiscoveryV1Api api, Map labels) { - try { - return api.listEndpointSliceForAllNamespaces(null, null, null, labelSelector(labels), null, null, null, - null, null, null).getItems(); - } - catch (ApiException e) { - LOG.warn(e, () -> "can not list endpoint slices in all namespaces"); - return Collections.emptyList(); - } - } - - private List namespacedEndpointSlices(DiscoveryV1Api api, String namespace, - Map labels) { - try { - return api.listNamespacedEndpointSlice(namespace, null, null, null, null, labelSelector(labels), null, null, - null, null, null).getItems(); - } - catch (ApiException e) { - LOG.warn(e, () -> "can not list endpoint slices in namespace " + namespace); - return Collections.emptyList(); - } - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsCatalogWatch.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsCatalogWatch.java deleted file mode 100644 index 3409e58d19..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsCatalogWatch.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2012-2023 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.discovery.catalog; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Stream; - -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1EndpointAddress; -import io.kubernetes.client.openapi.models.V1EndpointSubset; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1ObjectReference; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.core.log.LogAccessor; - -import static org.springframework.cloud.kubernetes.client.discovery.catalog.KubernetesCatalogWatchContext.labelSelector; - -/** - * Implementation that is based on V1Endpoints. - * - * @author wind57 - */ -final class KubernetesEndpointsCatalogWatch - implements Function> { - - private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesEndpointsCatalogWatch.class)); - - @Override - public List apply(KubernetesCatalogWatchContext context) { - List endpoints; - CoreV1Api coreV1Api = context.coreV1Api(); - if (context.properties().allNamespaces()) { - LOG.debug(() -> "discovering endpoints in all namespaces"); - endpoints = endpoints(coreV1Api, context.properties().serviceLabels()); - } - else if (!context.properties().namespaces().isEmpty()) { - LOG.debug(() -> "discovering endpoints in " + context.properties().namespaces()); - List inner = new ArrayList<>(context.properties().namespaces().size()); - context.properties().namespaces().forEach(namespace -> inner - .addAll(namespacedEndpoints(coreV1Api, namespace, context.properties().serviceLabels()))); - endpoints = inner; - } - else { - String namespace = KubernetesClientUtils.getApplicationNamespace(null, "catalog-watch", - context.namespaceProvider()); - LOG.debug(() -> "discovering endpoints in namespace : " + namespace); - endpoints = namespacedEndpoints(coreV1Api, namespace, context.properties().serviceLabels()); - } - - /** - *
-		 *   - An "V1Endpoints" holds a List of V1EndpointSubset.
-		 *   - A single V1EndpointSubset holds a List of V1EndpointAddress
-		 *
-		 *   - (The union of all V1EndpointSubsets is the Set of all V1Endpoints)
-		 *   - Set of V1Endpoints is the cartesian product of :
-		 *     V1EndpointSubset::getAddresses and V1EndpointSubset::getPorts (each is a List)
-		 * 
- */ - Stream references = endpoints.stream().map(V1Endpoints::getSubsets).filter(Objects::nonNull) - .flatMap(List::stream).map(V1EndpointSubset::getAddresses).filter(Objects::nonNull) - .flatMap(List::stream).map(V1EndpointAddress::getTargetRef); - - return KubernetesCatalogWatchContext.state(references); - - } - - private List endpoints(CoreV1Api client, Map labels) { - try { - return client.listEndpointsForAllNamespaces(null, null, null, labelSelector(labels), null, null, null, null, - null, null).getItems(); - } - catch (ApiException e) { - LOG.warn(e, () -> "can not list endpoints in all namespaces"); - return Collections.emptyList(); - } - } - - private List namespacedEndpoints(CoreV1Api client, String namespace, Map labels) { - try { - return client.listNamespacedEndpoints(namespace, null, null, null, null, labelSelector(labels), null, null, - null, null, null).getItems(); - } - catch (ApiException e) { - LOG.warn(e, () -> "can not list endpoints in namespace " + namespace); - return Collections.emptyList(); - } - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClient.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClient.java deleted file mode 100644 index 13248a2a5e..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClient.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2019-2023 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.discovery.reactive; - -import java.util.Objects; - -import io.kubernetes.client.informer.SharedInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1Service; -import reactor.core.publisher.Flux; -import reactor.core.scheduler.Schedulers; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -/** - * @author Ryan Baxter - */ -public class KubernetesInformerReactiveDiscoveryClient implements ReactiveDiscoveryClient { - - private final KubernetesInformerDiscoveryClient kubernetesDiscoveryClient; - - @Deprecated(forRemoval = true) - public KubernetesInformerReactiveDiscoveryClient(KubernetesNamespaceProvider kubernetesNamespaceProvider, - SharedInformerFactory sharedInformerFactory, Lister serviceLister, - Lister endpointsLister, SharedInformer serviceInformer, - SharedInformer endpointsInformer, KubernetesDiscoveryProperties properties) { - this.kubernetesDiscoveryClient = new KubernetesInformerDiscoveryClient( - kubernetesNamespaceProvider.getNamespace(), sharedInformerFactory, serviceLister, endpointsLister, - serviceInformer, endpointsInformer, properties); - } - - // this is either kubernetesClientInformerDiscoveryClient - // or selectiveNamespacesKubernetesClientInformerDiscoveryClient - KubernetesInformerReactiveDiscoveryClient(KubernetesInformerDiscoveryClient kubernetesDiscoveryClient) { - this.kubernetesDiscoveryClient = kubernetesDiscoveryClient; - } - - @Override - public String description() { - return "Kubernetes Reactive Discovery Client"; - } - - @Override - public Flux getInstances(String serviceId) { - Objects.requireNonNull(serviceId, "serviceId must be provided"); - return Flux.defer(() -> Flux.fromIterable(kubernetesDiscoveryClient.getInstances(serviceId))) - .subscribeOn(Schedulers.boundedElastic()); - } - - @Override - public Flux getServices() { - return Flux.defer(() -> Flux.fromIterable(kubernetesDiscoveryClient.getServices())) - .subscribeOn(Schedulers.boundedElastic()); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfiguration.java deleted file mode 100644 index 62f7393912..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfiguration.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2019-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.discovery.reactive; - -import java.util.List; - -import io.kubernetes.client.informer.SharedInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1Service; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; -import org.springframework.cloud.client.ConditionalOnDiscoveryHealthIndicatorEnabled; -import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled; -import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration; -import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration; -import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; -import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicatorProperties; -import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator; -import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientPodUtils; -import org.springframework.cloud.kubernetes.client.discovery.ConditionalOnSelectiveNamespacesMissing; -import org.springframework.cloud.kubernetes.client.discovery.ConditionalOnSelectiveNamespacesPresent; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerSelectiveNamespacesAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.PodUtils; -import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; - -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer.RegisteredEventSource; - -/** - * @author Ryan Baxter - */ - -@Configuration(proxyBeanMethods = false) -@ConditionalOnDiscoveryEnabled -@ConditionalOnKubernetesDiscoveryEnabled -@ConditionalOnReactiveDiscoveryEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@AutoConfigureBefore({ SimpleReactiveDiscoveryClientAutoConfiguration.class, - ReactiveCommonsClientAutoConfiguration.class }) -@AutoConfigureAfter({ ReactiveCompositeDiscoveryClientAutoConfiguration.class, - KubernetesDiscoveryPropertiesAutoConfiguration.class, KubernetesClientInformerAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class }) -public class KubernetesInformerReactiveDiscoveryClientAutoConfiguration { - - private static final LogAccessor LOG = new LogAccessor( - LogFactory.getLog(KubernetesInformerReactiveDiscoveryClientAutoConfiguration.class)); - - @Deprecated(forRemoval = true) - public ReactiveDiscoveryClientHealthIndicator kubernetesReactiveDiscoveryClientHealthIndicator( - KubernetesInformerReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties, - KubernetesClientPodUtils podUtils) { - ReactiveDiscoveryClientHealthIndicator healthIndicator = new ReactiveDiscoveryClientHealthIndicator(client, - properties); - InstanceRegisteredEvent event = new InstanceRegisteredEvent<>( - new RegisteredEventSource("kubernetes", podUtils.isInsideKubernetes(), podUtils.currentPod().get()), - null); - healthIndicator.onApplicationEvent(event); - return healthIndicator; - } - - @Deprecated(forRemoval = true) - public KubernetesInformerReactiveDiscoveryClient kubernetesReactiveDiscoveryClient( - KubernetesNamespaceProvider kubernetesNamespaceProvider, SharedInformerFactory sharedInformerFactory, - Lister serviceLister, Lister endpointsLister, - SharedInformer serviceInformer, SharedInformer endpointsInformer, - KubernetesDiscoveryProperties properties) { - return new KubernetesInformerReactiveDiscoveryClient(kubernetesNamespaceProvider, sharedInformerFactory, - serviceLister, endpointsLister, serviceInformer, endpointsInformer, properties); - } - - /** - * Post an event so that health indicator is initialized. - */ - @Bean - @ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator") - @ConditionalOnDiscoveryHealthIndicatorEnabled - KubernetesDiscoveryClientHealthIndicatorInitializer reactiveIndicatorInitializer( - ApplicationEventPublisher applicationEventPublisher, PodUtils podUtils) { - LOG.debug(() -> "Will publish InstanceRegisteredEvent from reactive implementation"); - return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher); - } - - /** - * unlike the blocking implementation, we need to register the health indicator. - */ - @Bean - @ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator") - @ConditionalOnDiscoveryHealthIndicatorEnabled - ReactiveDiscoveryClientHealthIndicator kubernetesReactiveDiscoveryClientHealthIndicator( - KubernetesInformerReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties) { - return new ReactiveDiscoveryClientHealthIndicator(client, properties); - } - - @Bean - @ConditionalOnMissingBean - KubernetesInformerReactiveDiscoveryClient kubernetesClientReactiveDiscoveryClient( - KubernetesInformerDiscoveryClient kubernetesClientInformerDiscoveryClient) { - return new KubernetesInformerReactiveDiscoveryClient(kubernetesClientInformerDiscoveryClient); - } - - @Bean - @ConditionalOnMissingBean - @Conditional(ConditionalOnSelectiveNamespacesMissing.class) - KubernetesInformerDiscoveryClient kubernetesClientInformerDiscoveryClient( - SharedInformerFactory sharedInformerFactory, Lister serviceLister, - Lister endpointsLister, SharedInformer serviceInformer, - SharedInformer endpointsInformer, KubernetesDiscoveryProperties properties) { - return new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, - serviceInformer, endpointsInformer, properties); - } - - @Bean - @ConditionalOnMissingBean - @Conditional(ConditionalOnSelectiveNamespacesPresent.class) - KubernetesInformerDiscoveryClient selectiveNamespacesKubernetesClientInformerDiscoveryClient( - List sharedInformerFactories, List> serviceListers, - List> endpointsListers, List> serviceInformers, - List> endpointsInformers, KubernetesDiscoveryProperties properties) { - return new KubernetesInformerDiscoveryClient(sharedInformerFactories, serviceListers, endpointsListers, - serviceInformers, endpointsInformers, properties); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring.factories deleted file mode 100644 index f1630371f1..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,6 +0,0 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientConfigClientBootstrapConfiguration - -org.springframework.boot.BootstrapRegistryInitializer=\ -org.springframework.cloud.kubernetes.client.discovery.KubernetesClientConfigServerBootstrapper - diff --git a/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index a2e5e61352..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,5 +0,0 @@ -org.springframework.cloud.kubernetes.client.discovery.catalog.KubernetesCatalogWatchAutoConfiguration -org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClientAutoConfiguration -org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerAutoConfiguration -org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClientAutoConfiguration -org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerSelectiveNamespacesAutoConfiguration diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesDisabledTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesDisabledTests.java deleted file mode 100644 index 0f3b8a3085..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesDisabledTests.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.context.annotation.ConditionContext; -import org.springframework.mock.env.MockEnvironment; - -/** - * @author wind57 - */ - -public class ConditionalOnSelectiveNamespacesDisabledTests { - - private static final ConditionalOnSelectiveNamespacesMissing TO_TEST = new ConditionalOnSelectiveNamespacesMissing(); - - private static final ConditionContext CONDITION_CONTEXT = Mockito.mock(ConditionContext.class); - - @Test - void testSelectiveNamespacesNotPresent() { - MockEnvironment environment = new MockEnvironment(); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertTrue(result); - } - - @Test - void testSelectiveNamespacesPresentEmpty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.discovery.namespaces", ""); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertTrue(result); - } - - @Test - void testSelectiveNamespacesPresentNonEmpty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.discovery.namespaces", "default"); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertFalse(result); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesEnabledTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesEnabledTests.java deleted file mode 100644 index 69f79fb234..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesEnabledTests.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.context.annotation.ConditionContext; -import org.springframework.mock.env.MockEnvironment; - -/** - * @author wind57 - */ -class ConditionalOnSelectiveNamespacesEnabledTests { - - private static final ConditionalOnSelectiveNamespacesPresent TO_TEST = new ConditionalOnSelectiveNamespacesPresent(); - - private static final ConditionContext CONDITION_CONTEXT = Mockito.mock(ConditionContext.class); - - @Test - void testSelectiveNamespacesNotPresent() { - MockEnvironment environment = new MockEnvironment(); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertFalse(result); - } - - @Test - void testSelectiveNamespacesPresentEmpty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.discovery.namespaces", ""); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertFalse(result); - } - - @Test - void testSelectiveNamespacesPresentNonEmpty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("spring.cloud.kubernetes.discovery.namespaces", "default"); - Mockito.when(CONDITION_CONTEXT.getEnvironment()).thenReturn(environment); - boolean result = TO_TEST.matches(CONDITION_CONTEXT, null); - Assertions.assertTrue(result); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapperTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapperTests.java deleted file mode 100644 index a3cfbf68d4..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientConfigServerBootstrapperTests.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2019-2023 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.discovery; - -import java.time.Duration; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.CoreV1EndpointPort; -import io.kubernetes.client.openapi.models.V1EndpointAddress; -import io.kubernetes.client.openapi.models.V1EndpointSubset; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1EndpointsListBuilder; -import io.kubernetes.client.openapi.models.V1ListMetaBuilder; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1ObjectReferenceBuilder; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.openapi.models.V1ServiceListBuilder; -import io.kubernetes.client.openapi.models.V1ServicePortBuilder; -import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.config.environment.Environment; -import org.springframework.cloud.config.environment.PropertySource; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -/** - * @author Ryan Baxter - */ -class KubernetesClientConfigServerBootstrapperTests { - - private static WireMockServer wireMockServer; - - private ConfigurableApplicationContext context; - - @BeforeEach - public void before() throws JsonProcessingException { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - V1ServiceList SERVICE_LIST = new V1ServiceListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("1").build()) - .addToItems(new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("spring-cloud-kubernetes-configserver") - .withNamespace("default").withResourceVersion("0").addToLabels("beta", "true") - .addToAnnotations("org.springframework.cloud", "true").withUid("0").build()) - .withSpec(new V1ServiceSpecBuilder().withClusterIP("localhost").withSessionAffinity("None") - .withType("ClusterIP") - .addToPorts(new V1ServicePortBuilder().withPort(wireMockServer.port()).withName("http") - .withProtocol("TCP").withNewTargetPort(wireMockServer.port()).build()) - .build()) - .build()) - .build(); - - V1EndpointsList ENDPOINTS_LIST = new V1EndpointsListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()) - .addToItems(new V1Endpoints() - .metadata(new V1ObjectMeta().name("spring-cloud-kubernetes-configserver").namespace("default")) - .addSubsetsItem( - new V1EndpointSubset() - .addPortsItem(new CoreV1EndpointPort().port(wireMockServer.port()).name("http")) - .addAddressesItem(new V1EndpointAddress().hostname("localhost").ip("localhost") - .targetRef(new V1ObjectReferenceBuilder().withUid("uid1").build())))) - .build(); - - Environment environment = new Environment("test", "default"); - Map properties = new HashMap<>(); - properties.put("hello", "world"); - org.springframework.cloud.config.environment.PropertySource p = new PropertySource("p1", properties); - environment.add(p); - ObjectMapper objectMapper = new ObjectMapper(); - stubFor(get("/application/default") - .willReturn(aResponse().withStatus(200).withBody(objectMapper.writeValueAsString(environment)) - .withHeader("content-type", "application/json"))); - stubFor(get("/api/v1/namespaces/default/endpoints?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(ENDPOINTS_LIST)) - .withHeader("content-type", "application/json"))); - stubFor(get("/api/v1/namespaces/default/services?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SERVICE_LIST)) - .withHeader("content-type", "application/json"))); - stubFor(get(urlMatching("/api/v1/namespaces/default/services.*.watch=true")) - .willReturn(aResponse().withStatus(200))); - stubFor(get(urlMatching("/api/v1/namespaces/default/endpoints.*.watch=true")) - .willReturn(aResponse().withStatus(200))); - } - - @AfterEach - public void after() { - wireMockServer.stop(); - context.close(); - } - - @Test - void testBootstrapper() { - this.context = setup().run(); - verify(getRequestedFor(urlEqualTo("/application/default"))); - assertThat(this.context.getEnvironment().getProperty("hello")).isEqualTo("world"); - } - - SpringApplicationBuilder setup(String... env) { - SpringApplicationBuilder builder = new SpringApplicationBuilder(TestConfig.class) - .properties(addDefaultEnv(env)); - ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()) - .setReadTimeout(Duration.ZERO).build(); - builder.addBootstrapRegistryInitializer(registry -> registry.register(ApiClient.class, (context) -> apiClient)); - builder.addBootstrapRegistryInitializer(new KubernetesClientConfigServerBootstrapper()); - return builder; - } - - private String[] addDefaultEnv(String[] env) { - Set set = new LinkedHashSet<>(); - if (env != null && env.length > 0) { - set.addAll(Arrays.asList(env)); - } - set.add("server.port=0"); - set.add("spring.cloud.config.discovery.enabled=true"); - set.add("spring.config.import=optional:configserver:"); - set.add("spring.cloud.config.discovery.service-id=spring-cloud-kubernetes-configserver"); - set.add("spring.cloud.kubernetes.client.namespace=default"); - return set.toArray(new String[0]); - } - - @SpringBootConfiguration - @EnableAutoConfiguration - static class TestConfig { - - @Bean - public ApiClient apiClient() { - return new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientAutoConfigurationTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientAutoConfigurationTests.java deleted file mode 100644 index f3405ac95f..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientAutoConfigurationTests.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.discovery; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1EndpointsListBuilder; -import io.kubernetes.client.openapi.models.V1ListMetaBuilder; -import io.kubernetes.client.openapi.models.V1ServiceListBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.context.annotation.Bean; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.discovery.cacheLoadingTimeoutSeconds=5", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.waitCacheReady=false" }) -class KubernetesDiscoveryClientAutoConfigurationTests { - - @Autowired - private DiscoveryClient discoveryClient; - - private static WireMockServer wireMockServer; - - @AfterAll - static void after() { - wireMockServer.stop(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @Test - void kubernetesDiscoveryClientCreated() { - assertThat(this.discoveryClient).isNotNull().isInstanceOf(CompositeDiscoveryClient.class); - - CompositeDiscoveryClient composite = (CompositeDiscoveryClient) this.discoveryClient; - assertThat(composite.getDiscoveryClients().stream() - .anyMatch(dc -> dc instanceof KubernetesInformerDiscoveryClient)).isTrue(); - } - - @SpringBootApplication - protected static class TestConfig { - - @Bean - KubernetesNamespaceProvider kubernetesNamespaceProvider() { - KubernetesNamespaceProvider provider = mock(KubernetesNamespaceProvider.class); - when(provider.getNamespace()).thenReturn("test"); - return provider; - } - - @Bean - ApiClient apiClient() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - stubFor(get("/api/v1/namespaces/test/endpoints?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1EndpointsListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()).build())))); - stubFor(get("/api/v1/namespaces/test/services?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ServiceListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()).build())))); - return new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests.java deleted file mode 100644 index 312f396fc0..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.discovery; - -import java.util.Collections; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import okhttp3.OkHttpClient; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.commons.util.UtilAutoConfiguration; -import org.springframework.cloud.config.client.ConfigClientProperties; -import org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests { - - private AnnotationConfigApplicationContext context; - - @AfterEach - void close() { - if (this.context != null) { - if (this.context.getParent() != null) { - ((AnnotationConfigApplicationContext) this.context.getParent()).close(); - } - this.context.close(); - } - } - - @Test - void onWhenRequested() { - setup("server.port=7000", "spring.cloud.config.discovery.enabled=true", - "spring.cloud.kubernetes.discovery.enabled:true", "spring.application.name:test", - "spring.cloud.config.discovery.service-id:configserver"); - Assertions.assertEquals(1, this.context.getParent().getBeanNamesForType(DiscoveryClient.class).length); - - DiscoveryClient client = this.context.getParent().getBean(DiscoveryClient.class); - verify(client, atLeast(2)).getInstances("configserver"); - ConfigClientProperties locator = this.context.getBean(ConfigClientProperties.class); - Assertions.assertEquals("http://fake:8888/", locator.getUri()[0]); - } - - private void setup(String... env) { - AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); - TestPropertyValues.of(env).applyTo(parent); - parent.register(UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - EnvironmentKnobbler.class, KubernetesCommonsAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, KubernetesInformerDiscoveryClientAutoConfiguration.class, - DiscoveryClientConfigServiceBootstrapConfiguration.class, ConfigClientProperties.class); - parent.refresh(); - this.context = new AnnotationConfigApplicationContext(); - this.context.setParent(parent); - this.context.register(PropertyPlaceholderAutoConfiguration.class, KubernetesCommonsAutoConfiguration.class, - KubernetesInformerDiscoveryClientAutoConfiguration.class); - this.context.refresh(); - } - - @Configuration(proxyBeanMethods = false) - protected static class EnvironmentKnobbler { - - @Bean - ApiClient apiClient() { - ApiClient apiClient = mock(ApiClient.class); - when(apiClient.getJSON()).thenReturn(new JSON()); - when(apiClient.getHttpClient()).thenReturn(new OkHttpClient.Builder().build()); - return apiClient; - } - - @Bean - KubernetesNamespaceProvider kubernetesNamespaceProvider() { - KubernetesNamespaceProvider provider = mock(KubernetesNamespaceProvider.class); - when(provider.getNamespace()).thenReturn("test"); - return provider; - } - - @Bean - KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient() { - KubernetesInformerDiscoveryClient client = mock(KubernetesInformerDiscoveryClient.class); - ServiceInstance instance = new DefaultServiceInstance("configserver1", "configserver", "fake", 8888, false); - given(client.getInstances("configserver")).willReturn(Collections.singletonList(instance)); - return client; - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientFilterTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientFilterTests.java deleted file mode 100644 index f730894004..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientFilterTests.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; - -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class KubernetesDiscoveryClientFilterTests { - - @Test - void testEmptyExpression(CapturedOutput output) { - - String spelFilter = null; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, null, 0, false); - - Predicate predicate = KubernetesDiscoveryClientUtils.filter(properties); - Assertions.assertNotNull(predicate); - Assertions.assertTrue(output.getOut().contains("filter not defined, returning always true predicate")); - } - - @Test - void testExpressionPresent(CapturedOutput output) { - - String spelFilter = "some"; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, null, 0, false); - - Predicate predicate = KubernetesDiscoveryClientUtils.filter(properties); - Assertions.assertNotNull(predicate); - Assertions.assertTrue(output.getOut().contains("returning predicate based on filter expression: some")); - } - - @Test - void testTwoServicesBothMatch() { - String spelFilter = """ - #root.metadata.namespace matches "^.+A$" - """; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, null, 0, false); - - V1Service a = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-A").withName("a").and().build(); - - V1Service b = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-A").withName("a").and().build(); - - List unfiltered = List.of(a, b); - Predicate predicate = KubernetesDiscoveryClientUtils.filter(properties); - List filtered = unfiltered.stream().filter(predicate) - .sorted(Comparator.comparing(service -> service.getMetadata().getName())).toList(); - Assertions.assertEquals(filtered.get(0).getMetadata().getName(), "a"); - Assertions.assertEquals(filtered.get(1).getMetadata().getName(), "a"); - } - - @Test - void testTwoServicesNoneMatch() { - String spelFilter = """ - #root.metadata.namespace matches "^.+A$" - """; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, null, 0, false); - - V1Service a = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-B").withName("a").and().build(); - - V1Service b = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-B").withName("a").and().build(); - - List unfiltered = List.of(a, b); - Predicate predicate = KubernetesDiscoveryClientUtils.filter(properties); - List filtered = unfiltered.stream().filter(predicate) - .sorted(Comparator.comparing(service -> service.getMetadata().getName())).toList(); - Assertions.assertEquals(filtered.size(), 0); - } - - @Test - void testTwoServicesOneMatch() { - String spelFilter = """ - #root.metadata.namespace matches "^.+A$" - """; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, null, 0, false); - - V1Service a = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-B").withName("a").and().build(); - - V1Service b = new V1ServiceBuilder().withNewMetadata().withNamespace("namespace-B").withName("a").and().build(); - - List unfiltered = List.of(a, b); - Predicate predicate = KubernetesDiscoveryClientUtils.filter(properties); - List filtered = unfiltered.stream().filter(predicate) - .sorted(Comparator.comparing(service -> service.getMetadata().getName())).toList(); - Assertions.assertEquals(filtered.size(), 0); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientServiceMetadataTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientServiceMetadataTests.java deleted file mode 100644 index 5d6b904aa1..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientServiceMetadataTests.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceSpec; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class KubernetesDiscoveryClientServiceMetadataTests { - - /** - *
-	 *     - labels are not added
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataEmpty() { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) - .metadata(new V1ObjectMeta().namespace("default")); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 2); - Assertions.assertEquals(result, Map.of("k8s_namespace", "default", "type", "ClusterIP")); - } - - /** - *
-	 *     - labels are added without a prefix
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsNoPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) - .metadata(new V1ObjectMeta().namespace("default").labels(Map.of("a", "b"))); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 3); - Assertions.assertEquals(result, Map.of("a", "b", "k8s_namespace", "default", "type", "ClusterIP")); - String labelsMetadata = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are added with prefix
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsWithPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = "prefix-"; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) - .metadata(new V1ObjectMeta().namespace("default").labels(Map.of("a", "b", "c", "d"))); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 4); - Assertions.assertEquals(result, - Map.of("prefix-a", "b", "prefix-c", "d", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String labelsMetadata = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are not added
-	 *     - annotations are added without prefix
-	 * 
- */ - @Test - void testServiceMetadataAddAnnotationsNoPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = true; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata( - new V1ObjectMeta().namespace("default").labels(Map.of("a", "b")).annotations(Map.of("aa", "bb"))); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 3); - Assertions.assertEquals(result, Map.of("aa", "bb", "k8s_namespace", "default", "type", "ClusterIP")); - Assertions - .assertTrue(output.getOut().contains("Adding annotations metadata: {aa=bb} for serviceId: my-service")); - } - - /** - *
-	 *     - labels are not added
-	 *     - annotations are added with prefix
-	 * 
- */ - @Test - void testServiceMetadataAddAnnotationsWithPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = true; - String annotationsPrefix = "prefix-"; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata(new V1ObjectMeta() - .namespace("default").labels(Map.of("a", "b")).annotations(Map.of("aa", "bb", "cc", "dd"))); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 4); - Assertions.assertEquals(result, - Map.of("prefix-aa", "bb", "prefix-cc", "dd", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String annotations = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are added with prefix
-	 *     - annotations are added with prefix
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsAndAnnotationsWithPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = "label-"; - boolean addAnnotations = true; - String annotationsPrefix = "annotation-"; - boolean addPorts = false; - String portsPrefix = ""; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata(new V1ObjectMeta() - .namespace("default").labels(Map.of("a", "b", "c", "d")).annotations(Map.of("aa", "bb", "cc", "dd"))); - - Map result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); - Assertions.assertEquals(result.size(), 6); - Assertions.assertEquals(result, Map.of("annotation-aa", "bb", "annotation-cc", "dd", "label-a", "b", "label-c", - "d", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String labels = result.entrySet().stream().filter(en -> en.getKey().contains("label")) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); - String annotations = result.entrySet().stream().filter(en -> en.getKey().contains("annotation")) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labels + " for serviceId: my-service")); - Assertions.assertTrue( - output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); - } - - private String filterOnK8sNamespaceAndType(Map result) { - return result.entrySet().stream().filter(en -> !en.getKey().contains("k8s_namespace")) - .filter(en -> !en.getKey().equals("type")) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtilsTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtilsTests.java deleted file mode 100644 index 4f3551e628..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesDiscoveryClientUtilsTests.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.matchesServiceLabels; - -/** - * @author wind57 - */ -@ExtendWith(OutputCaptureExtension.class) -class KubernetesDiscoveryClientUtilsTests { - - /** - * properties service labels are empty - */ - @Test - void testEmptyServiceLabelsFromProperties(CapturedOutput output) { - KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT; - V1Service service = new V1ServiceBuilder().withMetadata(new V1ObjectMeta().name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertTrue(result); - Assertions.assertTrue(output.getOut() - .contains("service labels from properties are empty, service with name : 'my-service' will match")); - } - - /** - * labels from service are empty - */ - @Test - void testEmptyServiceLabelsFromService(CapturedOutput output) { - Map propertiesLabels = Map.of("key", "value"); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), propertiesLabels, "", null, 0, false); - V1Service service = new V1ServiceBuilder().withMetadata(new V1ObjectMeta().name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertFalse(result); - Assertions.assertTrue(output.getOut().contains("service with name : 'my-service' does not have labels")); - } - - /** - *
-	 *     properties = [a=b]
-	 *     service    = [a=b]
-	 *
-	 *     This means the service is picked-up.
-	 * 
- */ - @Test - void testOne(CapturedOutput output) { - Map propertiesLabels = Map.of("a", "b"); - Map serviceLabels = Map.of("a", "b"); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), propertiesLabels, "", null, 0, false); - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMeta().labels(serviceLabels).name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertTrue(result); - Assertions.assertTrue(output.getOut().contains("Service labels from properties : {a=b}")); - Assertions.assertTrue(output.getOut().contains("Service labels from service : {a=b}")); - } - - /** - *
-	 *     properties = [a=b, c=d]
-	 *     service    = [a=b]
-	 *
-	 *     This means the service is not picked-up.
-	 * 
- */ - @Test - void testTwo(CapturedOutput output) { - Map propertiesLabels = ordered(Map.of("a", "b", "c", "d")); - Map serviceLabels = Map.of("a", "b"); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), propertiesLabels, "", null, 0, false); - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMeta().labels(serviceLabels).name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertFalse(result); - Assertions.assertTrue(output.getOut().contains("Service labels from properties : {a=b, c=d}")); - Assertions.assertTrue(output.getOut().contains("Service labels from service : {a=b}")); - } - - /** - *
-	 *     properties = [a=b, c=d]
-	 *     service    = [a=b, c=d]
-	 *
-	 *     This means the service is picked-up.
-	 * 
- */ - @Test - void testThree(CapturedOutput output) { - Map propertiesLabels = ordered(Map.of("a", "b", "c", "d")); - Map serviceLabels = ordered(Map.of("a", "b", "c", "d")); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), propertiesLabels, "", null, 0, false); - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMeta().labels(serviceLabels).name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertTrue(result); - Assertions.assertTrue(output.getOut().contains("Service labels from properties : {a=b, c=d}")); - Assertions.assertTrue(output.getOut().contains("Service labels from service : {a=b, c=d}")); - } - - /** - *
-	 *     properties = [a=b]
-	 *     service    = [a=b, c=d]
-	 *
-	 *     This means the service is picked-up.
-	 * 
- */ - @Test - void testFour(CapturedOutput output) { - Map propertiesLabels = Map.of("a", "b"); - Map serviceLabels = ordered(Map.of("a", "b", "c", "d")); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), propertiesLabels, "", null, 0, false); - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMeta().labels(serviceLabels).name("my-service")).build(); - - boolean result = matchesServiceLabels(service, properties); - Assertions.assertTrue(result); - Assertions.assertTrue(output.getOut().contains("Service labels from properties : {a=b}")); - Assertions.assertTrue(output.getOut().contains("Service labels from service : {a=b, c=d}")); - } - - // preserve order for testing reasons - private Map ordered(Map input) { - return input.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect( - Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (left, right) -> left, LinkedHashMap::new)); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfigurationApplicationContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfigurationApplicationContextTests.java deleted file mode 100644 index 58c7329f82..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientAutoConfigurationApplicationContextTests.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.io.StringReader; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.util.Config; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; - -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertNonSelectiveNamespacesBeansMissing; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertNonSelectiveNamespacesBeansPresent; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertSelectiveNamespacesBeansMissing; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertSelectiveNamespacesBeansPresent; - -/** - * Test various conditionals for - * {@link KubernetesInformerDiscoveryClientAutoConfiguration} - * - * @author wind57 - */ -class KubernetesInformerDiscoveryClientAutoConfigurationApplicationContextTests { - - private ApplicationContextRunner applicationContextRunner; - - private static K3sContainer container; - - @AfterAll - static void afterAll() { - container.stop(); - } - - @Test - void discoveryEnabledDefault() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledDefaultWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 3); - }); - } - - @Test - void discoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void discoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 4); - }); - } - - @Test - void kubernetesDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryBlockingEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryBlockingEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 1); - }); - } - - @Test - void kubernetesDiscoveryBlockingDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryBlockingDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=true", - "spring.cloud.kubernetes.discovery.namespaces=b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 1); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 1); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissing() { - setupWithFilteredClassLoader(HealthIndicator.class, "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissingWithSelectiveNamespaces() { - setupWithFilteredClassLoader(HealthIndicator.class, "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d,e"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 5); - }); - } - - /** - * reactive is disabled and should not impact blocking in any way - */ - @Test - void reactiveDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - /** - * reactive is disabled and should not impact blocking in any way - */ - @Test - void reactiveDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d,e"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 5); - }); - } - - private void setup(String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(KubernetesInformerDiscoveryClientAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesClientInformerAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class)) - .withUserConfiguration(ApiClientConfig.class).withPropertyValues(properties); - } - - private void setupWithFilteredClassLoader(Class cls, String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(KubernetesInformerDiscoveryClientAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesClientInformerAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class)) - .withClassLoader(new FilteredClassLoader(cls)).withUserConfiguration(ApiClientConfig.class) - .withPropertyValues(properties); - } - - @Configuration - static class ApiClientConfig { - - @Bean - @Primary - ApiClient apiClient() throws Exception { - container = Commons.container(); - container.start(); - - return Config.fromConfig(new StringReader(container.getKubeConfigYaml())); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientTests.java deleted file mode 100644 index 626009fa2b..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClientTests.java +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Cache; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.CoreV1EndpointPort; -import io.kubernetes.client.openapi.models.V1EndpointAddress; -import io.kubernetes.client.openapi.models.V1EndpointSubset; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceSpec; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -import static org.assertj.core.api.Assertions.assertThat; - -class KubernetesInformerDiscoveryClientTests { - - private static final V1Service SERVICE_1 = service("test-svc-1", "namespace1", Map.of()); - - private static final V1Service SERVICE_2 = service("test-svc-1", "namespace2", Map.of()); - - private static final V1Service SERVICE_3 = service("test-svc-3", "namespace1", - Map.of("spring", "true", "k8s", "true")); - - private static final V1Service SERVICE_4 = service("test-svc-1", "namespace1", Map.of("secured", "true")); - - private static final V1Service SERVICE_5 = service("test-svc-1", "namespace1", Map.of("primary-port-name", "oops")); - - private static final V1Service SERVICE_6 = service("test-svc-1", "namespace1", - Map.of("primary-port-name", "https")); - - private static final SharedInformerFactory SHARED_INFORMER_FACTORY = Mockito.mock(SharedInformerFactory.class); - - private static final V1Endpoints ENDPOINTS_1 = endpointsReadyAddress("test-svc-1", "namespace1"); - - private static final V1Endpoints ENDPOINTS_2 = endpointsReadyAddress("test-svc-1", "namespace2"); - - private static final V1Endpoints ENDPOINTS_3 = endpointsReadyAddress("test-svc-3", "namespace1"); - - private static final V1Endpoints ENDPOINTS_NOT_READY_ADDRESS = endpointsNotReadyAddress(); - - private static final V1Endpoints ENDPOINTS_NO_PORTS = endpointsNoPorts(); - - private static final V1Endpoints ENDPOINTS_NO_UNSET_PORT_NAME = endpointsNoUnsetPortName(); - - private static final V1Endpoints ENDPOINTS_WITH = endpointsWithMultiplePorts(); - - private static final V1Endpoints ENDPOINTS_WITH_MULTIPLE_PORTS_NO_HTTPS = endpointsWithMultiplePortsNoHttps(); - - private static final V1Endpoints ENDPOINTS_MULTIPLE_PORTS_WITHOUT_SUPPORTED_PORT_NAMES = endpointsMultiplePortsWithoutSupportedPortNames(); - - private static final KubernetesDiscoveryProperties ALL_NAMESPACES = properties(true, Map.of()); - - private static final KubernetesDiscoveryProperties NOT_ALL_NAMESPACES = properties(false, Map.of()); - - @Test - void testServiceWithUnsetPortNames() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NO_UNSET_PORT_NAME); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1").toArray()) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 80, - Map.of("", "80", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void testDiscoveryGetServicesAllNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NO_UNSET_PORT_NAME); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT); - - assertThat(discoveryClient.getServices().toArray()).containsOnly(SERVICE_1.getMetadata().getName(), - SERVICE_2.getMetadata().getName()); - - } - - @Test - void testDiscoveryWithServiceLabels() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2, SERVICE_3); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NO_UNSET_PORT_NAME); - - Map labels = Map.of("k8s", "true", "spring", "true"); - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = properties(true, labels); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, kubernetesDiscoveryProperties); - - assertThat(discoveryClient.getServices().toArray()).containsOnly(SERVICE_3.getMetadata().getName()); - - } - - @Test - void testDiscoveryInstancesWithServiceLabels() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2, SERVICE_3); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1, ENDPOINTS_3); - - Map labels = Map.of("k8s", "true", "spring", "true"); - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = properties(true, labels); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, kubernetesDiscoveryProperties); - - assertThat(discoveryClient.getInstances("test-svc-1").toArray()).isEmpty(); - assertThat(discoveryClient.getInstances("test-svc-3").toArray()) - .containsOnly( - new DefaultKubernetesServiceInstance( - "", "test-svc-3", "2.2.2.2", 8080, Map.of("spring", "true", "", "8080", "k8s", - "true", "k8s_namespace", "namespace1", "type", "ClusterIP"), - false, "namespace1", null)); - } - - @Test - void testDiscoveryInstancesWithSecuredServiceByAnnotations() { - Lister serviceLister = setupServiceLister(SERVICE_4); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1); - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, ALL_NAMESPACES); - assertThat(discoveryClient.getServices().toArray()).containsOnly(SERVICE_4.getMetadata().getName()); - ServiceInstance serviceInstance = discoveryClient.getInstances(SERVICE_4.getMetadata().getName()).get(0); - assertThat(serviceInstance.isSecure()).isTrue(); - } - - @Test - void testDiscoveryInstancesWithSecuredServiceByLabels() { - Lister serviceLister = setupServiceLister(SERVICE_4); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1); - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, ALL_NAMESPACES); - - assertThat(discoveryClient.getServices().toArray()).containsOnly(SERVICE_4.getMetadata().getName()); - ServiceInstance serviceInstance = discoveryClient.getInstances(SERVICE_4.getMetadata().getName()).get(0); - assertThat(serviceInstance.isSecure()).isTrue(); - } - - @Test - void testDiscoveryGetServicesOneNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NO_UNSET_PORT_NAME); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT); - - assertThat(discoveryClient.getServices().toArray()).containsOnly(SERVICE_1.getMetadata().getName()); - - } - - @Test - void testDiscoveryGetInstanceAllNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("", "8080", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void testDiscoveryGetInstanceOneNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("", "8080", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void testDiscoveryGetInstanceWithoutReadyAddressesShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NOT_READY_ADDRESS); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT); - - assertThat(discoveryClient.getInstances("test-svc-1")).isEmpty(); - } - - @Test - void testDiscoveryGetInstanceWithNotReadyAddressesIncludedShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NOT_READY_ADDRESS); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, false, - Set.of(), true, 60, true, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, true); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, kubernetesDiscoveryProperties); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("", "8080", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void instanceWithoutEndpointsShouldBeSkipped() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT); - - assertThat(discoveryClient.getInstances("test-svc-1")).isEmpty(); - } - - @Test - void instanceWithoutPortsShouldBeSkipped() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_NO_PORTS); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT); - - assertThat(discoveryClient.getInstances("test-svc-1")).isEmpty(); - } - - @Test - void instanceWithMultiplePortsAndPrimaryPortNameConfiguredWithLabelShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_6); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_WITH); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly( - new DefaultKubernetesServiceInstance( - "", "test-svc-1", "1.1.1.1", 443, Map.of("http", "80", "primary-port-name", "https", - "https", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), - false, "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndMisconfiguredPrimaryPortNameInLabelShouldReturnFirstPortAndLogWarning() { - Lister serviceLister = setupServiceLister(SERVICE_5); - Lister endpointsLister = setupEndpointsLister( - ENDPOINTS_MULTIPLE_PORTS_WITHOUT_SUPPORTED_PORT_NAMES); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly( - new DefaultKubernetesServiceInstance( - "", "test-svc-1", "1.1.1.1", 80, Map.of("tcp1", "80", "primary-port-name", "oops", - "tcp2", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), - false, "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndGenericPrimaryPortNameConfiguredShouldWork() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_WITH); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 443, - Map.of("http", "80", "https", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndMisconfiguredGenericPrimaryPortNameShouldReturnFirstPortAndLogWarning() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister( - ENDPOINTS_MULTIPLE_PORTS_WITHOUT_SUPPORTED_PORT_NAMES); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 80, - Map.of("tcp1", "80", "tcp2", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndWithoutPrimaryPortNameSpecifiedShouldFallBackToHttpsPort() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_WITH); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 443, - Map.of("http", "80", "https", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndWithoutPrimaryPortNameSpecifiedOrHttpsPortShouldFallBackToHttpPort() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_WITH_MULTIPLE_PORTS_NO_HTTPS); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 80, - Map.of("http", "80", "tcp", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void instanceWithMultiplePortsAndWithoutAnyConfigurationShouldPickTheFirstPort() { - Lister serviceLister = setupServiceLister(SERVICE_1); - Lister endpointsLister = setupEndpointsLister( - ENDPOINTS_MULTIPLE_PORTS_WITHOUT_SUPPORTED_PORT_NAMES); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, NOT_ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")) - .containsOnly(new DefaultKubernetesServiceInstance("", "test-svc-1", "1.1.1.1", 80, - Map.of("tcp1", "80", "tcp2", "443", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null)); - } - - @Test - void getInstancesShouldReturnInstancesWithTheSameServiceIdFromNamespaces() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1, ENDPOINTS_2); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, ALL_NAMESPACES); - - assertThat(discoveryClient.getInstances("test-svc-1")).containsOnly( - new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("", "8080", "k8s_namespace", "namespace1", "type", "ClusterIP"), false, - "namespace1", null), - new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("", "8080", "k8s_namespace", "namespace2", "type", "ClusterIP"), false, - "namespace2", null)); - } - - @Test - void testBothServicesMatchesFilter() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_3); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1, ENDPOINTS_3); - - String spelFilter = """ - #root.metadata.namespace matches "^.+1$" - """; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, properties); - - assertThat(discoveryClient.getServices()).contains("test-svc-1", "test-svc-3"); - - List one = discoveryClient.getInstances("test-svc-1"); - assertThat(one.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespace1"); - - List two = discoveryClient.getInstances("test-svc-3"); - assertThat(two.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespace1"); - - } - - @Test - void testOneServiceMatchesFilter() { - Lister serviceLister = setupServiceLister(SERVICE_1, SERVICE_2); - Lister endpointsLister = setupEndpointsLister(ENDPOINTS_1, ENDPOINTS_2); - - // without filter, both match - String spelFilter = ""; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, - false, spelFilter, Set.of(), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, properties); - - // only one here because of distinct - assertThat(discoveryClient.getServices()).contains("test-svc-1"); - - List result = discoveryClient.getInstances("test-svc-1").stream() - .sorted(Comparator.comparing(res -> res.getMetadata().get("k8s_namespace"))).toList(); - assertThat(result.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespace1"); - assertThat(result.get(1).getMetadata().get("k8s_namespace")).isEqualTo("namespace2"); - - // with filter, only one matches - - spelFilter = """ - #root.metadata.namespace matches "^.+1$" - """; - properties = new KubernetesDiscoveryProperties(false, false, Set.of(), true, 60L, false, spelFilter, Set.of(), - Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - discoveryClient = new KubernetesInformerDiscoveryClient(SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, - null, null, properties); - - // only one here because of distinct - assertThat(discoveryClient.getServices()).contains("test-svc-1"); - - result = discoveryClient.getInstances("test-svc-1").stream() - .sorted(Comparator.comparing(res -> res.getMetadata().get("k8s_namespace"))).toList(); - assertThat(result.size()).isEqualTo(1); - assertThat(result.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespace1"); - - } - - @Test - void testServicesWithDifferentMetadataLabels() { - V1Service serviceA = service("serviceX", "namespaceA", Map.of("shape", "round")); - V1Service serviceB = service("serviceX", "namespaceB", Map.of("shape", "triangle")); - - V1Endpoints endpointsA = endpointsReadyAddress("serviceX", "namespaceA"); - V1Endpoints endpointsB = endpointsReadyAddress("serviceX", "namespaceB"); - - Lister serviceLister = setupServiceLister(serviceA, serviceB); - Lister endpointsLister = setupEndpointsLister(endpointsA, endpointsB); - - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, true, Set.of(), true, 60L, - false, null, Set.of(), Map.of("shape", "round"), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, - 0, false); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, properties); - - List serviceInstances = discoveryClient.getInstances("serviceX"); - assertThat(serviceInstances.size()).isEqualTo(1); - assertThat(serviceInstances.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespaceA"); - } - - @Test - void testServicesWithSameMetadataLabels() { - V1Service serviceA = service("serviceX", "namespaceA", Map.of("shape", "round")); - V1Service serviceB = service("serviceX", "namespaceB", Map.of("shape", "round")); - - V1Endpoints endpointsA = endpointsReadyAddress("serviceX", "namespaceA"); - V1Endpoints endpointsB = endpointsReadyAddress("serviceX", "namespaceB"); - - Lister serviceLister = setupServiceLister(serviceA, serviceB); - Lister endpointsLister = setupEndpointsLister(endpointsA, endpointsB); - - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, true, Set.of(), true, 60L, - false, null, Set.of(), Map.of("shape", "round"), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, - 0, false); - - KubernetesInformerDiscoveryClient discoveryClient = new KubernetesInformerDiscoveryClient( - SHARED_INFORMER_FACTORY, serviceLister, endpointsLister, null, null, properties); - - List serviceInstances = discoveryClient.getInstances("serviceX").stream() - .sorted(Comparator.comparing(x -> x.getMetadata().get("k8s_namespace"))).toList(); - assertThat(serviceInstances.size()).isEqualTo(2); - assertThat(serviceInstances.get(0).getMetadata().get("k8s_namespace")).isEqualTo("namespaceA"); - assertThat(serviceInstances.get(1).getMetadata().get("k8s_namespace")).isEqualTo("namespaceB"); - } - - private Lister setupServiceLister(V1Service... services) { - Cache serviceCache = new Cache<>(); - Lister serviceLister = new Lister<>(serviceCache); - for (V1Service svc : services) { - serviceCache.add(svc); - } - return serviceLister; - } - - private Lister setupEndpointsLister(V1Endpoints... endpoints) { - Cache endpointsCache = new Cache<>(); - Lister endpointsLister = new Lister<>(endpointsCache); - for (V1Endpoints ep : endpoints) { - endpointsCache.add(ep); - } - return endpointsLister; - } - - private static V1Service service(String name, String namespace, Map labels) { - return new V1Service().metadata(new V1ObjectMeta().name(name).namespace(namespace).labels(labels)) - .spec(new V1ServiceSpec().type("ClusterIP")); - } - - private static V1Endpoints endpointsReadyAddress(String name, String namespace) { - return new V1Endpoints().metadata(new V1ObjectMeta().name(name).namespace(namespace)) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("2.2.2.2"))); - } - - private static V1Endpoints endpointsNotReadyAddress() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addNotReadyAddressesItem(new V1EndpointAddress().ip("2.2.2.2"))); - } - - private static V1Endpoints endpointsNoPorts() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - } - - private static V1Endpoints endpointsNoUnsetPortName() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(80)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - } - - private static V1Endpoints endpointsWithMultiplePorts() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().name("http").port(80)) - .addPortsItem(new CoreV1EndpointPort().name("https").port(443)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - } - - private static V1Endpoints endpointsWithMultiplePortsNoHttps() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().name("http").port(80)) - .addPortsItem(new CoreV1EndpointPort().name("tcp").port(443)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - } - - private static V1Endpoints endpointsMultiplePortsWithoutSupportedPortNames() { - return new V1Endpoints().metadata(new V1ObjectMeta().name("test-svc-1").namespace("namespace1")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().name("tcp1").port(80)) - .addPortsItem(new CoreV1EndpointPort().name("tcp2").port(443)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - } - - private static KubernetesDiscoveryProperties properties(boolean allNamespaces, Map labels) { - return new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(), true, 60, false, null, Set.of(), - labels, null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, true); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java deleted file mode 100644 index 2cccd1f8fd..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery; - -import java.util.List; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1Service; - -import org.springframework.boot.test.context.assertj.AssertableApplicationContext; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.ResolvableType; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Some common class that test code delegates to. - * - * @author wind57 - */ -public final class TestUtils { - - private TestUtils() { - - } - - public static void assertSelectiveNamespacesBeansMissing(AssertableApplicationContext context) { - String[] sharedInformerFactoriesBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - })); - assertThat(sharedInformerFactoriesBeanName).isEmpty(); - - String[] serviceSharedIndexInformersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - })); - assertThat(serviceSharedIndexInformersBeanName).isEmpty(); - - String[] endpointsSharedIndexInformersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - })); - assertThat(endpointsSharedIndexInformersBeanName).isEmpty(); - - String[] serviceListersBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>>() { - })); - assertThat(serviceListersBeanName).isEmpty(); - - String[] endpointsListersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - })); - assertThat(endpointsListersBeanName).isEmpty(); - } - - @SuppressWarnings("unchecked") - public static void assertSelectiveNamespacesBeansPresent(AssertableApplicationContext context, int times) { - String sharedInformerFactoriesBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - }))[0]; - List sharedInformerFactories = (List) context - .getBean(sharedInformerFactoriesBeanName); - assertThat(sharedInformerFactories.size()).isEqualTo(times); - - String serviceSharedIndexInformersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - }))[0]; - List> serviceSharedIndexInformers = (List>) context - .getBean(serviceSharedIndexInformersBeanName); - assertThat(serviceSharedIndexInformers.size()).isEqualTo(times); - - String endpointsSharedIndexInformersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - }))[0]; - List> endpointsSharedIndexInformers = (List>) context - .getBean(endpointsSharedIndexInformersBeanName); - assertThat(endpointsSharedIndexInformers.size()).isEqualTo(times); - - String serviceListersBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>>() { - }))[0]; - List> serviceListers = (List>) context.getBean(serviceListersBeanName); - assertThat(serviceListers.size()).isEqualTo(times); - - String endpointsListersBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>>() { - }))[0]; - List> endpointsListers = (List>) context - .getBean(endpointsListersBeanName); - assertThat(endpointsListers.size()).isEqualTo(times); - } - - @SuppressWarnings("unchecked") - public static void assertNonSelectiveNamespacesBeansPresent(AssertableApplicationContext context) { - assertThat(context).hasSingleBean(SharedInformerFactory.class); - - String serviceSharedIndexInformerBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - }))[0]; - SharedIndexInformer serviceSharedIndexInformer = (SharedIndexInformer) context - .getBean(serviceSharedIndexInformerBeanName); - assertThat(serviceSharedIndexInformer).isNotNull(); - - String endpointSharedIndexInformerBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - }))[0]; - SharedIndexInformer endpointsSharedIndexInformer = (SharedIndexInformer) context - .getBean(endpointSharedIndexInformerBeanName); - assertThat(endpointsSharedIndexInformer).isNotNull(); - - String serviceListerBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>() { - }))[0]; - Lister serviceLister = (Lister) context.getBean(serviceListerBeanName); - assertThat(serviceLister).isNotNull(); - - String endpointsListerBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>() { - }))[0]; - Lister endpointsLister = (Lister) context.getBean(endpointsListerBeanName); - assertThat(endpointsLister).isNotNull(); - } - - public static void assertNonSelectiveNamespacesBeansMissing(AssertableApplicationContext context) { - String[] serviceSharedIndexInformerBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - })); - assertThat(serviceSharedIndexInformerBeanName).isEmpty(); - - String[] endpointSharedIndexInformerBeanName = context.getBeanNamesForType( - ResolvableType.forType(new ParameterizedTypeReference>() { - })); - assertThat(endpointSharedIndexInformerBeanName).isEmpty(); - - String[] serviceListerBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>() { - })); - assertThat(serviceListerBeanName).isEmpty(); - - String[] endpointsListerBeanName = context - .getBeanNamesForType(ResolvableType.forType(new ParameterizedTypeReference>() { - })); - assertThat(endpointsListerBeanName).isEmpty(); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfigurationApplicationContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfigurationApplicationContextTests.java deleted file mode 100644 index 1bee1f8e3d..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchAutoConfigurationApplicationContextTests.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import io.kubernetes.client.informer.SharedIndexInformer; -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Lister; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test various conditionals for {@link KubernetesCatalogWatch} - * - * @author wind57 - */ -class KubernetesCatalogWatchAutoConfigurationApplicationContextTests { - - private ApplicationContextRunner applicationContextRunner; - - @Test - void discoveryEnabledDefault() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false"); - applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class)); - } - - @Test - void discoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true"); - applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class)); - } - - @Test - void discoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false"); - applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(KubernetesCatalogWatch.class)); - } - - @Test - void kubernetesDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true"); - applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class)); - } - - // disabling discovery has no impact on the catalog watch. - @Test - void kubernetesDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false"); - applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class)); - } - - /** - * both blocking and reactive configs are disabled, should not influence catalog - * watcher in any way. - */ - @Test - void disableBlockingAndReactive() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.discovery.reactive.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesCatalogWatch.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(SharedInformerFactory.class); - assertThat(context).doesNotHaveBean(SharedIndexInformer.class); - assertThat(context).doesNotHaveBean(Lister.class); - }); - } - - /** - * spring.cloud.kubernetes.discovery.enabled is false, but does not influence catalog - * watcher. - */ - @Test - void disableKubernetesDiscovery() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesCatalogWatch.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - }); - } - - private void setup(String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(KubernetesCatalogWatchAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesCommonsAutoConfiguration.class)) - .withPropertyValues(properties); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContextTests.java deleted file mode 100644 index d3f8619325..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchContextTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author wind57 - */ -class KubernetesCatalogWatchContextTests { - - @Test - void emptyLabels() { - String result = KubernetesCatalogWatchContext.labelSelector(Map.of()); - Assertions.assertEquals("", result); - } - - @Test - void singleLabel() { - String result = KubernetesCatalogWatchContext.labelSelector(Map.of("a", "b")); - Assertions.assertEquals("a=b", result); - } - - @Test - void multipleLabelsLabel() { - String result = KubernetesCatalogWatchContext.labelSelector(Map.of("a", "b", "c", "d")); - Assertions.assertTrue(result.contains("c=d")); - Assertions.assertTrue(result.contains("&")); - Assertions.assertTrue(result.contains("a=b")); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointSlicesTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointSlicesTests.java deleted file mode 100644 index 72206d8cd3..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointSlicesTests.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * Test cases for the Endpoint Slices support - * - * @author wind57 - */ -class KubernetesCatalogWatchEndpointSlicesTests extends KubernetesEndpointsAndEndpointSlicesTests { - - private static final Boolean USE_ENDPOINT_SLICES = true; - - private static ApiClient apiClient; - - public static WireMockServer wireMockServer; - - @BeforeAll - static void beforeAll() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - apiClient = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - Mockito.reset(APPLICATION_EVENT_PUBLISHER); - } - - @Test - @Override - void testInAllNamespacesEmptyServiceLabels() { - stubFor(get("/apis/discovery.k8s.io/v1/endpointslices?labelSelector=").willReturn( - aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "default"))))); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(Map.of(), Set.of(), null, apiClient, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInAllNamespacesWithSingleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/endpointslices?labelSelector=a%3Db").willReturn( - aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "default"))))); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(Map.of("a", "b"), Set.of(), null, - apiClient, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInAllNamespacesWithDoubleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/endpointslices?labelSelector=a%3Db%26c%3Dd").willReturn( - aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "default"))))); - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("a", "b"); - map.put("c", "d"); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(map, Set.of(), null, apiClient, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInSpecificNamespacesEmptyServiceLabels() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/b/endpointslices?labelSelector=") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("b"), Map.of(), null, - apiClient, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInSpecificNamespacesWithSingleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/one/endpointslices?labelSelector=a%3Db") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("aa", "a"))))); - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/two/endpointslices?labelSelector=a%3Db") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("bb", "b"))))); - - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("one", "two"), - Map.of("a", "b"), null, apiClient, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, - List.of(new EndpointNameAndNamespace("aa", "a"), new EndpointNameAndNamespace("bb", "b"))); - } - - @Test - @Override - void testInSpecificNamespacesWithDoubleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/one/endpointslices?labelSelector=a%3Db%26c%3Dd") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("aa", "a"))))); - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/two/endpointslices?labelSelector=a%3Db%26c%3Dd") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("bb", "b"))))); - - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("a", "b"); - map.put("c", "d"); - - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("one", "two"), map, null, - apiClient, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, - List.of(new EndpointNameAndNamespace("aa", "a"), new EndpointNameAndNamespace("bb", "b"))); - } - - @Test - @Override - void testInOneNamespaceEmptyServiceLabels() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/b/endpointslices?labelSelector=") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", Map.of(), null, apiClient, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInOneNamespaceWithSingleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/b/endpointslices?labelSelector=key%3Dvalue") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", Map.of("key", "value"), null, - apiClient, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInOneNamespaceWithDoubleLabel() { - stubFor(get("/apis/discovery.k8s.io/v1/namespaces/b/endpointslices?labelSelector=key%3Dvalue%26key1%3Dvalue1") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpointSlices("a", "b"))))); - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("key", "value"); - map.put("key1", "value1"); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", map, null, apiClient, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointsTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointsTests.java deleted file mode 100644 index f50fb75c0c..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesCatalogWatchEndpointsTests.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -/** - * Test cases for the Endpoints support - * - * @author wind57 - */ -class KubernetesCatalogWatchEndpointsTests extends KubernetesEndpointsAndEndpointSlicesTests { - - private static final Boolean USE_ENDPOINT_SLICES = false; - - private static CoreV1Api coreV1Api; - - public static WireMockServer wireMockServer; - - @BeforeAll - static void beforeAll() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - coreV1Api = new CoreV1Api(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - Mockito.reset(APPLICATION_EVENT_PUBLISHER); - } - - @Test - @Override - void testInAllNamespacesEmptyServiceLabels() { - stubFor(get("/api/v1/endpoints?labelSelector=") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "default"))))); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(Map.of(), Set.of(), coreV1Api, null, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInAllNamespacesWithSingleLabel() { - stubFor(get("/api/v1/endpoints?labelSelector=a%3Db") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "default"))))); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(Map.of("a", "b"), Set.of(), coreV1Api, - null, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInAllNamespacesWithDoubleLabel() { - stubFor(get("/api/v1/endpoints?labelSelector=a%3Db%26c%3Dd") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "default"))))); - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("a", "b"); - map.put("c", "d"); - KubernetesCatalogWatch watch = createWatcherInAllNamespacesWithLabels(map, Set.of(), coreV1Api, null, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "default"))); - } - - @Test - @Override - void testInSpecificNamespacesEmptyServiceLabels() { - stubFor(get("/api/v1/namespaces/b/endpoints?labelSelector=") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("b"), Map.of(), coreV1Api, - null, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInSpecificNamespacesWithSingleLabel() { - stubFor(get("/api/v1/namespaces/one/endpoints?labelSelector=a%3Db") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("aa", "a"))))); - stubFor(get("/api/v1/namespaces/two/endpoints?labelSelector=a%3Db") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("bb", "b"))))); - - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("one", "two"), - Map.of("a", "b"), coreV1Api, null, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, - List.of(new EndpointNameAndNamespace("aa", "a"), new EndpointNameAndNamespace("bb", "b"))); - } - - @Test - @Override - void testInSpecificNamespacesWithDoubleLabel() { - stubFor(get("/api/v1/namespaces/one/endpoints?labelSelector=a%3Db%26c%3Dd") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("aa", "a"))))); - stubFor(get("/api/v1/namespaces/two/endpoints?labelSelector=a%3Db%26c%3Dd") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("bb", "b"))))); - - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("a", "b"); - map.put("c", "d"); - - KubernetesCatalogWatch watch = createWatcherInSpecificNamespacesWithLabels(Set.of("one", "two"), map, coreV1Api, - null, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, - List.of(new EndpointNameAndNamespace("aa", "a"), new EndpointNameAndNamespace("bb", "b"))); - } - - @Test - @Override - void testInOneNamespaceEmptyServiceLabels() { - stubFor(get("/api/v1/namespaces/b/endpoints?labelSelector=") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", Map.of(), coreV1Api, null, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInOneNamespaceWithSingleLabel() { - stubFor(get("/api/v1/namespaces/b/endpoints?labelSelector=key%3Dvalue") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "b"))))); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", Map.of("key", "value"), - coreV1Api, null, USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - - @Test - @Override - void testInOneNamespaceWithDoubleLabel() { - stubFor(get("/api/v1/namespaces/b/endpoints?labelSelector=key%3Dvalue%26key1%3Dvalue1") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(endpoints("a", "b"))))); - // otherwise the stub might fail - LinkedHashMap map = new LinkedHashMap<>(); - map.put("key", "value"); - map.put("key1", "value1"); - KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceWithLabels("b", map, coreV1Api, null, - USE_ENDPOINT_SLICES); - - invokeAndAssert(watch, List.of(new EndpointNameAndNamespace("a", "b"))); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesClientCatalogWatchEndpointSlicesSupportTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesClientCatalogWatchEndpointSlicesSupportTests.java deleted file mode 100644 index 29d822f0fa..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesClientCatalogWatchEndpointSlicesSupportTests.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.Map; -import java.util.Set; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1APIResource; -import io.kubernetes.client.openapi.models.V1APIResourceBuilder; -import io.kubernetes.client.openapi.models.V1APIResourceList; -import io.kubernetes.client.openapi.models.V1APIResourceListBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.ENDPOINT_SLICE; - -/** - * Tests that only assert the needed support for EndpointSlices in the cluster. - * - * @author wind57 - */ -class KubernetesClientCatalogWatchEndpointSlicesSupportTests { - - public static WireMockServer wireMockServer; - - private static final KubernetesNamespaceProvider NAMESPACE_PROVIDER = Mockito - .mock(KubernetesNamespaceProvider.class); - - private static ApiClient apiClient; - - @BeforeAll - static void beforeAll() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - - apiClient = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - /** - *
-	 *     - endpoint slices are enabled, but are not supported by the cluster, as such we will fail
-	 *       with an IllegalArgumentException
-	 *     - V1APIResource is empty
-	 * 
- */ - @Test - void testEndpointSlicesEnabledButNotSupported() { - boolean useEndpointSlices = true; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60, - false, "", Set.of(), Map.of(), "", null, 0, useEndpointSlices); - - V1APIResourceList list = new V1APIResourceListBuilder().addToResources(new V1APIResource()).build(); - stubFor(get("/apis/discovery.k8s.io/v1") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(null, apiClient, properties, NAMESPACE_PROVIDER); - IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, watch::postConstruct); - Assertions.assertEquals("EndpointSlices are not supported on the cluster", ex.getMessage()); - } - - /** - *
-	 *     - endpoint slices are enabled, but are not supported by the cluster, as such we will fail
-	 *       with an IllegalArgumentException
-	 *     - V1APIResource does not contain EndpointSlice
-	 * 
- */ - @Test - void testEndpointSlicesEnabledButNotSupportedViaApiVersions() { - boolean useEndpointSlices = true; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60, - false, "", Set.of(), Map.of(), "", null, 0, useEndpointSlices); - - V1APIResourceList list = new V1APIResourceListBuilder() - .addToResources(new V1APIResourceBuilder().withName("not-the-one").build()).build(); - stubFor(get("/apis/discovery.k8s.io/v1") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(null, apiClient, properties, NAMESPACE_PROVIDER); - IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, watch::postConstruct); - Assertions.assertEquals("EndpointSlices are not supported on the cluster", ex.getMessage()); - } - - /** - * endpoint slices are disabled via properties, as such we will use a catalog watch - * based on Endpoints - */ - @Test - void testEndpointsSupport() { - boolean useEndpointSlices = false; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60, - false, "", Set.of(), Map.of(), "", null, 0, useEndpointSlices); - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(null, apiClient, properties, NAMESPACE_PROVIDER); - - Assertions.assertEquals(KubernetesEndpointsCatalogWatch.class, watch.stateGenerator().getClass()); - } - - /** - * endpoint slices are enabled via properties and supported by the cluster, as such we - * will use a catalog watch based on Endpoint Slices - */ - @Test - void testEndpointSlicesSupport() { - boolean useEndpointSlices = true; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60, - false, "", Set.of(), Map.of(), "", null, 0, useEndpointSlices); - - V1APIResourceList list = new V1APIResourceListBuilder() - .addToResources(new V1APIResourceBuilder().withName("endpointslices").withKind(ENDPOINT_SLICE).build()) - .build(); - stubFor(get("/apis/discovery.k8s.io/v1") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(list)))); - - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(null, apiClient, properties, NAMESPACE_PROVIDER); - Assertions.assertEquals(KubernetesEndpointSlicesCatalogWatch.class, watch.stateGenerator().getClass()); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsAndEndpointSlicesTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsAndEndpointSlicesTests.java deleted file mode 100644 index 1f8688e499..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/catalog/KubernetesEndpointsAndEndpointSlicesTests.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.catalog; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1EndpointAddressBuilder; -import io.kubernetes.client.openapi.models.V1EndpointBuilder; -import io.kubernetes.client.openapi.models.V1EndpointSliceBuilder; -import io.kubernetes.client.openapi.models.V1EndpointSliceList; -import io.kubernetes.client.openapi.models.V1EndpointSliceListBuilder; -import io.kubernetes.client.openapi.models.V1EndpointSubsetBuilder; -import io.kubernetes.client.openapi.models.V1EndpointsBuilder; -import io.kubernetes.client.openapi.models.V1EndpointsList; -import io.kubernetes.client.openapi.models.V1EndpointsListBuilder; -import io.kubernetes.client.openapi.models.V1ObjectReferenceBuilder; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import org.springframework.cloud.client.discovery.event.HeartbeatEvent; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.context.ApplicationEventPublisher; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * make sure that all the tests for endpoints are also handled by endpoint slices - * - * @author wind57 - */ -abstract class KubernetesEndpointsAndEndpointSlicesTests { - - static final KubernetesNamespaceProvider NAMESPACE_PROVIDER = Mockito.mock(KubernetesNamespaceProvider.class); - - static final ArgumentCaptor HEARTBEAT_EVENT_ARGUMENT_CAPTOR = ArgumentCaptor - .forClass(HeartbeatEvent.class); - - static final ApplicationEventPublisher APPLICATION_EVENT_PUBLISHER = Mockito.mock(ApplicationEventPublisher.class); - - /** - * test in all namespaces with service labels being empty - */ - abstract void testInAllNamespacesEmptyServiceLabels(); - - /** - * test in all namespaces with service labels having a single label present - */ - abstract void testInAllNamespacesWithSingleLabel(); - - /** - * test in all namespaces with service labels having two labels - */ - abstract void testInAllNamespacesWithDoubleLabel(); - - /** - * test in some specific namespaces with service labels being empty - */ - abstract void testInSpecificNamespacesEmptyServiceLabels(); - - /** - * test in some specific namespaces with service labels having a single label present - */ - abstract void testInSpecificNamespacesWithSingleLabel(); - - /** - * test in some specific namespaces with service labels having two labels - */ - abstract void testInSpecificNamespacesWithDoubleLabel(); - - /** - * test in one namespace with service labels being empty - */ - abstract void testInOneNamespaceEmptyServiceLabels(); - - /** - * test in one namespace with service labels having a single label present - */ - abstract void testInOneNamespaceWithSingleLabel(); - - /** - * test in one namespace with service labels having two labels - */ - abstract void testInOneNamespaceWithDoubleLabel(); - - KubernetesCatalogWatch createWatcherInAllNamespacesWithLabels(Map labels, Set namespaces, - CoreV1Api coreV1Api, ApiClient apiClient, boolean endpointSlices) { - - boolean allNamespaces = true; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, allNamespaces, namespaces, - true, 60, false, "", Set.of(), labels, "", null, 0, endpointSlices); - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(coreV1Api, apiClient, properties, NAMESPACE_PROVIDER); - - if (endpointSlices) { - watch = Mockito.spy(watch); - Mockito.doReturn(new KubernetesEndpointSlicesCatalogWatch()).when(watch).stateGenerator(); - } - - watch.postConstruct(); - watch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER); - return watch; - - } - - KubernetesCatalogWatch createWatcherInSpecificNamespacesWithLabels(Set namespaces, - Map labels, CoreV1Api coreV1Api, ApiClient apiClient, boolean endpointSlices) { - - boolean allNamespaces = false; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, allNamespaces, namespaces, - true, 60, false, "", Set.of(), labels, "", null, 0, false); - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(coreV1Api, apiClient, properties, NAMESPACE_PROVIDER); - - if (endpointSlices) { - watch = Mockito.spy(watch); - Mockito.doReturn(new KubernetesEndpointSlicesCatalogWatch()).when(watch).stateGenerator(); - } - - watch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER); - watch.postConstruct(); - return watch; - - } - - KubernetesCatalogWatch createWatcherInSpecificNamespaceWithLabels(String namespace, Map labels, - CoreV1Api coreV1Api, ApiClient apiClient, boolean endpointSlices) { - - when(NAMESPACE_PROVIDER.getNamespace()).thenReturn(namespace); - - boolean allNamespaces = false; - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, allNamespaces, Set.of(), - true, 60, false, "", Set.of(), labels, "", null, 0, endpointSlices); - KubernetesCatalogWatch watch = new KubernetesCatalogWatch(coreV1Api, apiClient, properties, NAMESPACE_PROVIDER); - - if (endpointSlices) { - watch = Mockito.spy(watch); - Mockito.doReturn(new KubernetesEndpointSlicesCatalogWatch()).when(watch).stateGenerator(); - } - - watch.postConstruct(); - watch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER); - return watch; - - } - - V1EndpointsList endpoints(String name, String namespace) { - return new V1EndpointsListBuilder().addToItems(new V1EndpointsBuilder() - .addToSubsets(new V1EndpointSubsetBuilder().addToAddresses(new V1EndpointAddressBuilder() - .withTargetRef(new V1ObjectReferenceBuilder().withName(name).withNamespace(namespace).build()) - .build()).build()) - .build()).build(); - } - - V1EndpointSliceList endpointSlices(String name, String namespace) { - return new V1EndpointSliceListBuilder() - .addToItems(new V1EndpointSliceBuilder().addToEndpoints(new V1EndpointBuilder() - .withTargetRef(new V1ObjectReferenceBuilder().withName(name).withNamespace(namespace).build()) - .build()).build()) - .build(); - } - - static void invokeAndAssert(KubernetesCatalogWatch watch, List state) { - watch.catalogServicesWatch(); - - verify(APPLICATION_EVENT_PUBLISHER).publishEvent(HEARTBEAT_EVENT_ARGUMENT_CAPTOR.capture()); - - HeartbeatEvent event = HEARTBEAT_EVENT_ARGUMENT_CAPTOR.getValue(); - assertThat(event.getValue()).isInstanceOf(List.class); - - assertThat(event.getValue()).isEqualTo(state); - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java deleted file mode 100644 index 68d4f2153a..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.reactive; - -import java.io.StringReader; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.util.Config; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator; -import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration; -import org.springframework.cloud.commons.util.UtilAutoConfiguration; -import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerSelectiveNamespacesAutoConfiguration; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertNonSelectiveNamespacesBeansMissing; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertNonSelectiveNamespacesBeansPresent; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertSelectiveNamespacesBeansMissing; -import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertSelectiveNamespacesBeansPresent; - -/** - * Test various conditionals for - * {@link KubernetesInformerReactiveDiscoveryClientAutoConfiguration} - * - * @author wind57 - */ -class KubernetesInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests { - - private ApplicationContextRunner applicationContextRunner; - - private static K3sContainer container; - - @AfterAll - static void afterAll() { - container.stop(); - } - - @Test - void discoveryEnabledDefault() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledDefaultWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 3); - }); - } - - @Test - void discoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 3); - }); - } - - @Test - void discoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void kubernetesDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - // only "simple" one from commons, as ours is not picked up - assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - // only "simple" one from commons, as ours is not picked up - assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesReactiveDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesReactiveDiscoveryEnabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void kubernetesReactiveDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesReactiveDiscoveryDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - /** - * blocking is disabled, and it should not impact reactive in any way. - */ - @Test - void blockingDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - /** - * blocking is disabled, and it should not impact reactive in any way. - */ - @Test - void blockingDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void healthDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void healthDisabledWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void healthEnabledClassNotPresent() { - setupWithFilteredClassLoader("org.springframework.boot.actuate.health.ReactiveHealthIndicator", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void healthEnabledClassNotPresentWithSelectiveNamespaces() { - setupWithFilteredClassLoader("org.springframework.boot.actuate.health.ReactiveHealthIndicator", - "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - private void setup(String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - KubernetesInformerReactiveDiscoveryClientAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, SimpleReactiveDiscoveryClientAutoConfiguration.class, - UtilAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class, - KubernetesCommonsAutoConfiguration.class, KubernetesClientInformerAutoConfiguration.class)) - .withUserConfiguration(ApiClientConfig.class).withPropertyValues(properties); - } - - private void setupWithFilteredClassLoader(String name, String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - KubernetesInformerReactiveDiscoveryClientAutoConfiguration.class, - KubernetesClientAutoConfiguration.class, SimpleReactiveDiscoveryClientAutoConfiguration.class, - UtilAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class, - KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class, - KubernetesCommonsAutoConfiguration.class, KubernetesClientInformerAutoConfiguration.class)) - .withUserConfiguration(ApiClientConfig.class).withClassLoader(new FilteredClassLoader(name)) - .withPropertyValues(properties); - } - - @Configuration - static class ApiClientConfig { - - @Bean - @Primary - ApiClient apiClient() throws Exception { - container = Commons.container(); - container.start(); - - return Config.fromConfig(new StringReader(container.getKubeConfigYaml())); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationTests.java deleted file mode 100644 index a22d101b5e..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientAutoConfigurationTests.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.discovery.reactive; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.models.V1EndpointsListBuilder; -import io.kubernetes.client.openapi.models.V1ListMetaBuilder; -import io.kubernetes.client.openapi.models.V1ServiceListBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; -import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.context.annotation.Bean; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { "spring.main.cloud-platform=KUBERNETES", - "spring.cloud.kubernetes.discovery.cacheLoadingTimeoutSeconds=5", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.waitCacheReady=false", "spring.main.web-application-type=reactive" }) -class KubernetesInformerReactiveDiscoveryClientAutoConfigurationTests { - - @Autowired - private ReactiveDiscoveryClient discoveryClient; - - private static WireMockServer wireMockServer; - - @AfterAll - static void after() { - wireMockServer.stop(); - } - - @AfterEach - void afterEach() { - WireMock.reset(); - } - - @Test - void kubernetesDiscoveryClientCreated() { - assertThat(this.discoveryClient).isNotNull().isInstanceOf(ReactiveCompositeDiscoveryClient.class); - - ReactiveCompositeDiscoveryClient composite = (ReactiveCompositeDiscoveryClient) this.discoveryClient; - assertThat(composite.getDiscoveryClients().stream() - .anyMatch(dc -> dc instanceof KubernetesInformerReactiveDiscoveryClient)).isTrue(); - } - - @SpringBootApplication - protected static class TestConfig { - - @Bean - ApiClient apiClient() { - wireMockServer = new WireMockServer(options().dynamicPort()); - wireMockServer.start(); - WireMock.configureFor(wireMockServer.port()); - stubFor(get("/api/v1/namespaces/test/endpoints?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1EndpointsListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()).build())))); - stubFor(get("/api/v1/namespaces/test/services?resourceVersion=0&watch=false") - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(new V1ServiceListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()).build())))); - return new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - } - - @Bean - KubernetesNamespaceProvider kubernetesNamespaceProvider() { - KubernetesNamespaceProvider provider = mock(KubernetesNamespaceProvider.class); - when(provider.getNamespace()).thenReturn("test"); - return provider; - } - - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientTests.java deleted file mode 100644 index 16d98059e3..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/reactive/KubernetesInformerReactiveDiscoveryClientTests.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2013-2023 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.discovery.reactive; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.informer.cache.Cache; -import io.kubernetes.client.informer.cache.Lister; -import io.kubernetes.client.openapi.models.CoreV1EndpointPort; -import io.kubernetes.client.openapi.models.V1EndpointAddress; -import io.kubernetes.client.openapi.models.V1EndpointSubset; -import io.kubernetes.client.openapi.models.V1Endpoints; -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceSpec; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import reactor.test.StepVerifier; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; - -import static io.kubernetes.client.util.Namespaces.NAMESPACE_ALL; - -/** - * @author Ryan Baxter - */ -class KubernetesInformerReactiveDiscoveryClientTests { - - // default constructor partitions by namespace - private Cache serviceCache = new Cache<>(); - - // default constructor partitions by namespace - private Cache endpointsCache = new Cache<>(); - - private static final String NAMESPACE_1 = "namespace1"; - - private static final String NAMESPACE_2 = "namespace2"; - - private final SharedInformerFactory sharedInformerFactory = Mockito.mock(SharedInformerFactory.class); - - private static final V1Service TEST_SERVICE_1 = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) - .metadata(new V1ObjectMeta().name("test-svc-1").namespace(NAMESPACE_1)); - - private static final V1Service TEST_SERVICE_2 = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) - .metadata(new V1ObjectMeta().name("test-svc-2").namespace(NAMESPACE_2)); - - // same name as TEST_SERVICE_1, to test distinct - private static final V1Service TEST_SERVICE_3 = new V1Service() - .metadata(new V1ObjectMeta().name("test-svc-2").namespace(NAMESPACE_2)); - - private static final V1Endpoints TEST_ENDPOINTS_1 = new V1Endpoints() - .metadata(new V1ObjectMeta().name("test-svc-1").namespace(NAMESPACE_1)) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("2.2.2.2"))); - - @AfterEach - void afterEach() { - serviceCache = new Cache<>(); - endpointsCache = new Cache<>(); - } - - @Test - void testDiscoveryGetServicesAllNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(NAMESPACE_ALL, TEST_SERVICE_1, TEST_SERVICE_2, - TEST_SERVICE_3); - Lister endpointsLister = setupEndpointsLister(""); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, true, - Set.of(), true, 60, false, null, Set.of(), Map.of(), null, null, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - StepVerifier.create(discoveryClient.getServices()) - .expectNext(TEST_SERVICE_1.getMetadata().getName(), TEST_SERVICE_2.getMetadata().getName()) - .expectComplete().verify(); - - } - - @Test - void testDiscoveryGetServicesOneNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(NAMESPACE_1, TEST_SERVICE_1, TEST_SERVICE_2); - Lister endpointsLister = setupEndpointsLister(""); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - KubernetesDiscoveryProperties.DEFAULT)); - - StepVerifier.create(discoveryClient.getServices()).expectNext(TEST_SERVICE_1.getMetadata().getName()) - .expectComplete().verify(); - - } - - @Test - void testDiscoveryGetInstanceAllNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(NAMESPACE_ALL, TEST_SERVICE_1, TEST_SERVICE_2); - Lister endpointsLister = setupEndpointsLister(NAMESPACE_1, TEST_ENDPOINTS_1); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, true, - Set.of(), true, 60, false, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - StepVerifier.create(discoveryClient.getInstances("test-svc-1")) - .expectNext(new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("type", "ClusterIP", "", "8080", "k8s_namespace", "namespace1"), false, - "namespace1", null)) - .expectComplete().verify(); - - } - - @Test - void testDiscoveryGetInstanceOneNamespaceShouldWork() { - Lister serviceLister = setupServiceLister(NAMESPACE_1, TEST_SERVICE_1, TEST_SERVICE_2); - Lister endpointsLister = setupEndpointsLister(NAMESPACE_1, TEST_ENDPOINTS_1); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, false, - Set.of(), true, 60, false, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - StepVerifier.create(discoveryClient.getInstances("test-svc-1")) - .expectNext(new DefaultKubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, - Map.of("type", "ClusterIP", "", "8080", "k8s_namespace", "namespace1"), false, - "namespace1", null)) - .expectComplete().verify(); - - } - - /** - *
-	 *     - all-namespaces = true
-	 *     - service-a in namespace-a exists
-	 *     - service-b in namespace-b exists
-	 *
-	 *     As such, both services are found.
-	 * 
- */ - @Test - void testAllNamespacesTwoServicesPresent() { - Lister endpointsLister = setupEndpointsLister(""); - - boolean allNamespaces = true; - V1Service serviceA = new V1Service().metadata(new V1ObjectMeta().name("service-a").namespace("namespace-a")); - V1Service serviceB = new V1Service().metadata(new V1ObjectMeta().name("service-b").namespace("namespace-b")); - serviceCache.add(serviceA); - serviceCache.add(serviceB); - - Lister serviceLister = new Lister<>(serviceCache).namespace(NAMESPACE_ALL); - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, - allNamespaces, Set.of(), true, 60, false, null, Set.of(), Map.of(), null, null, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - List result = discoveryClient.getServices().collectList().block(); - Assertions.assertEquals(result.size(), 2); - Assertions.assertTrue(result.contains("service-a")); - Assertions.assertTrue(result.contains("service-b")); - } - - /** - *
-	 *     - all-namespaces = false
-	 *     - service-a in namespace-a exists
-	 *     - service-b in namespace-b exists
-	 *     - service lister exists in namespace-a
-	 *
-	 *     As such, one service is found.
-	 * 
- */ - @Test - void testSingleNamespaceTwoServicesPresent() { - Lister endpointsLister = setupEndpointsLister(""); - - boolean allNamespaces = false; - V1Service serviceA = new V1Service().metadata(new V1ObjectMeta().name("service-a").namespace("namespace-a")); - V1Service serviceB = new V1Service().metadata(new V1ObjectMeta().name("service-b").namespace("namespace-b")); - serviceCache.add(serviceA); - serviceCache.add(serviceB); - - Lister serviceLister = new Lister<>(serviceCache).namespace("namespace-a"); - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, - allNamespaces, Set.of(), true, 60, false, null, Set.of(), Map.of(), null, null, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - List result = discoveryClient.getServices().collectList().block(); - Assertions.assertEquals(result.size(), 1); - Assertions.assertTrue(result.contains("service-a")); - Assertions.assertFalse(result.contains("service-b")); - } - - /** - *
-	 *     - all-namespaces = true
-	 *     - endpoints-X in namespace-a exists
-	 *     - endpoints-X in namespace-b exists
-	 *
-	 *     As such, both endpoints are found.
-	 * 
- */ - @Test - void testAllNamespacesTwoEndpointsPresent() { - boolean allNamespaces = true; - - V1Service serviceXNamespaceA = new V1Service() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-a")); - V1Service serviceXNamespaceB = new V1Service() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-b")); - serviceCache.add(serviceXNamespaceA); - serviceCache.add(serviceXNamespaceB); - - V1Endpoints endpointsXNamespaceA = new V1Endpoints() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-a")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - V1Endpoints endpointsXNamespaceB = new V1Endpoints() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-b")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("2.2.2.2"))); - endpointsCache.add(endpointsXNamespaceA); - endpointsCache.add(endpointsXNamespaceB); - - Lister endpointsLister = new Lister<>(endpointsCache, NAMESPACE_ALL); - Lister serviceLister = new Lister<>(serviceCache, NAMESPACE_ALL); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, - allNamespaces, Set.of(), true, 60, false, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - List result = discoveryClient.getInstances("endpoints-x").collectList().block(); - Assertions.assertEquals(result.size(), 2); - List byIp = result.stream().map(ServiceInstance::getHost).sorted().toList(); - Assertions.assertTrue(byIp.contains("1.1.1.1")); - Assertions.assertTrue(byIp.contains("2.2.2.2")); - } - - /** - *
-	 *     - all-namespaces = true
-	 *     - endpoints-X in namespace-a exists
-	 *     - endpoints-X in namespace-b exists
-	 *
-	 *     We search in namespace-a, only. As such, single endpoints is found.
-	 * 
- */ - @Test - void testAllSingleTwoEndpointsPresent() { - boolean allNamespaces = true; - - V1Service serviceXNamespaceA = new V1Service() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-a")); - V1Service serviceXNamespaceB = new V1Service() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-b")); - serviceCache.add(serviceXNamespaceA); - serviceCache.add(serviceXNamespaceB); - - V1Endpoints endpointsXNamespaceA = new V1Endpoints() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-a")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("1.1.1.1"))); - V1Endpoints endpointsXNamespaceB = new V1Endpoints() - .metadata(new V1ObjectMeta().name("endpoints-x").namespace("namespace-b")) - .addSubsetsItem(new V1EndpointSubset().addPortsItem(new CoreV1EndpointPort().port(8080)) - .addAddressesItem(new V1EndpointAddress().ip("2.2.2.2"))); - endpointsCache.add(endpointsXNamespaceA); - endpointsCache.add(endpointsXNamespaceB); - - Lister endpointsLister = new Lister<>(endpointsCache).namespace("namespace-a"); - Lister serviceLister = new Lister<>(serviceCache).namespace("namespace-a"); - - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, - allNamespaces, Set.of(), true, 60, false, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - - KubernetesInformerReactiveDiscoveryClient discoveryClient = new KubernetesInformerReactiveDiscoveryClient( - new KubernetesInformerDiscoveryClient(sharedInformerFactory, serviceLister, endpointsLister, null, null, - kubernetesDiscoveryProperties)); - - List result = discoveryClient.getInstances("endpoints-x").collectList().block(); - Assertions.assertEquals(result.size(), 1); - List byIp = result.stream().map(ServiceInstance::getHost).sorted().toList(); - Assertions.assertTrue(byIp.contains("1.1.1.1")); - } - - private Lister setupServiceLister(String namespace, V1Service... services) { - Lister serviceLister = new Lister<>(serviceCache, namespace); - for (V1Service svc : services) { - serviceCache.add(svc); - } - return serviceLister; - } - - private Lister setupEndpointsLister(String namespace, V1Endpoints... endpoints) { - Lister endpointsLister = new Lister<>(endpointsCache); - for (V1Endpoints ep : endpoints) { - endpointsCache.add(ep); - } - return endpointsLister; - } - -} diff --git a/spring-cloud-kubernetes-client-discovery/src/test/resources/logback-test.xml b/spring-cloud-kubernetes-client-discovery/src/test/resources/logback-test.xml deleted file mode 100644 index cd7555796e..0000000000 --- a/spring-cloud-kubernetes-client-discovery/src/test/resources/logback-test.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - - - - diff --git a/spring-cloud-kubernetes-client-loadbalancer/.flattened-pom.xml b/spring-cloud-kubernetes-client-loadbalancer/.flattened-pom.xml new file mode 100644 index 0000000000..ba13cb058e --- /dev/null +++ b/spring-cloud-kubernetes-client-loadbalancer/.flattened-pom.xml @@ -0,0 +1,113 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-client-loadbalancer + 3.0.4-SNAPSHOT + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io/spring-cloud-kubernetes-client-loadbalancer + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-loadbalancer + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-client-loadbalancer + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-client-loadbalancer + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + 4.0.4-SNAPSHOT + compile + + + org.springframework.cloud + spring-cloud-kubernetes-client-discovery + 3.0.4-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-actuator + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-configuration-processor + 3.0.7 + compile + true + + + diff --git a/spring-cloud-kubernetes-client-loadbalancer/pom.xml b/spring-cloud-kubernetes-client-loadbalancer/pom.xml deleted file mode 100644 index dbed72cbe6..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - spring-cloud-kubernetes - org.springframework.cloud - - 3.1.0-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-client-loadbalancer - - - - org.springframework.cloud - spring-cloud-starter-loadbalancer - - - org.springframework.cloud - spring-cloud-kubernetes-client-discovery - - - org.springframework.boot - spring-boot-starter-actuator - true - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.boot - spring-boot-starter-test - test - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - io.projectreactor - reactor-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - - diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerAutoConfiguration.java b/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerAutoConfiguration.java deleted file mode 100644 index 0f54c87a3d..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerAutoConfiguration.java +++ /dev/null @@ -1,45 +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.loadbalancer; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties; -import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Ryan Baxter - */ -@Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(KubernetesLoadBalancerProperties.class) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@ConditionalOnProperty(value = "spring.cloud.kubernetes.loadbalancer.enabled", matchIfMissing = true) -@LoadBalancerClients(defaultConfiguration = KubernetesClientLoadBalancerClientConfiguration.class) -public class KubernetesClientLoadBalancerAutoConfiguration { - - @Bean - KubernetesClientServiceInstanceMapper mapper(KubernetesLoadBalancerProperties properties, - KubernetesDiscoveryProperties discoveryProperties) { - return new KubernetesClientServiceInstanceMapper(properties, discoveryProperties); - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerClientConfiguration.java b/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerClientConfiguration.java deleted file mode 100644 index 2a0585303d..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerClientConfiguration.java +++ /dev/null @@ -1,43 +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.loadbalancer; - -import io.kubernetes.client.openapi.apis.CoreV1Api; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.core.env.Environment; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientLoadBalancerClientConfiguration { - - @Bean - @ConditionalOnProperty(name = "spring.cloud.kubernetes.loadbalancer.mode", havingValue = "SERVICE") - ServiceInstanceListSupplier kubernetesServicesListSupplier(Environment environment, CoreV1Api coreV1Api, - KubernetesClientServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties, - KubernetesNamespaceProvider kubernetesNamespaceProvider, ConfigurableApplicationContext context) { - return ServiceInstanceListSupplier.builder().withBase(new KubernetesClientServicesListSupplier(environment, - mapper, discoveryProperties, coreV1Api, kubernetesNamespaceProvider)).withCaching().build(context); - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapper.java b/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapper.java deleted file mode 100644 index 83c7e969fa..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapper.java +++ /dev/null @@ -1,94 +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.loadbalancer; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServicePort; - -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper; -import org.springframework.util.StringUtils; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientServiceInstanceMapper implements KubernetesServiceInstanceMapper { - - private KubernetesLoadBalancerProperties properties; - - private KubernetesDiscoveryProperties discoveryProperties; - - public KubernetesClientServiceInstanceMapper(KubernetesLoadBalancerProperties properties, - KubernetesDiscoveryProperties discoveryProperties) { - this.properties = properties; - this.discoveryProperties = discoveryProperties; - } - - @Override - public KubernetesServiceInstance map(V1Service service) { - final V1ObjectMeta meta = service.getMetadata(); - - final List ports = service.getSpec().getPorts(); - V1ServicePort port = null; - if (ports.size() == 1) { - port = ports.get(0); - } - else if (ports.size() > 1 && StringUtils.hasText(this.properties.getPortName())) { - Optional optPort = ports.stream() - .filter(it -> properties.getPortName().endsWith(it.getName())).findAny(); - if (optPort.isPresent()) { - port = optPort.get(); - } - } - if (port == null) { - return null; - } - final String host = KubernetesServiceInstanceMapper.createHost(service.getMetadata().getName(), - service.getMetadata().getNamespace(), properties.getClusterDomain()); - final boolean secure = KubernetesServiceInstanceMapper.isSecure(service.getMetadata().getLabels(), - service.getMetadata().getAnnotations(), port.getName(), port.getPort()); - return new DefaultKubernetesServiceInstance(meta.getUid(), meta.getName(), host, port.getPort(), - getServiceMetadata(service), secure); - } - - private Map getServiceMetadata(V1Service service) { - final Map serviceMetadata = new HashMap<>(); - KubernetesDiscoveryProperties.Metadata metadataProps = this.discoveryProperties.metadata(); - if (metadataProps.addLabels()) { - Map labelMetadata = KubernetesServiceInstanceMapper - .getMapWithPrefixedKeys(service.getMetadata().getLabels(), metadataProps.labelsPrefix()); - serviceMetadata.putAll(labelMetadata); - } - if (metadataProps.addAnnotations()) { - Map annotationMetadata = KubernetesServiceInstanceMapper - .getMapWithPrefixedKeys(service.getMetadata().getAnnotations(), metadataProps.annotationsPrefix()); - serviceMetadata.putAll(annotationMetadata); - } - - return serviceMetadata; - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplier.java b/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplier.java deleted file mode 100644 index 2d6cb01026..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplier.java +++ /dev/null @@ -1,86 +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.loadbalancer; - -import java.util.ArrayList; -import java.util.List; - -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1Service; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import reactor.core.publisher.Flux; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServicesListSupplier; -import org.springframework.core.env.Environment; - -/** - * @author Ryan Baxter - */ -public class KubernetesClientServicesListSupplier extends KubernetesServicesListSupplier { - - private static final Log LOG = LogFactory.getLog(KubernetesClientServicesListSupplier.class); - - private CoreV1Api coreV1Api; - - private KubernetesClientProperties kubernetesClientProperties; - - private KubernetesNamespaceProvider kubernetesNamespaceProvider; - - public KubernetesClientServicesListSupplier(Environment environment, KubernetesServiceInstanceMapper mapper, - KubernetesDiscoveryProperties discoveryProperties, CoreV1Api coreV1Api, - KubernetesNamespaceProvider kubernetesNamespaceProvider) { - super(environment, mapper, discoveryProperties); - this.coreV1Api = coreV1Api; - this.kubernetesNamespaceProvider = kubernetesNamespaceProvider; - } - - private String getNamespace() { - return kubernetesNamespaceProvider != null ? kubernetesNamespaceProvider.getNamespace() - : kubernetesClientProperties.namespace(); - } - - @Override - public Flux> get() { - LOG.info("Getting services with id " + this.getServiceId()); - List result = new ArrayList<>(); - List services; - try { - if (discoveryProperties.allNamespaces()) { - services = coreV1Api.listServiceForAllNamespaces(null, null, "metadata.name=" + this.getServiceId(), - null, null, null, null, null, null, null).getItems(); - } - else { - services = coreV1Api.listNamespacedService(getNamespace(), null, null, null, - "metadata.name=" + this.getServiceId(), null, null, null, null, null, null).getItems(); - } - services.forEach(service -> result.add(mapper.map(service))); - } - catch (ApiException e) { - LOG.warn("Error retrieving service with name " + this.getServiceId(), e); - } - LOG.info("Returning services: " + result); - return Flux.defer(() -> Flux.just(result)); - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-kubernetes-client-loadbalancer/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index e2edbe021b..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -org.springframework.cloud.kubernetes.client.loadbalancer.KubernetesClientLoadBalancerAutoConfiguration diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerPodModeTests.java b/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerPodModeTests.java deleted file mode 100644 index bfc95cf5bb..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerPodModeTests.java +++ /dev/null @@ -1,113 +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.loadbalancer; - -import java.io.IOException; -import java.util.Collections; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.mock.http.client.MockClientHttpResponse; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = KubernetesClientLoadBalancerPodModeTests.App.class) -public class KubernetesClientLoadBalancerPodModeTests { - - @Autowired - private RestTemplate restTemplate; - - @Test - public void testLoadBalancer() { - String resp = restTemplate.getForObject("http://servicea-wiremock", String.class); - assertThat(resp).isEqualTo("hello"); - } - - @SpringBootApplication - static class App { - - @Bean - public ApiClient apiClient() { - return new ClientBuilder().build(); - } - - @Bean - public BlockingLoadBalancerClient blockingLoadBalancerClient() { - BlockingLoadBalancerClient client = mock(BlockingLoadBalancerClient.class); - try { - ClientHttpResponse response = new MockClientHttpResponse("hello".getBytes(), HttpStatus.OK); - when(client.execute(eq("servicea-wiremock"), any(LoadBalancerRequest.class))).thenReturn(response); - when(client.execute(eq("servicea-wiremock"), any(ServiceInstance.class), - any(LoadBalancerRequest.class))).thenReturn(response); - } - catch (IOException e) { - e.printStackTrace(); - } - return client; - } - - @Bean - public KubernetesNamespaceProvider kubernetesNamespaceProvider() { - KubernetesNamespaceProvider provider = mock(KubernetesNamespaceProvider.class); - when(provider.getNamespace()).thenReturn("test"); - return provider; - } - - @Bean - public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient() { - KubernetesInformerDiscoveryClient client = mock(KubernetesInformerDiscoveryClient.class); - ServiceInstance instance = new DefaultServiceInstance("servicea-wiremock1", "servicea-wiremock", "fake", - 8888, false); - given(client.getInstances(eq("servicea-wiremock"))).willReturn(Collections.singletonList(instance)); - return client; - } - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplateBuilder().build(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerServiceModeTests.java b/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerServiceModeTests.java deleted file mode 100644 index bebf4b072e..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientLoadBalancerServiceModeTests.java +++ /dev/null @@ -1,148 +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.loadbalancer; - -import java.io.IOException; - -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.openapi.models.V1ServiceListBuilder; -import io.kubernetes.client.openapi.models.V1ServicePortBuilder; -import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest; -import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.mock.http.client.MockClientHttpResponse; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = KubernetesClientLoadBalancerServiceModeTests.App.class, - properties = { "spring.cloud.kubernetes.loadbalancer.mode=SERVICE" }) -public class KubernetesClientLoadBalancerServiceModeTests { - - private static final V1ServiceList SERVICE_LIST = new V1ServiceListBuilder() - .addToItems( - new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("servicea-wiremock") - .withNamespace("default").withResourceVersion("1").addToLabels("beta", "true") - .addToAnnotations("org.springframework.cloud", "true").withUid("0").build()) - .withSpec(new V1ServiceSpecBuilder().withClusterIP("10.96.0.1").withSessionAffinity("None") - .withType("ClusterIP") - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http") - .withProtocol("TCP").withNewTargetPort(8080).build()) - .build()) - .build()) - .build(); - - @Autowired - private RestTemplate restTemplate; - - @Test - public void testLoadBalancer() { - String resp = restTemplate.getForObject("http://servicea-wiremock", String.class); - assertThat(resp).isEqualTo("hello"); - } - - @SpringBootApplication - static class App { - - @Bean - public ApiClient apiClient() { - return new ClientBuilder().build(); - } - - @Bean - public CoreV1Api coreV1Api() { - CoreV1Api coreV1Api = mock(CoreV1Api.class); - try { - when(coreV1Api.listNamespacedService(eq("default"), eq(null), eq(null), eq(null), - eq("metadata.name=servicea-wiremock"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null))).thenReturn(SERVICE_LIST); - } - catch (ApiException e) { - e.printStackTrace(); - } - return coreV1Api; - } - - @Bean - public BlockingLoadBalancerClient blockingLoadBalancerClient() { - BlockingLoadBalancerClient client = mock(BlockingLoadBalancerClient.class); - try { - ClientHttpResponse response = new MockClientHttpResponse("hello".getBytes(), HttpStatus.OK); - when(client.execute(eq("servicea-wiremock"), any(LoadBalancerRequest.class))).thenReturn(response); - when(client.execute(eq("servicea-wiremock"), any(ServiceInstance.class), - any(LoadBalancerRequest.class))).thenReturn(response); - } - catch (IOException e) { - e.printStackTrace(); - } - return client; - } - - @Bean - public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient() { - // Mock this so the real implementation does not try to connect to the K8S API - // Server - KubernetesInformerDiscoveryClient client = mock(KubernetesInformerDiscoveryClient.class); - Mockito.when(client.getOrder()).thenReturn(0); - return client; - } - - @Bean - public KubernetesNamespaceProvider kubernetesNamespaceProvider() { - KubernetesNamespaceProvider provider = mock(KubernetesNamespaceProvider.class); - when(provider.getNamespace()).thenReturn("test"); - return provider; - } - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplateBuilder().build(); - } - - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapperTests.java b/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapperTests.java deleted file mode 100644 index 7f3118dffd..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServiceInstanceMapperTests.java +++ /dev/null @@ -1,86 +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.loadbalancer; - -import java.util.HashMap; -import java.util.Map; - -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Service; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import io.kubernetes.client.openapi.models.V1ServicePortBuilder; -import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Ryan Baxter - */ -class KubernetesClientServiceInstanceMapperTests { - - @Test - void basicMap() { - KubernetesLoadBalancerProperties loadBalancerProperties = new KubernetesLoadBalancerProperties(); - KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(loadBalancerProperties, - KubernetesDiscoveryProperties.DEFAULT); - - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("database").withUid("0").withResourceVersion("0") - .withNamespace("default").addToAnnotations("org.springframework.cloud", "true") - .addToLabels("beta", "true").build()) - .withSpec(new V1ServiceSpecBuilder() - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build()) - .build(); - - KubernetesServiceInstance serviceInstance = mapper.map(service); - Map metadata = new HashMap<>(); - metadata.put("org.springframework.cloud", "true"); - metadata.put("beta", "true"); - DefaultKubernetesServiceInstance result = new DefaultKubernetesServiceInstance("0", "database", - "database.default.svc.cluster.local", 80, metadata, false); - assertThat(serviceInstance).isEqualTo(result); - } - - @Test - void multiportMap() { - KubernetesLoadBalancerProperties loadBalancerProperties = new KubernetesLoadBalancerProperties(); - loadBalancerProperties.setPortName("https"); - KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(loadBalancerProperties, - KubernetesDiscoveryProperties.DEFAULT); - - V1Service service = new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("database").withUid("0").withResourceVersion("0") - .withNamespace("default").build()) - .withSpec(new V1ServiceSpecBuilder() - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build(), - new V1ServicePortBuilder().withPort(443).withName("https").build()) - .build()) - .build(); - - KubernetesServiceInstance serviceInstance = mapper.map(service); - DefaultKubernetesServiceInstance result = new DefaultKubernetesServiceInstance("0", "database", - "database.default.svc.cluster.local", 443, new HashMap(), true); - assertThat(serviceInstance).isEqualTo(result); - } - -} diff --git a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplierTests.java b/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplierTests.java deleted file mode 100644 index b27e1386d2..0000000000 --- a/spring-cloud-kubernetes-client-loadbalancer/src/test/java/org/springframework/cloud/kubernetes/client/loadbalancer/KubernetesClientServicesListSupplierTests.java +++ /dev/null @@ -1,176 +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.loadbalancer; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.JSON; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1ServiceBuilder; -import io.kubernetes.client.openapi.models.V1ServiceList; -import io.kubernetes.client.openapi.models.V1ServicePortBuilder; -import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import reactor.test.StepVerifier; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties; -import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; -import org.springframework.mock.env.MockEnvironment; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Ryan Baxter - */ -class KubernetesClientServicesListSupplierTests { - - private static final V1ServiceList SERVICE_LIST = new V1ServiceList().addItemsItem(new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("default") - .withResourceVersion("1").addToLabels("beta", "true") - .addToAnnotations("org.springframework.cloud", "true").withUid("0").build()) - .withSpec(new V1ServiceSpecBuilder() - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build()) - .build()); - - private static final V1ServiceList SERVICE_LIST_ALL_NAMESPACE = new V1ServiceList() - .addItemsItem(new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("default") - .withResourceVersion("1").addToLabels("beta", "true") - .addToAnnotations("org.springframework.cloud", "true").withUid("0").build()) - .withSpec(new V1ServiceSpecBuilder() - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build()) - .build()) - .addItemsItem(new V1ServiceBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("test") - .withResourceVersion("1").withUid("1").build()) - .withSpec(new V1ServiceSpecBuilder() - .addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build(), - new V1ServicePortBuilder().withPort(443).withName("https").build()) - .build()) - .build()); - - private static WireMockServer wireMockServer; - - @BeforeAll - public static void setup() { - wireMockServer = new WireMockServer(options().dynamicPort()); - - wireMockServer.start(); - WireMock.configureFor("localhost", wireMockServer.port()); - - ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build(); - client.setDebugging(true); - Configuration.setDefaultApiClient(client); - } - - @AfterAll - public static void after() { - wireMockServer.stop(); - } - - @AfterEach - public void afterEach() { - WireMock.reset(); - } - - @Test - void getList() { - MockEnvironment env = new MockEnvironment(); - env.setProperty(LoadBalancerClientFactory.PROPERTY_NAME, "service1"); - KubernetesNamespaceProvider kubernetesNamespaceProvider = mock(KubernetesNamespaceProvider.class); - when(kubernetesNamespaceProvider.getNamespace()).thenReturn("default"); - CoreV1Api coreV1Api = new CoreV1Api(); - KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper( - new KubernetesLoadBalancerProperties(), KubernetesDiscoveryProperties.DEFAULT); - KubernetesClientServicesListSupplier listSupplier = new KubernetesClientServicesListSupplier(env, mapper, - KubernetesDiscoveryProperties.DEFAULT, coreV1Api, kubernetesNamespaceProvider); - - stubFor(get(urlMatching("^/api/v1/namespaces/default/services.*")) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SERVICE_LIST)))); - - Flux> instances = listSupplier.get(); - - Map metadata = new HashMap<>(); - metadata.put("org.springframework.cloud", "true"); - metadata.put("beta", "true"); - DefaultKubernetesServiceInstance service1 = new DefaultKubernetesServiceInstance("0", "service1", - "service1.default.svc.cluster.local", 80, metadata, false); - List services = new ArrayList<>(); - services.add(service1); - - StepVerifier.create(instances).expectNext(services).verifyComplete(); - } - - @Test - void getListAllNamespaces() { - MockEnvironment env = new MockEnvironment(); - env.setProperty(LoadBalancerClientFactory.PROPERTY_NAME, "service1"); - KubernetesNamespaceProvider kubernetesNamespaceProvider = mock(KubernetesNamespaceProvider.class); - when(kubernetesNamespaceProvider.getNamespace()).thenReturn("default"); - KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties(true, true, - Set.of(), true, 60, false, null, Set.of(), Map.of(), null, - KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false); - CoreV1Api coreV1Api = new CoreV1Api(); - KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper( - new KubernetesLoadBalancerProperties(), kubernetesDiscoveryProperties); - KubernetesClientServicesListSupplier listSupplier = new KubernetesClientServicesListSupplier(env, mapper, - kubernetesDiscoveryProperties, coreV1Api, kubernetesNamespaceProvider); - - stubFor(get(urlMatching("^/api/v1/services.*")) - .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SERVICE_LIST_ALL_NAMESPACE)))); - - Flux> instances = listSupplier.get(); - - Map metadata = new HashMap<>(); - metadata.put("org.springframework.cloud", "true"); - metadata.put("beta", "true"); - DefaultKubernetesServiceInstance service1 = new DefaultKubernetesServiceInstance("0", "service1", - "service1.default.svc.cluster.local", 80, metadata, false); - DefaultKubernetesServiceInstance service2 = new DefaultKubernetesServiceInstance("1", "service1", - "service1.test.svc.cluster.local", 80, new HashMap<>(), false); - List services = new ArrayList<>(); - services.add(service1); - services.add(service2); - - StepVerifier.create(instances).expectNext(services).verifyComplete(); - } - -} diff --git a/spring-cloud-kubernetes-commons/.flattened-pom.xml b/spring-cloud-kubernetes-commons/.flattened-pom.xml new file mode 100644 index 0000000000..58c80729a9 --- /dev/null +++ b/spring-cloud-kubernetes-commons/.flattened-pom.xml @@ -0,0 +1,167 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-kubernetes + 3.0.4-SNAPSHOT + + org.springframework.cloud + spring-cloud-kubernetes-commons + 3.0.4-SNAPSHOT + Spring Cloud parent pom, managing plugins and dependencies for Spring + Cloud projects + https://cloud.spring.io/spring-cloud-kubernetes-commons + 2017 + + Pivotal Software, Inc. + https://www.spring.io + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + dsyer + Dave Syer + dsyer at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + sgibb + Spencer Gibb + sgibb at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + lead + + + + mgrzejszczak + Marcin Grzejszczak + mgrzejszczak at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + rbaxter + Ryan Baxter + rbaxter at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + omaciaszeksharma + Olga Maciaszek-Sharma + omaciaszeksharma at pivotal.io + Pivotal Software, Inc. + https://www.spring.io + + developer + + + + + scm:git:git://github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-commons + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-kubernetes.git/spring-cloud-kubernetes-commons + https://github.com/spring-cloud/spring-cloud-kubernetes/spring-cloud-kubernetes-commons + + + + org.springframework.boot + spring-boot-autoconfigure + 3.0.7 + compile + + + org.springframework.cloud + spring-cloud-commons + 4.0.4-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-actuator-autoconfigure + 3.0.7 + compile + true + + + org.springframework.boot + spring-boot-configuration-processor + 3.0.7 + compile + true + + + org.springframework.integration + spring-integration-core + 6.0.5 + compile + true + + + org.springframework.cloud + spring-cloud-loadbalancer + 4.0.4-SNAPSHOT + compile + true + + + org.springframework.cloud + spring-cloud-context + 4.0.4-SNAPSHOT + compile + + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + compile + + + org.springframework.boot + spring-boot-starter-logging + 3.0.7 + compile + true + + + org.springframework.retry + spring-retry + 2.0.1 + compile + true + + + org.springframework.boot + spring-boot-starter-aop + 3.0.7 + compile + true + + + org.springframework.cloud + spring-cloud-config-client + 4.0.4-SNAPSHOT + compile + true + + + diff --git a/spring-cloud-kubernetes-commons/pom.xml b/spring-cloud-kubernetes-commons/pom.xml deleted file mode 100644 index 879d2009dc..0000000000 --- a/spring-cloud-kubernetes-commons/pom.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - org.springframework.cloud - spring-cloud-kubernetes - 3.1.0-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-commons - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - - - - - org.springframework.boot - spring-boot-autoconfigure - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.boot - spring-boot-actuator-autoconfigure - true - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.integration - spring-integration-core - true - - - org.springframework.cloud - spring-cloud-loadbalancer - true - - - org.springframework.cloud - spring-cloud-context - - - jakarta.annotation - jakarta.annotation-api - - - org.springframework.boot - spring-boot-starter-logging - true - - - org.springframework.retry - spring-retry - true - - - org.springframework.boot - spring-boot-starter-aop - true - - - org.springframework.cloud - spring-cloud-config-client - true - - - - org.springframework.boot - spring-boot-starter-test - - - org.mockito - mockito-core - - - test - - - org.junit.jupiter - junit-jupiter - test - - - org.mockito - mockito-inline - test - - - org.springframework - spring-test - test - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - test - - - - - diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesHealthIndicator.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesHealthIndicator.java deleted file mode 100644 index b2fd015123..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesHealthIndicator.java +++ /dev/null @@ -1,81 +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.commons; - -import java.util.Map; - -import org.springframework.boot.actuate.health.AbstractHealthIndicator; -import org.springframework.boot.actuate.health.Health; - -/** - * @author Ryan Baxter - */ -public abstract class AbstractKubernetesHealthIndicator extends AbstractHealthIndicator { - - /** - * Inside key. - */ - public static final String INSIDE = "inside"; - - /** - * Namespace key. - */ - public static final String NAMESPACE = "namespace"; - - /** - * Pod name key. - */ - public static final String POD_NAME = "podName"; - - /** - * Pod IP key. - */ - public static final String POD_IP = "podIp"; - - /** - * Service account key. - */ - public static final String SERVICE_ACCOUNT = "serviceAccount"; - - /** - * Node name key. - */ - public static final String NODE_NAME = "nodeName"; - - /** - * Host IP key. - */ - public static final String HOST_IP = "hostIp"; - - /** - * Labels key. - */ - public static final String LABELS = "labels"; - - @Override - protected void doHealthCheck(Health.Builder builder) { - try { - builder.up().withDetails(getDetails()); - } - catch (Exception e) { - builder.down(e); - } - } - - protected abstract Map getDetails() throws Exception; - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesInfoContributor.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesInfoContributor.java deleted file mode 100644 index 3327f19f8d..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/AbstractKubernetesInfoContributor.java +++ /dev/null @@ -1,91 +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.commons; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoContributor; - -/** - * @author Ryan Baxter - */ -public abstract class AbstractKubernetesInfoContributor implements InfoContributor { - - /** - * Kubernetes key. - */ - public static final String KUBERNETES = "kubernetes"; - - /** - * Inside key. - */ - public static final String INSIDE = "inside"; - - /** - * Namespace key. - */ - public static final String NAMESPACE = "namespace"; - - /** - * Pod name key. - */ - public static final String POD_NAME = "podName"; - - /** - * Pod IP key. - */ - public static final String POD_IP = "podIp"; - - /** - * Service account key. - */ - public static final String SERVICE_ACCOUNT = "serviceAccount"; - - /** - * Node name key. - */ - public static final String NODE_NAME = "nodeName"; - - /** - * Host IP key. - */ - public static final String HOST_IP = "hostIp"; - - /** - * Labels key. - */ - public static final String LABELS = "labels"; - - private static final Log LOG = LogFactory.getLog(AbstractKubernetesInfoContributor.class); - - @Override - public void contribute(Info.Builder builder) { - try { - builder.withDetail(KUBERNETES, getDetails()); - } - catch (Exception e) { - LOG.warn("Failed to get pod details", e); - } - } - - public abstract Map getDetails(); - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigEnabled.java deleted file mode 100644 index b8170f4a58..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigEnabled.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019-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.commons; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Provides a more succinct conditional - * spring.cloud.kubernetes.config.enabled. - * - * @author wind57 - */ - -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnProperty(value = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true) -public @interface ConditionalOnKubernetesConfigEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigMapsOrSecretsEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigMapsOrSecretsEnabled.java deleted file mode 100644 index ac8681763b..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesConfigMapsOrSecretsEnabled.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2023 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.commons; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; -import org.springframework.context.annotation.Conditional; - -/** - * {@link Conditional @Conditional} that matches when either or both of - * {@link ConditionalOnKubernetesConfigEnabled @ConditionalOnKubernetesConfigEnabled} and - * {@link ConditionalOnKubernetesSecretsEnabled @ConditionalOnKubernetesSecretsEnabled}. - * - * @author wind57 - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnKubernetesConfigMapsOrSecretsEnabled.OnKubernetesConfigMapsOrSecretesEnabled.class) -public @interface ConditionalOnKubernetesConfigMapsOrSecretsEnabled { - - class OnKubernetesConfigMapsOrSecretesEnabled extends AnyNestedCondition { - - OnKubernetesConfigMapsOrSecretesEnabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnKubernetesConfigEnabled - static class OnConfigMapPropertiesRetryEnabled { - - } - - @ConditionalOnKubernetesSecretsEnabled - static class OnSecretsPropertiesRetryEnabled { - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesSecretsEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesSecretsEnabled.java deleted file mode 100644 index 96ae629257..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/ConditionalOnKubernetesSecretsEnabled.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019-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.commons; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Provides a more succinct conditional - * spring.cloud.kubernetes.secrets.enabled. - * - * @author wind57 - */ - -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnProperty(value = "spring.cloud.kubernetes.secrets.enabled", matchIfMissing = true) -public @interface ConditionalOnKubernetesSecretsEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/EnvReader.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/EnvReader.java deleted file mode 100644 index 1b0750ee0e..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/EnvReader.java +++ /dev/null @@ -1,33 +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.commons; - -/** - * @author wind57 - * - * a class that should be used instead of System::getEnv, uselfull for testing - */ -public final class EnvReader { - - private EnvReader() { - } - - public static String getEnv(String property) { - return System.getenv(property); - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesClientProperties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesClientProperties.java deleted file mode 100644 index f9dc5a6990..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesClientProperties.java +++ /dev/null @@ -1,69 +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.commons; - -import java.time.Duration; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.DefaultValue; - -import static org.springframework.cloud.kubernetes.commons.KubernetesClientProperties.PREFIX; - -/** - * Kubernetes client properties. - * - * @author Ioannis Canellos - */ -@ConfigurationProperties(PREFIX) -public record KubernetesClientProperties(Boolean trustCerts, String masterUrl, String apiVersion, String namespace, - String caCertFile, String caCertData, String clientCertFile, String clientCertData, String clientKeyFile, - String clientKeyData, String clientKeyAlgo, String clientKeyPassphrase, String username, String password, - Duration watchReconnectInterval, Duration watchReconnectLimit, Duration connectionTimeout, - Duration requestTimeout, @Deprecated(forRemoval = true) Duration rollingTimeout, Duration loggingInterval, - String httpProxy, String httpsProxy, String proxyUsername, String proxyPassword, String oauthToken, - String[] noProxy, @DefaultValue(SERVICE_ACCOUNT_NAMESPACE_PATH) String serviceAccountNamespacePath, - @DefaultValue(DEFAULT_USER_AGENT) String userAgent) { - - /** - * Configuration properties prefix. - */ - public static final String PREFIX = "spring.cloud.kubernetes.client"; - - /** - * Default user-agent for kubernetes client. - */ - public static final String DEFAULT_USER_AGENT = "Spring-Cloud-Kubernetes-Application"; - - /** - * Default path for namespace file. - */ - public static final String SERVICE_ACCOUNT_NAMESPACE_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"; - - /** - * copy constructor that only changes the namespace. - */ - public KubernetesClientProperties withNamespace(String namespace) { - return new KubernetesClientProperties(this.trustCerts(), this.masterUrl(), this.apiVersion(), namespace, - this.caCertFile(), this.caCertData(), this.clientCertFile(), this.clientCertData(), - this.clientKeyFile(), this.clientKeyData(), this.clientKeyAlgo(), this.clientKeyPassphrase(), - this.username(), this.password(), this.watchReconnectInterval(), this.watchReconnectLimit(), - this.connectionTimeout(), this.requestTimeout(), this.rollingTimeout(), this.loggingInterval(), - this.httpProxy(), this.httpsProxy(), this.proxyUsername(), this.proxyPassword(), this.oauthToken(), - this.noProxy(), this.serviceAccountNamespacePath(), this.userAgent()); - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesCommonsAutoConfiguration.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesCommonsAutoConfiguration.java deleted file mode 100644 index 523d6e78c4..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesCommonsAutoConfiguration.java +++ /dev/null @@ -1,32 +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.commons; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -/** - * @author Ryan Baxter - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@EnableConfigurationProperties(KubernetesClientProperties.class) -public class KubernetesCommonsAutoConfiguration { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesNamespaceProvider.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesNamespaceProvider.java deleted file mode 100644 index fa8d2ab473..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/KubernetesNamespaceProvider.java +++ /dev/null @@ -1,119 +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.commons; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.springframework.boot.context.properties.bind.BindHandler; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.logging.DeferredLog; -import org.springframework.core.env.Environment; -import org.springframework.util.ObjectUtils; - -import static org.springframework.cloud.kubernetes.commons.KubernetesClientProperties.SERVICE_ACCOUNT_NAMESPACE_PATH; - -/** - * @author Ryan Baxter - */ -public class KubernetesNamespaceProvider { - - private static final DeferredLog LOG = new DeferredLog(); - - /** - * Property name for namespace. - */ - public static final String NAMESPACE_PROPERTY = "spring.cloud.kubernetes.client.namespace"; - - /** - * Property for namespace file path. - */ - public static final String NAMESPACE_PATH_PROPERTY = "spring.cloud.kubernetes.client.serviceAccountNamespacePath"; - - private BindHandler bindHandler; - - private String serviceAccountNamespace; - - private Environment environment; - - private Binder binder; - - public KubernetesNamespaceProvider(Environment env) { - this.environment = env; - LOG.replayTo(KubernetesNamespaceProvider.class); - } - - public KubernetesNamespaceProvider(Binder binder, BindHandler bindHandler) { - this.binder = binder; - this.bindHandler = bindHandler; - } - - public String getNamespace() { - String namespace = null; - if (environment != null) { - namespace = environment.getProperty(NAMESPACE_PROPERTY); - } - if (ObjectUtils.isEmpty(namespace) && binder != null) { - namespace = binder.bind(NAMESPACE_PROPERTY, String.class).orElse(null); - } - return namespace != null ? namespace : getServiceAccountNamespace(); - } - - private String getServiceAccountNamespace() { - String serviceAccountNamespacePathString = null; - if (environment != null) { - serviceAccountNamespacePathString = environment.getProperty(NAMESPACE_PATH_PROPERTY, - SERVICE_ACCOUNT_NAMESPACE_PATH); - } - if (ObjectUtils.isEmpty(serviceAccountNamespacePathString) && binder != null) { - // When using the binder we cannot use camelcase properties, it considers them - // invalid - serviceAccountNamespacePathString = binder - .bind("spring.cloud.kubernetes.client.service-account-namespace-path", Bindable.of(String.class), - bindHandler) - .orElse(SERVICE_ACCOUNT_NAMESPACE_PATH); - } - if (serviceAccountNamespace == null) { - serviceAccountNamespace = getNamespaceFromServiceAccountFile(serviceAccountNamespacePathString); - } - return serviceAccountNamespace; - } - - public static String getNamespaceFromServiceAccountFile(String path) { - String namespace = null; - LOG.debug("Looking for service account namespace at: [" + path + "]."); - Path serviceAccountNamespacePath = Paths.get(path); - boolean serviceAccountNamespaceExists = Files.isRegularFile(serviceAccountNamespacePath); - if (serviceAccountNamespaceExists) { - LOG.debug("Found service account namespace at: [" + serviceAccountNamespacePath + "]."); - - try { - namespace = new String(Files.readAllBytes((serviceAccountNamespacePath))); - LOG.debug("Service account namespace value: " + serviceAccountNamespacePath); - } - catch (IOException ioe) { - LOG.error("Error reading service account namespace from: [" + serviceAccountNamespacePath + "].", ioe); - } - - } - return namespace; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/LazilyInstantiate.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/LazilyInstantiate.java deleted file mode 100644 index 3d0187e621..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/LazilyInstantiate.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.commons; - -import java.util.function.Supplier; - -/** - * Lazy instantiation utility class. - * - * @param return type - * @author Ioannis Canellos - */ -public final class LazilyInstantiate implements Supplier { - - private volatile T t; - - private final Supplier supplier; - - private LazilyInstantiate(Supplier supplier) { - this.supplier = supplier; - } - - public static LazilyInstantiate using(Supplier supplier) { - return new LazilyInstantiate<>(supplier); - } - - public T get() { - T localT = t; - if (localT == null) { - synchronized (this) { - localT = t; - if (localT == null) { - localT = supplier.get(); - t = localT; - } - } - } - return localT; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/PodUtils.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/PodUtils.java deleted file mode 100644 index 5a4a452d50..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/PodUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.commons; - -import java.util.function.Supplier; - -/** - * Utility interface to retrieve Pod related information. - * - * @author Ioannis Canellos - */ -public interface PodUtils { - - /** - * @return A supplier of the current Pod. The supplier will hold the current Pod if - * inside Kubernetes or null, otherwise. - */ - Supplier currentPod(); - - /** - * @return true if called from within Kubernetes, false otherwise. - */ - boolean isInsideKubernetes(); - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesAndConfigEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesAndConfigEnabled.java deleted file mode 100644 index 75f5bcccb4..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesAndConfigEnabled.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesConfigEnabled; - -/** - * @author Haytham Mohamed - **/ - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnKubernetesConfigEnabled -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -public @interface ConditionalOnKubernetesAndConfigEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigFailFastEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigFailFastEnabled.java deleted file mode 100644 index 96493a40d7..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigFailFastEnabled.java +++ /dev/null @@ -1,41 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Provides a more succinct conditional - * spring.cloud.kubernetes.config.fail-fast. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnProperty(prefix = ConfigMapConfigProperties.PREFIX, name = "fail-fast", havingValue = "true") -public @interface ConditionalOnKubernetesConfigFailFastEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigOrSecretsRetryEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigOrSecretsRetryEnabled.java deleted file mode 100644 index 5734dd35f5..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigOrSecretsRetryEnabled.java +++ /dev/null @@ -1,62 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; -import org.springframework.context.annotation.Conditional; - -/** - * {@link Conditional @Conditional} that matches when either or both of - * {@link ConditionalOnKubernetesConfigRetryEnabled @ConditionalOnKubernetesConfigRetryEnabled} - * and - * {@link ConditionalOnKubernetesSecretsRetryEnabled @ConditionalOnKubernetesSecretsRetryEnabled}. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnKubernetesConfigOrSecretsRetryEnabled.OnKubernetesConfigPropertiesRetryEnabled.class) -public @interface ConditionalOnKubernetesConfigOrSecretsRetryEnabled { - - class OnKubernetesConfigPropertiesRetryEnabled extends AnyNestedCondition { - - OnKubernetesConfigPropertiesRetryEnabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnKubernetesConfigRetryEnabled - static class OnConfigMapPropertiesRetryEnabled { - - } - - @ConditionalOnKubernetesSecretsRetryEnabled - static class OnSecretsPropertiesRetryEnabled { - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryDisabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryDisabled.java deleted file mode 100644 index b3f4a56634..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryDisabled.java +++ /dev/null @@ -1,56 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; -import org.springframework.context.annotation.Conditional; - -/** - * {@link Conditional @Conditional} that matches when at least one of Spring Cloud - * Kubernetes, Kubernetes ConfigMap property sources or Kubernetes ConfigMap property - * sources fail fast (thus retry) is disabled. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnKubernetesConfigRetryDisabled.OnConfigMapPropertiesRetryDisabled.class) -public @interface ConditionalOnKubernetesConfigRetryDisabled { - - class OnConfigMapPropertiesRetryDisabled extends NoneNestedConditions { - - OnConfigMapPropertiesRetryDisabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnKubernetesConfigRetryEnabled - static class OnConfigMapPropertiesRetryEnabled { - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryEnabled.java deleted file mode 100644 index 07aca74f7e..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesConfigRetryEnabled.java +++ /dev/null @@ -1,49 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesConfigEnabled; - -/** - * {@link org.springframework.context.annotation.Conditional @Conditional} that only - * matches when Spring Cloud Kubernetes, Kubernetes config, Kubernetes config fail-fast - * and Kubernetes config retry are enabled. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@ConditionalOnKubernetesConfigEnabled -@ConditionalOnKubernetesConfigFailFastEnabled -@ConditionalOnProperty(prefix = ConfigMapConfigProperties.PREFIX + ".retry", name = "enabled", havingValue = "true", - matchIfMissing = true) -public @interface ConditionalOnKubernetesConfigRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsFailFastEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsFailFastEnabled.java deleted file mode 100644 index 1ebbffc0e1..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsFailFastEnabled.java +++ /dev/null @@ -1,41 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Provides a more succinct conditional - * spring.cloud.kubernetes.secrets.fail-fast. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnProperty(prefix = SecretsConfigProperties.PREFIX, name = "fail-fast", havingValue = "true") -public @interface ConditionalOnKubernetesSecretsFailFastEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryDisabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryDisabled.java deleted file mode 100644 index fc9a0840e6..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryDisabled.java +++ /dev/null @@ -1,56 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; -import org.springframework.context.annotation.Conditional; - -/** - * {@link Conditional @Conditional} that matches when at least one of Spring Cloud - * Kubernetes, Kubernetes Secret property sources or Kubernetes Secret property sources - * fail fast (thus retry) is disabled. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnKubernetesSecretsRetryDisabled.OnSecretsPropertiesRetryDisabled.class) -public @interface ConditionalOnKubernetesSecretsRetryDisabled { - - class OnSecretsPropertiesRetryDisabled extends NoneNestedConditions { - - OnSecretsPropertiesRetryDisabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnKubernetesSecretsRetryEnabled - static class OnSecretsPropertiesRetryEnabled { - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryEnabled.java deleted file mode 100644 index 8845c87cb7..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConditionalOnKubernetesSecretsRetryEnabled.java +++ /dev/null @@ -1,49 +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.commons.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesSecretsEnabled; - -/** - * {@link org.springframework.context.annotation.Conditional @Conditional} that only - * matches when Spring Cloud Kubernetes, Kubernetes secrets, Kubernetes secrets fail-fast - * and Kubernetes secrets retry are enabled. - * - * @author Isik Erhan - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@ConditionalOnKubernetesSecretsEnabled -@ConditionalOnKubernetesSecretsFailFastEnabled -@ConditionalOnProperty(prefix = SecretsConfigProperties.PREFIX + ".retry", name = "enabled", havingValue = "true", - matchIfMissing = true) -public @interface ConditionalOnKubernetesSecretsRetryEnabled { - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableConfigMapPropertySourceLocator.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableConfigMapPropertySourceLocator.java deleted file mode 100644 index 3abae46b88..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableConfigMapPropertySourceLocator.java +++ /dev/null @@ -1,88 +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.commons.config; - -import java.util.Collection; - -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.retry.support.RetryTemplate; - -/** - * ConfigMapPropertySourceLocator for when retry is enabled. - * - * @author Ryan Baxter - */ -public class ConfigDataRetryableConfigMapPropertySourceLocator extends ConfigMapPropertySourceLocator { - - private final RetryTemplate retryTemplate; - - private ConfigMapPropertySourceLocator configMapPropertySourceLocator; - - /** - * This constructor is deprecated, and we do not use it anymore internally. It will be - * removed in the next major release. - */ - @Deprecated(forRemoval = true) - public ConfigDataRetryableConfigMapPropertySourceLocator( - ConfigMapPropertySourceLocator configMapPropertySourceLocator, ConfigMapConfigProperties properties) { - super(properties); - this.configMapPropertySourceLocator = configMapPropertySourceLocator; - this.retryTemplate = RetryTemplate.builder().maxAttempts(properties.retry().maxAttempts()) - .exponentialBackoff(properties.retry().initialInterval(), properties.retry().multiplier(), - properties.retry().maxInterval()) - .build(); - } - - public ConfigDataRetryableConfigMapPropertySourceLocator( - ConfigMapPropertySourceLocator configMapPropertySourceLocator, ConfigMapConfigProperties properties, - ConfigMapCache cache) { - super(properties, cache); - this.configMapPropertySourceLocator = configMapPropertySourceLocator; - this.retryTemplate = RetryTemplate.builder().maxAttempts(properties.retry().maxAttempts()) - .exponentialBackoff(properties.retry().initialInterval(), properties.retry().multiplier(), - properties.retry().maxInterval()) - .build(); - } - - @Override - protected MapPropertySource getMapPropertySource(NormalizedSource normalizedSource, - ConfigurableEnvironment environment) { - return configMapPropertySourceLocator.getMapPropertySource(normalizedSource, environment); - } - - @Override - public PropertySource locate(Environment environment) { - return retryTemplate.execute(retryContext -> configMapPropertySourceLocator.locate(environment)); - } - - @Override - public Collection> locateCollection(Environment environment) { - return retryTemplate.execute(retryContext -> configMapPropertySourceLocator.locateCollection(environment)); - } - - public void setConfigMapPropertySourceLocator(ConfigMapPropertySourceLocator configMapPropertySourceLocator) { - this.configMapPropertySourceLocator = configMapPropertySourceLocator; - } - - public ConfigMapPropertySourceLocator getConfigMapPropertySourceLocator() { - return configMapPropertySourceLocator; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableSecretsPropertySourceLocator.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableSecretsPropertySourceLocator.java deleted file mode 100644 index 3cc71e96d5..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigDataRetryableSecretsPropertySourceLocator.java +++ /dev/null @@ -1,86 +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.commons.config; - -import java.util.Collection; - -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; -import org.springframework.retry.support.RetryTemplate; - -/** - * SecretsPropertySourceLocator for when retry is enabled. - * - * @author Ryan Baxter - */ -public class ConfigDataRetryableSecretsPropertySourceLocator extends SecretsPropertySourceLocator { - - private final RetryTemplate retryTemplate; - - private SecretsPropertySourceLocator secretsPropertySourceLocator; - - /** - * This constructor is deprecated, and we do not use it anymore internally. It will be - * removed in the next major release. - */ - @Deprecated(forRemoval = true) - public ConfigDataRetryableSecretsPropertySourceLocator(SecretsPropertySourceLocator propertySourceLocator, - SecretsConfigProperties secretsConfigProperties) { - super(secretsConfigProperties); - this.secretsPropertySourceLocator = propertySourceLocator; - this.retryTemplate = RetryTemplate.builder().maxAttempts(properties.retry().maxAttempts()) - .exponentialBackoff(properties.retry().initialInterval(), properties.retry().multiplier(), - properties.retry().maxInterval()) - .build(); - } - - public ConfigDataRetryableSecretsPropertySourceLocator(SecretsPropertySourceLocator propertySourceLocator, - SecretsConfigProperties secretsConfigProperties, SecretsCache cache) { - super(secretsConfigProperties, cache); - this.secretsPropertySourceLocator = propertySourceLocator; - this.retryTemplate = RetryTemplate.builder().maxAttempts(properties.retry().maxAttempts()) - .exponentialBackoff(properties.retry().initialInterval(), properties.retry().multiplier(), - properties.retry().maxInterval()) - .build(); - } - - @Override - public PropertySource locate(Environment environment) { - return retryTemplate.execute(retryContext -> secretsPropertySourceLocator.locate(environment)); - } - - @Override - public Collection> locateCollection(Environment environment) { - return retryTemplate.execute(retryContext -> secretsPropertySourceLocator.locateCollection(environment)); - } - - @Override - protected SecretsPropertySource getPropertySource(ConfigurableEnvironment environment, - NormalizedSource normalizedSource) { - return this.secretsPropertySourceLocator.getPropertySource(environment, normalizedSource); - } - - public SecretsPropertySourceLocator getSecretsPropertySourceLocator() { - return secretsPropertySourceLocator; - } - - public void setSecretsPropertySourceLocator(SecretsPropertySourceLocator secretsPropertySourceLocator) { - this.secretsPropertySourceLocator = secretsPropertySourceLocator; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapCache.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapCache.java deleted file mode 100644 index 8c55724660..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapCache.java +++ /dev/null @@ -1,41 +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.commons.config; - -/** - * @author wind57 - */ -public interface ConfigMapCache { - - /** - * Discards all stored entries from the cache. - */ - void discardAll(); - - /** - * an implementation that does nothing. In the next major release it will become - * absolute and must be removed. - */ - class NOOPCache implements ConfigMapCache { - - @Override - public void discardAll() { - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapConfigProperties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapConfigProperties.java deleted file mode 100644 index 2b3fc5ba16..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapConfigProperties.java +++ /dev/null @@ -1,119 +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.commons.config; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.DefaultValue; -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName; - -/** - * Config map configuration properties. - * - * @author Ioannis Canellos - * @author Isik Erhan - */ -@ConfigurationProperties(ConfigMapConfigProperties.PREFIX) -public record ConfigMapConfigProperties(@DefaultValue("true") boolean enableApi, @DefaultValue List paths, - @DefaultValue List sources, @DefaultValue Map labels, - @DefaultValue("true") boolean enabled, String name, String namespace, boolean useNameAsPrefix, - @DefaultValue("true") boolean includeProfileSpecificSources, boolean failFast, - @DefaultValue RetryProperties retry) { - - /** - * Prefix for Kubernetes config maps configuration properties. - */ - public static final String PREFIX = "spring.cloud.kubernetes.config"; - - /** - * @return A list of config map source(s) to use. - */ - public List determineSources(Environment environment) { - if (this.sources.isEmpty()) { - List result = new ArrayList<>(2); - String name = getApplicationName(environment, this.name, "ConfigMap"); - result.add(new NamedConfigMapNormalizedSource(name, this.namespace, this.failFast, - this.includeProfileSpecificSources)); - - if (!labels.isEmpty()) { - result.add(new LabeledConfigMapNormalizedSource(this.namespace, this.labels, this.failFast, - ConfigUtils.Prefix.DEFAULT, false)); - } - return result; - } - - return this.sources - .stream().flatMap(s -> s.normalize(this.name, this.namespace, this.labels, - this.includeProfileSpecificSources, this.failFast, this.useNameAsPrefix, environment)) - .collect(Collectors.toList()); - } - - /** - * Config map source. - * @param name The name of the ConfigMap. - * @param namespace The namespace where the ConfigMap is found. - * @param labels labels of the config map to look for against. - * @param explicitPrefix An explicit prefix to be used for properties. - * @param useNameAsPrefix Use config map name as prefix for properties. - * @param includeProfileSpecificSources Use profile name to append to a config map - * name. - */ - public record Source(String name, String namespace, @DefaultValue Map labels, String explicitPrefix, - Boolean useNameAsPrefix, Boolean includeProfileSpecificSources) { - - private Stream normalize(String defaultName, String defaultNamespace, - Map defaultLabels, boolean defaultIncludeProfileSpecificSources, boolean failFast, - boolean defaultUseNameAsPrefix, Environment environment) { - - Stream.Builder normalizedSources = Stream.builder(); - - String normalizedName = StringUtils.hasLength(this.name) ? this.name : defaultName; - String normalizedNamespace = StringUtils.hasLength(this.namespace) ? this.namespace : defaultNamespace; - Map normalizedLabels = this.labels.isEmpty() ? defaultLabels : this.labels; - - String configMapName = getApplicationName(environment, normalizedName, "Config Map"); - - ConfigUtils.Prefix prefix = ConfigUtils.findPrefix(this.explicitPrefix, this.useNameAsPrefix, - defaultUseNameAsPrefix, normalizedName); - - boolean includeProfileSpecificSources = ConfigUtils.includeProfileSpecificSources( - defaultIncludeProfileSpecificSources, this.includeProfileSpecificSources); - NormalizedSource namedBasedSource = new NamedConfigMapNormalizedSource(configMapName, normalizedNamespace, - failFast, prefix, includeProfileSpecificSources); - normalizedSources.add(namedBasedSource); - - if (!normalizedLabels.isEmpty()) { - NormalizedSource labeledBasedSource = new LabeledConfigMapNormalizedSource(normalizedNamespace, labels, - failFast, prefix, includeProfileSpecificSources); - normalizedSources.add(labeledBasedSource); - } - - return normalizedSources.build(); - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapPropertySourceLocator.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapPropertySourceLocator.java deleted file mode 100644 index 1ca300b5bb..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigMapPropertySourceLocator.java +++ /dev/null @@ -1,152 +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.commons.config; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.bootstrap.config.PropertySourceLocator; -import org.springframework.core.env.CompositePropertySource; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; - -import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES; -import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP; -import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.yamlParserGenerator; - -/** - * A {@link PropertySourceLocator} that uses config maps. - * - * @author Ioannis Canellos - * @author Michael Moudatsos - * @author Isik Erhan - */ -public abstract class ConfigMapPropertySourceLocator implements PropertySourceLocator { - - private static final Log LOG = LogFactory.getLog(ConfigMapPropertySourceLocator.class); - - private final ConfigMapCache cache; - - protected final ConfigMapConfigProperties properties; - - /** - * This constructor is deprecated, and we do not use it anymore internally. It will be - * removed in the next major release. - */ - @Deprecated(forRemoval = true) - public ConfigMapPropertySourceLocator(ConfigMapConfigProperties properties) { - this.properties = properties; - this.cache = new ConfigMapCache.NOOPCache(); - } - - public ConfigMapPropertySourceLocator(ConfigMapConfigProperties properties, ConfigMapCache cache) { - this.properties = properties; - this.cache = cache; - } - - protected abstract MapPropertySource getMapPropertySource(NormalizedSource normalizedSource, - ConfigurableEnvironment environment); - - @Override - public PropertySource locate(Environment environment) { - if (environment instanceof ConfigurableEnvironment env) { - - CompositePropertySource composite = new CompositePropertySource("composite-configmap"); - if (this.properties.enableApi()) { - Set sources = new LinkedHashSet<>(this.properties.determineSources(environment)); - LOG.debug("Config Map normalized sources : " + sources); - sources.forEach(s -> composite.addFirstPropertySource(getMapPropertySource(s, env))); - } - - addPropertySourcesFromPaths(environment, composite); - - cache.discardAll(); - return composite; - } - return null; - } - - @Override - public Collection> locateCollection(Environment environment) { - return PropertySourceLocator.super.locateCollection(environment); - } - - private void addPropertySourcesFromPaths(Environment environment, CompositePropertySource composite) { - Set uniquePaths = new LinkedHashSet<>(properties.paths()); - if (!uniquePaths.isEmpty()) { - LOG.warn( - "path support is deprecated and will be removed in a future release. Please use spring.config.import"); - } - LOG.debug("paths property sources : " + uniquePaths); - uniquePaths.stream().map(Paths::get).filter(p -> { - boolean exists = Files.exists(p); - if (!exists) { - LOG.warn("Configured input path: " + p - + " will be ignored because it does not exist on the file system"); - } - return exists; - }).filter(p -> { - boolean regular = Files.isRegularFile(p); - if (!regular) { - LOG.warn("Configured input path: " + p + " will be ignored because it is not a regular file"); - } - return regular; - }).toList().forEach(p -> { - try { - String content = new String(Files.readAllBytes(p)).trim(); - String filename = p.toAbsolutePath().toString().toLowerCase(); - if (filename.endsWith(".properties")) { - addPropertySourceIfNeeded(c -> PROPERTIES_TO_MAP.apply(KEY_VALUE_TO_PROPERTIES.apply(c)), content, - filename, composite); - } - else if (filename.endsWith(".yml") || filename.endsWith(".yaml")) { - addPropertySourceIfNeeded(c -> PROPERTIES_TO_MAP.apply(yamlParserGenerator(environment).apply(c)), - content, filename, composite); - } - } - catch (IOException e) { - LOG.warn("Error reading input file", e); - } - }); - } - - private void addPropertySourceIfNeeded(Function> contentToMapFunction, String content, - String name, CompositePropertySource composite) { - - Map map = new HashMap<>(contentToMapFunction.apply(content)); - if (map.isEmpty()) { - LOG.warn("Property source: " + name + "will be ignored because no properties could be found"); - } - else { - LOG.debug("will add file-based property source : " + name); - composite.addFirstPropertySource(new MountConfigMapPropertySource(name, map)); - } - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigUtils.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigUtils.java deleted file mode 100644 index 60197c3964..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/ConfigUtils.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.commons.config; - -import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.BootstrapRegistry; -import org.springframework.boot.ConfigurableBootstrapContext; -import org.springframework.core.env.Environment; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.kubernetes.commons.config.Constants.FALLBACK_APPLICATION_NAME; -import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR; -import static org.springframework.cloud.kubernetes.commons.config.Constants.SPRING_APPLICATION_NAME; - -/** - * Utility class that works with configuration properties. - * - * @author Ioannis Canellos - */ -public final class ConfigUtils { - - private static final Log LOG = LogFactory.getLog(ConfigUtils.class); - - private ConfigUtils() { - } - - public static String getApplicationName(Environment env, String configName, String configurationTarget) { - if (!StringUtils.hasLength(configName)) { - LOG.debug(configurationTarget + " name has not been set, taking it from property/env " - + SPRING_APPLICATION_NAME + " (default=" + FALLBACK_APPLICATION_NAME + ")"); - configName = env.getProperty(SPRING_APPLICATION_NAME, FALLBACK_APPLICATION_NAME); - } - - return configName; - } - - /** - * @param explicitPrefix value of - * 'spring.cloud.kubernetes.config|secrets.sources.explicitPrefix' - * @param useNameAsPrefix value of - * 'spring.cloud.kubernetes.config|secrets.sources.useNameAsPrefix' - * @param defaultUseNameAsPrefix value of - * 'spring.cloud.kubernetes.config|secrets.defaultUseNameAsPrefix' - * @param normalizedName either the name of - * 'spring.cloud.kubernetes.config|secrets.sources.name' or - * 'spring.cloud.kubernetes.config|secrets.name' - * @return prefix to use in normalized sources - */ - public static Prefix findPrefix(String explicitPrefix, Boolean useNameAsPrefix, boolean defaultUseNameAsPrefix, - String normalizedName) { - // if explicitPrefix is set, it takes priority over useNameAsPrefix - // (either the one from 'spring.cloud.kubernetes.config|secrets' or - // 'spring.cloud.kubernetes.config|secrets.sources') - if (StringUtils.hasText(explicitPrefix)) { - Prefix.computeKnown(() -> explicitPrefix); - return Prefix.KNOWN; - } - - // useNameAsPrefix is a java.lang.Boolean and if it's != null, users have - // specified it explicitly - if (useNameAsPrefix != null) { - if (useNameAsPrefix) { - // this is the case when the source is searched by labels, - // but prefix support is enabled. - // in such cases, the name is not known yet. - if (normalizedName == null) { - return Prefix.DELAYED; - } - - Prefix.computeKnown(() -> normalizedName); - return Prefix.KNOWN; - } - return Prefix.DEFAULT; - } - - if (defaultUseNameAsPrefix) { - - // this is the case when the source is searched by labels, - // but prefix support is enabled.ConfigUtilsTests - // in such cases, the name is not known yet. - if (normalizedName == null) { - return Prefix.DELAYED; - } - - Prefix.computeKnown(() -> normalizedName); - return Prefix.KNOWN; - } - - return Prefix.DEFAULT; - } - - /** - * @param defaultIncludeProfileSpecificSources value of - * 'spring.cloud.kubernetes.config.includeProfileSpecificSources' - * @param includeProfileSpecificSources value of - * 'spring.cloud.kubernetes.config.sources.includeProfileSpecificSources' - * @return useProfileNameAsPrefix to be used in normalized sources - */ - public static boolean includeProfileSpecificSources(boolean defaultIncludeProfileSpecificSources, - Boolean includeProfileSpecificSources) { - if (includeProfileSpecificSources != null) { - return includeProfileSpecificSources; - } - return defaultIncludeProfileSpecificSources; - } - - /** - * action to take when an Exception happens when dealing with a source. - */ - public static void onException(boolean failFast, Exception e) { - if (failFast) { - throw new IllegalStateException(e.getMessage(), e); - } - LOG.warn(e.getMessage() + ". Ignoring.", e); - } - - /* - * this method will return a SourceData that has a name in the form : - * "configmap.my-configmap.my-configmap-2.namespace" and the "data" from the context - * is appended with prefix. So if incoming is "a=b", the result will be : "prefix.a=b" - */ - public static SourceData withPrefix(String target, PrefixContext context) { - Map withPrefix = CollectionUtils.newHashMap(context.data().size()); - context.data().forEach((key, value) -> withPrefix.put(context.prefix() + "." + key, value)); - - String propertySourceTokens = String.join(PROPERTY_SOURCE_NAME_SEPARATOR, - context.propertySourceNames().stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new))); - return new SourceData(sourceName(target, propertySourceTokens, context.namespace()), withPrefix); - } - - public static String sourceName(String target, String applicationName, String namespace) { - return target + PROPERTY_SOURCE_NAME_SEPARATOR + applicationName + PROPERTY_SOURCE_NAME_SEPARATOR + namespace; - } - - /** - * transforms raw data from one or multiple sources into an entry of source names and - * flattened data that they all hold (potentially overriding entries without any - * defined order). - */ - public static MultipleSourcesContainer processNamedData(List strippedSources, - Environment environment, LinkedHashSet sourceNames, String namespace, boolean decode) { - - Map hashByName = strippedSources.stream() - .collect(Collectors.toMap(StrippedSourceContainer::name, Function.identity())); - - LinkedHashSet foundSourceNames = new LinkedHashSet<>(); - Map data = new HashMap<>(); - - // this is an ordered stream, and it means that non-profile based sources will be - // processed before profile based sources. This way, we replicate that - // "application-dev.yaml" - // overrides properties from "application.yaml" - sourceNames.forEach(source -> { - StrippedSourceContainer stripped = hashByName.get(source); - if (stripped != null) { - LOG.debug("Found source with name : '" + source + " in namespace: '" + namespace + "'"); - foundSourceNames.add(source); - // see if data is a single yaml/properties file and if it needs decoding - Map rawData = stripped.data(); - if (decode) { - rawData = decodeData(rawData); - } - data.putAll(SourceDataEntriesProcessor.processAllEntries(rawData == null ? Map.of() : rawData, - environment)); - } - }); - - return new MultipleSourcesContainer(foundSourceNames, data); - } - - /** - * transforms raw data from one or multiple sources into an entry of source names and - * flattened data that they all hold (potentially overriding entries without any - * defined order). This method first searches by labels, find the sources, then uses - * these names to find any profile based sources. - */ - - public static MultipleSourcesContainer processLabeledData(List containers, - Environment environment, Map labels, String namespace, Set profiles, - boolean decode) { - - // find sources by provided labels - List byLabels = containers.stream().filter(one -> { - Map sourceLabels = one.labels(); - Map labelsToSearchAgainst = sourceLabels == null ? Map.of() : sourceLabels; - return labelsToSearchAgainst.entrySet().containsAll((labels.entrySet())); - }).toList(); - - // compute profile based source names (based on the ones we found by labels) - List sourceNamesByLabelsWithProfile = new ArrayList<>(); - if (profiles != null && !profiles.isEmpty()) { - for (StrippedSourceContainer one : byLabels) { - for (String profile : profiles) { - String name = one.name() + "-" + profile; - sourceNamesByLabelsWithProfile.add(name); - } - } - } - - // once we know sources by labels (and thus their names), we can find out - // profiles based sources from the above. This would get all sources - // we are interested in. - List byProfile = containers.stream() - .filter(one -> sourceNamesByLabelsWithProfile.contains(one.name())).toList(); - - // this makes sure that we first have "app" and then "app-dev" in the list - List all = new ArrayList<>(byLabels.size() + byProfile.size()); - all.addAll(byLabels); - all.addAll(byProfile); - - LinkedHashSet sourceNames = new LinkedHashSet<>(); - Map result = new HashMap<>(); - - all.forEach(source -> { - String foundSourceName = source.name(); - LOG.debug("Loaded source with name : '" + foundSourceName + " in namespace: '" + namespace + "'"); - sourceNames.add(foundSourceName); - - Map rawData = source.data(); - if (decode) { - rawData = decodeData(rawData); - } - result.putAll(SourceDataEntriesProcessor.processAllEntries(rawData, environment)); - }); - - return new MultipleSourcesContainer(sourceNames, result); - } - - private static Map decodeData(Map data) { - Map result = new HashMap<>(CollectionUtils.newHashMap(data.size())); - data.forEach((key, value) -> result.put(key, new String(Base64.getDecoder().decode(value)).trim())); - return result; - } - - public static void registerSingle(ConfigurableBootstrapContext bootstrapContext, Class cls, T instance, - String name) { - bootstrapContext.registerIfAbsent(cls, BootstrapRegistry.InstanceSupplier.of(instance)); - bootstrapContext.addCloseListener(event -> { - if (event.getApplicationContext().getBeanFactory().getSingleton(name) == null) { - event.getApplicationContext().getBeanFactory().registerSingleton(name, - event.getBootstrapContext().get(cls)); - } - }); - } - - /** - * append prefix to the keys and return a new Map with the new values. - */ - public static Map keysWithPrefix(Map map, String prefix) { - if (map == null || map.isEmpty()) { - return Map.of(); - } - - if (!StringUtils.hasText(prefix)) { - return map; - } - - Map result = CollectionUtils.newHashMap(map.size()); - map.forEach((key, value) -> result.put(prefix + key, value)); - return result; - } - - public static final class Prefix { - - /** - * prefix has not been provided. - */ - public static final Prefix DEFAULT = new Prefix(() -> "", "DEFAULT"); - - /** - * prefix has been enabled, but the actual value will be known later; the value - * for the prefix will be the name of the source. (this is the case for a - * prefix-enabled labeled source for example) - */ - public static final Prefix DELAYED = new Prefix(() -> { - throw new IllegalArgumentException("prefix is delayed, needs to be taken elsewhere"); - }, "DELAYED"); - - /** - * prefix is known at the callsite. - */ - public static Prefix KNOWN; - - public Supplier prefixProvider() { - return prefixProvider; - } - - private final Supplier prefixProvider; - - private final String name; - - private Prefix(Supplier prefixProvider, String name) { - this.prefixProvider = prefixProvider; - this.name = name; - } - - private static void computeKnown(Supplier supplier) { - KNOWN = new Prefix(supplier, "KNOWN"); - } - - public String toString() { - return new ToStringCreator(this).append("name", name).toString(); - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/Constants.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/Constants.java deleted file mode 100644 index e8be954fb8..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/Constants.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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.commons.config; - -public final class Constants { - - /** - * Spring application name property. - */ - public static final String SPRING_APPLICATION_NAME = "spring.application.name"; - - /** - * Default application name. - */ - public static final String FALLBACK_APPLICATION_NAME = "application"; - - /** - * Property separator. - */ - public static final String PROPERTY_SOURCE_NAME_SEPARATOR = "."; - - /** - * Property for legacy profile specific configuration. - */ - public static final String SPRING_PROFILES = "spring.profiles"; - - /** - * Property for profile specific configuration. - */ - public static final String SPRING_CONFIG_ACTIVATE_ON_PROFILE = "spring.config.activate.on-profile"; - - /** - * application.yml property. - */ - public static final String APPLICATION_YML = "application.yml"; - - /** - * application.yaml property. - */ - public static final String APPLICATION_YAML = "application.yaml"; - - /** - * application.properties property. - */ - public static final String APPLICATION_PROPERTIES = "application.properties"; - - /** - * reload mode spring property. - */ - public static final String RELOAD_MODE = "spring.cloud.kubernetes.reload.mode"; - - private Constants() { - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesBootstrapConfiguration.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesBootstrapConfiguration.java deleted file mode 100644 index 48ae9f8a2d..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesBootstrapConfiguration.java +++ /dev/null @@ -1,83 +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.commons.config; - -import org.aspectj.lang.annotation.Aspect; - -import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.retry.annotation.EnableRetry; -import org.springframework.retry.annotation.Retryable; -import org.springframework.retry.interceptor.RetryInterceptorBuilder; -import org.springframework.retry.interceptor.RetryOperationsInterceptor; -import org.springframework.retry.policy.NeverRetryPolicy; - -/** - * @author Ryan Baxter - * @author Isik Erhan - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) -@EnableConfigurationProperties({ ConfigMapConfigProperties.class, SecretsConfigProperties.class }) -public class KubernetesBootstrapConfiguration { - - @ConditionalOnKubernetesConfigOrSecretsRetryEnabled - @ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class }) - @Configuration(proxyBeanMethods = false) - @EnableRetry(proxyTargetClass = true) - @Import(AopAutoConfiguration.class) - public static class RetryConfiguration { - - public static RetryOperationsInterceptor retryOperationsInterceptor(RetryProperties retryProperties) { - return RetryInterceptorBuilder.stateless().backOffOptions(retryProperties.initialInterval(), - retryProperties.multiplier(), retryProperties.maxInterval()) - .maxAttempts(retryProperties.maxAttempts()).build(); - } - - @Bean - @ConditionalOnKubernetesConfigRetryEnabled - public RetryOperationsInterceptor kubernetesConfigRetryInterceptor(ConfigMapConfigProperties configProperties) { - return retryOperationsInterceptor(configProperties.retry()); - } - - @Bean("kubernetesConfigRetryInterceptor") - @ConditionalOnKubernetesConfigRetryDisabled - public RetryOperationsInterceptor kubernetesConfigRetryInterceptorNoRetry() { - return RetryInterceptorBuilder.stateless().retryPolicy(new NeverRetryPolicy()).build(); - } - - @Bean - @ConditionalOnKubernetesSecretsRetryEnabled - public RetryOperationsInterceptor kubernetesSecretsRetryInterceptor(SecretsConfigProperties configProperties) { - return retryOperationsInterceptor(configProperties.retry()); - } - - @Bean("kubernetesSecretsRetryInterceptor") - @ConditionalOnKubernetesSecretsRetryDisabled - public RetryOperationsInterceptor kubernetesSecretsRetryInterceptorNoRetry() { - return RetryInterceptorBuilder.stateless().retryPolicy(new NeverRetryPolicy()).build(); - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java deleted file mode 100644 index 3d0ae05cf8..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java +++ /dev/null @@ -1,84 +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.commons.config; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.springframework.boot.ConfigurableBootstrapContext; -import org.springframework.boot.context.config.ConfigData; -import org.springframework.boot.context.config.ConfigData.Option; -import org.springframework.boot.context.config.ConfigDataLoader; -import org.springframework.boot.context.config.ConfigDataLoaderContext; -import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; -import org.springframework.core.Ordered; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; - -/** - * @author Ryan Baxter - */ -public class KubernetesConfigDataLoader implements ConfigDataLoader, Ordered { - - @Override - public ConfigData load(ConfigDataLoaderContext context, KubernetesConfigDataResource resource) - throws IOException, ConfigDataResourceNotFoundException { - - List> propertySources = new ArrayList<>(2); - ConfigurableBootstrapContext bootstrapContext = context.getBootstrapContext(); - Environment env = resource.getEnvironment(); - - if (bootstrapContext.isRegistered(SecretsPropertySourceLocator.class)) { - propertySources.add(bootstrapContext.get(SecretsPropertySourceLocator.class).locate(env)); - } - - if (bootstrapContext.isRegistered(ConfigMapPropertySourceLocator.class)) { - propertySources.add(bootstrapContext.get(ConfigMapPropertySourceLocator.class).locate(env)); - } - - // boot 2.4.5+ - return new ConfigData(propertySources, propertySource -> { - String propertySourceName = propertySource.getName(); - List