diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 0bbeaf27c..2aeb9bcd1 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -10,27 +10,6 @@ assignees: '' **Describe the bug** A clear and concise description of what the bug is. -NOTE: you can enable higher logging level output via the command line or env var. to help with debugging - -``` -# cmd line -./cnf-conformance -l debug test - -# make sure to use -- if running from source -crystal src/cnf-conformance.cr -- -l debug test - -# env var -LOGLEVEL=DEBUG ./cnf-conformance test -``` - -Also setting the verbose option for many tasks will add extra output to help with debugging - -``` -crystal src/cnf-conformance.cr test_name verbose -``` - -Check [usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md) for more info about invoking commands and loggin - **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' @@ -44,22 +23,35 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Workstation (please complete the following information):** - - OS [e.g. Linux] +**Device (please complete the following information):** + - OS [e.g. Linux, iOS, Windows, Android] - Distro [e.g. Ubuntu] - Version [e.g. 18.04] - Architecture [e.g. x86, arm] - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] **Additional context** Add any other context about the problem here. + +--- + +NOTE: you can enable higher logging level output via the command line or env var. to help with debugging + +``` +# cmd line +./cnf-conformance -l debug test + +# make sure to use -- if running from source +crystal src/cnf-conformance.cr -- -l debug test + +# env var +LOGLEVEL=DEBUG ./cnf-conformance test +``` + +Also setting the verbose option for many tasks will add extra output to help with debugging + +``` +crystal src/cnf-conformance.cr test_name verbose +``` + +Check [usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md) for more info about invoking commands and loggin diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1869efc53..2e5135283 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,3 @@ -# CNF Conformance PR Template - ## Description (name of issue/change) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 73df296fa..d451bc031 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -1,6 +1,64 @@ name: Crystal Specs on: [push, pull_request] jobs: + debug_status: + name: Debug Status + runs-on: ubuntu-20.04 + env: + skip_debug: ${{secrets.SKIP_DEBUG}} + release_debug: ${{secrets.RELEASE_DEBUG}} + build_debug: ${{secrets.BUILD_DEBUG}} + steps: + - name: Create Debug Files + run: | + touch skip_debug + touch release_debug + touch build_debug + if [[ "$skip_debug" == 'true' ]]; then + echo 'true' > skip_debug + fi + if [[ "$release_debug" == 'true' ]]; then + echo 'true' > release_debug + fi + if [[ "$build_debug" == 'true' ]]; then + echo 'true' > build_debug + fi + - name: upload artifact + uses: actions/upload-artifact@v2 + with: + name: debug_status + path: | + skip_debug + release_debug + build_debug + debug_output: + name: Debug Outputs + needs: [debug_status] + runs-on: ubuntu-20.04 + outputs: + skip-debug: ${{ steps.skip-debug.outputs.debug }} + release-debug: ${{ steps.release-debug.outputs.debug }} + build-debug: ${{ steps.build-debug.outputs.debug }} + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: debug_status + - id: skip-debug + run: | + if grep -q 'true' "./skip_debug"; then + echo "::set-output name=debug::true" + fi + - id: release-debug + run: | + if grep -q 'true' "./release_debug"; then + echo "::set-output name=debug::true" + fi + - id: build-debug + run: | + if grep -q 'true' "./build_debug"; then + echo "::set-output name=debug::true" + fi tests: name: Fetch Matrix Tests runs-on: ubuntu-20.04 @@ -9,36 +67,57 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 + with: + fetch-depth: 0 - id: set-matrix run: | JSON="{\"include\":[" - TEST_LIST=$(for i in $(find spec -name '*_spec.cr') + TEST_ARRAY=$(grep -roP --no-filename 'tags: \K(\[|")(.*)(\]|")' spec/ | tr -d '[],' | tr -s '\n' ' ' | xargs -n1 | sort -u | xargs) + TEST_ARRAY=("${TEST_ARRAY[@]/conformance-config-lifecycle/}") + TEST_ARRAY=("${TEST_ARRAY[@]/conformance-microservice/}") + TEST_ARRAY=("${TEST_ARRAY[@]/conformance-all/}") + + TEST_LIST=$(for i in ${TEST_ARRAY[@]} do - if ! [ "$i" == "spec/cpu_hog_spec.cr" ]; then echo "{\"spec\":\"$i\"}," | tr -d '\n' - fi done) TEST_LIST="${TEST_LIST%?}" JSON="$JSON$TEST_LIST" JSON="$JSON]}" + + echo "TESTS: $JSON" echo "::set-output name=matrix::$JSON" + + skip: + name: Skip Build + runs-on: ubuntu-20.04 + needs: [debug_output] + outputs: + skip: ${{ steps.skip.outputs.skip }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: mxschmitt/action-tmate@v3 + if: needs.debug_output.outputs.skip-debug == 'true' + - id: skip + run: | + echo "::set-output name=skip::$(.github/workflows/skip.sh)" + spec: name: Crystal Specs - needs: tests + needs: [tests, skip] runs-on: ubuntu-latest strategy: fail-fast: false matrix: ${{fromJson(needs.tests.outputs.matrix)}} + if: needs.skip.outputs.skip == 'false' steps: - name: Checkout code uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Install Clusterctl - run: | - curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.3.10/clusterctl-linux-amd64 -o clusterctl - chmod +x ./clusterctl - sudo mv ./clusterctl /usr/local/bin/clusterctl - name: Install Crystal env: CRYSTAL_VERSION: 0.35.1 @@ -56,40 +135,192 @@ jobs: && sudo rm -rf /var/lib/apt/lists/* - name: Create Kind Cluster run: | - kind create cluster + cat << EOF > /tmp/cluster.yml + kind: Cluster + apiVersion: kind.x-k8s.io/v1alpha4 + containerdConfigPatches: + - |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry:5000"] + endpoint = ["http://localhost:5000"] + EOF + kind create cluster --config=/tmp/cluster.yml kubectl get nodes + - name: Cache crystal shards + uses: actions/cache@v2 + env: + cache-name: cache-crystal-shards + with: + path: ./lib + key: lib-${{ hashFiles('**/shard.lock') }} + restore-keys: | + lib- - name: Setup CNF-Conformance run: | - helm repo add stable https://charts.helm.sh/stable - git fetch --all --tags + helm repo add stable https://cncf.gitlab.io/stable + git fetch --all --tags --force shards install - crystal src/cnf-conformance.cr setup - name: Run Crystal Spec env: GITHUB_USER: ${{ secrets.GH_USER }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + PROTECTED_DOCKERHUB_EMAIL: ${{ secrets.PROTECTED_DOCKERHUB_EMAIL }} + PROTECTED_DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + PROTECTED_DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + run: | + LOG_LEVEL=info crystal spec --warnings none --tag ${{ matrix.spec }} -v + + build: + name: Build Release + # needs: [skip, debug_output] + runs-on: ubuntu-latest + # if: needs.skip.outputs.skip == 'false' + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + # - uses: mxschmitt/action-tmate@v3 + # if: needs.debug_output.outputs.build-debug == 'true' + - name: Cache crystal shards + uses: actions/cache@v2 + env: + cache-name: cache-crystal-shards + with: + path: ./lib + key: lib-${{ hashFiles('**/shard.lock') }} + restore-keys: | + lib- + - name: Build Release + run: | + docker pull conformance/crystal:0.35.1 + docker run --rm -v $PWD:/workspace -w /workspace conformance/crystal:0.35.1-llvm10-grep shards install + docker run --rm -v $PWD:/workspace -w /workspace conformance/crystal:0.35.1-llvm10-grep crystal build --warnings none src/cnf-conformance.cr --release --static --link-flags '-lxml2 -llzma' + - name: upload artifact + uses: actions/upload-artifact@v2 + with: + name: release + path: cnf-conformance + + test_binary_configuration_lifecycle: + name: Test Binary Without Source(config_lifecycle) + needs: [build, debug_output] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: release + - uses: mxschmitt/action-tmate@v3 + if: needs.debug_output.outputs.release-debug == 'true' + - name: Create Kind Cluster + run: | + cat << EOF > /tmp/cluster.yml + kind: Cluster + apiVersion: kind.x-k8s.io/v1alpha4 + containerdConfigPatches: + - |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry:5000"] + endpoint = ["http://localhost:5000"] + EOF + kind create cluster --config=/tmp/cluster.yml + kubectl get nodes + - name: Run Test Suite without source(config_lifecycle) run: | - LOG_LEVEL=info crystal spec --warnings none ${{ matrix.spec }} -v + helm repo add stable https://cncf.gitlab.io/stable + chmod +x ./cnf-conformance + ./cnf-conformance setup + wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml + ./cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml + LOG_LEVEL=info ./cnf-conformance all ~reasonable_startup_time ~reasonable_image_size ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~volume_hostpath_not_found ~privileged ~increase_capacity ~decrease_capacity ~install_script_helm ~helm_chart_valid ~helm_chart_published verbose + + test_binary_microservice: + name: Test Binary Without Source(microservice) + needs: [build, debug_output] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: release + - uses: mxschmitt/action-tmate@v3 + if: needs.debug_output.outputs.release-debug == 'true' + - name: Create Kind Cluster + run: | + cat << EOF > /tmp/cluster.yml + kind: Cluster + apiVersion: kind.x-k8s.io/v1alpha4 + containerdConfigPatches: + - |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry:5000"] + endpoint = ["http://localhost:5000"] + EOF + kind create cluster --config=/tmp/cluster.yml + kubectl get nodes + - name: Run Test Suite without source(microservice) + run: | + helm repo add stable https://cncf.gitlab.io/stable + chmod +x ./cnf-conformance + ./cnf-conformance setup + wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml + ./cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml + LOG_LEVEL=info ./cnf-conformance all ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~volume_hostpath_not_found ~privileged ~increase_capacity ~decrease_capacity ~ip_addresses ~liveness ~readiness ~rolling_update ~rolling_downgrade ~rolling_version_change ~nodeport_not_used ~hardcoded_ip_addresses_in_k8s_runtime_configuration ~install_script_helm ~helm_chart_valid ~helm_chart_published ~rollback ~secrets_used ~immutable_configmap verbose + + test_binary_all: + name: Test Binary Without Source(all) + needs: [build, debug_output] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: release + - uses: mxschmitt/action-tmate@v3 + if: needs.debug_output.outputs.release-debug == 'true' + - name: Create Kind Cluster + run: | + cat << EOF > /tmp/cluster.yml + kind: Cluster + apiVersion: kind.x-k8s.io/v1alpha4 + containerdConfigPatches: + - |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry:5000"] + endpoint = ["http://localhost:5000"] + EOF + kind create cluster --config=/tmp/cluster.yml + kubectl get nodes + - name: Run Test Suite without source(all) + run: | + helm repo add stable https://cncf.gitlab.io/stable + chmod +x ./cnf-conformance + ./cnf-conformance setup + wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml + ./cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml + LOG_LEVEL=info ./cnf-conformance all ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~ip_addresses ~liveness ~readiness ~rolling_update ~rolling_downgrade ~rolling_version_change ~nodeport_not_used ~hardcoded_ip_addresses_in_k8s_runtime_configuration ~rollback ~secrets_used ~immutable_configmap ~reasonable_startup_time ~reasonable_image_size verbose + release: - name: Release - needs: spec + name: Publish Release + needs: [spec, build, debug_output] runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Create Release + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: release + - uses: mxschmitt/action-tmate@v3 + if: needs.debug_output.outputs.release-debug == 'true' + - name: Make release executable + run: chmod +x ./cnf-conformance + - name: Publish Release env: GITHUB_USER: ${{ secrets.GH_USER }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} run: | - source .github/workflows/retry.sh - docker pull crystallang/crystal:0.35.1-alpine - retry "docker run --rm -v $PWD:/workspace -w /workspace crystallang/crystal:0.35.1-alpine shards install" - retry "docker run --rm -v $PWD:/workspace -w /workspace crystallang/crystal:0.35.1-alpine crystal build --warnings none src/cnf-conformance.cr --release --static --link-flags '-lxml2 -llzma'" if [ -z "${GITHUB_USER+x}" ] || [ -z "${GITHUB_TOKEN+x}" ]; then exit 0 else diff --git a/.github/workflows/skip.sh b/.github/workflows/skip.sh new file mode 100755 index 000000000..ef3ed042d --- /dev/null +++ b/.github/workflows/skip.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if git status | grep -q -P -i 'v[0-9]\.[0-9]'; then + echo 'false' +elif git branch | grep -q '^*.*master.*$'; then + if ! git diff --name-only HEAD HEAD~1 | grep -q -P '^((?!.md).)*$'; then + echo 'true' + else + echo 'false' + fi +else + if ! git diff --name-only HEAD origin/master | grep -q -P '^((?!.md).)*$'; then + echo 'true' + else + echo 'false' + fi +fi diff --git a/.github/workflows/test.sh b/.github/workflows/test.sh new file mode 100755 index 000000000..c478dc8c7 --- /dev/null +++ b/.github/workflows/test.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if git diff --name-only HEAD master | grep -P '^((?!.md).)*$'; then + echo 'Run Specs' +else + echo 'Skip Specs' +fi diff --git a/.gitignore b/.gitignore index 3877a0428..cf0475766 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /tools/chaos_mesh /tools/helm /tools/sonobuoy +/tools/cluster-api admin.conf cnf-conformance results.yml @@ -17,3 +18,21 @@ cnf-conformance-results* cnf-conformance.env *.tar *.tar* +reasonable_startup_orig.yml +reasonable_startup_test.yml +cri_tools.yml +ephemeral_env +kubeconfig.conf +linux-amd64/ +reasonable_startup_orig_gobal.yml +reasonable_startup_orig_local.yml +sam.cr +test.file +tools/k8s-infra/ +tmp/ +chaos_network_loss.yml +chaos_cpu_hog.yml +chaos_container_kill.yml +/.idea/ +*.sh +*.log \ No newline at end of file diff --git a/CNF_CONFORMANCE_YML_USAGE.md b/CNF_CONFORMANCE_YML_USAGE.md index 87a9e50ac..392463207 100644 --- a/CNF_CONFORMANCE_YML_USAGE.md +++ b/CNF_CONFORMANCE_YML_USAGE.md @@ -1,70 +1,309 @@ -# Usage document for the cnf-conformance.yml - +# Test Suite Configuration Usage: cnf-conformance.yml ### What is the cnf-conformance.yml and why is it required?: -The cnf-conformance.yml is used by the CNF-Conformance suite to locate a deployed CNF on an existing K8s cluster or get enough information about the CNF and it's helm chart that will allow the test suite to deploy the CNF itself. - -This information is also required for running various tests e.g. The 'deployment_name' is used for finding the name of the CNF deployment in the K8s cluster and is then used to run tests like [increase_capacity](https://github.com/cncf/cnf-conformance/blob/master/src/tasks/scalability.cr#L20) and [decrease_capacity](https://github.com/cncf/cnf-conformance/blob/master/src/tasks/scalability.cr#L42) +The cnf-conformance.yml is used by the CNF-Conformance suite to locate a deployed CNF on an existing K8s cluster. If the CNF is not found, it will attempt to deploy the CNF itself according to it's helm chart configuration. +This information is also required for running various tests e.g. The 'container_names' are used for finding the name of the CNF containers in the K8s cluster and is then used to run tests like [increase_capacity](https://github.com/cncf/cnf-conformance/blob/main/src/tasks/scalability.cr#L20) and [decrease_capacity](https://github.com/cncf/cnf-conformance/blob/main/src/tasks/scalability.cr#L42) +### Table of Contents +- [Overview](#Overview-of-all-cnf-conformance.yml) +- [Keys and Values](#Keys-and-Values) + - [helm_directory](#helm_directory) + - [git_clone_url](#git_clone_url) + - [install_script](#install_script) + - [release_name](#release_name) + - [deployment_name](#deployment_name) + - [deployment_label](#deployment_label) + - [application_deployment_name](#application_deployment_name) + - [docker_repository](#docker_repository) + - [helm_repository](#helm_repository) + - [helm_chart](#helm_chart) + - [helm_chart_container_name](#helm_chart_container_name) + - [allowlist_helm_chart_container_names](#allowlist_helm_chart_container_names) + - [container_names](#container_names) +- [Creating Your Own cnf-conformance.yml](#creating-your-own-cnf-conformanceyml) +- [Setup and Configuration](#Setup-and-Configuration) +- [Quick Setup and Config Reference Steps](#Quick-Setup-and-Config-Reference-Steps) +- [Using a Private Registry](#Using-a-Private-Registry) -### All cnf-conformance.yml keys/values -###### [cnf-conformance.example.yml](https://github.com/cncf/cnf-conformance/blob/develop/cnf-conformance.example.yml) +### Overview of all cnf-conformance.yml +The following is a basic example cnf-conformance.yml file that can be found in the cnf-conformance respository: [cnf-conformance.example.yml](https://github.com/cncf/cnf-conformance/blob/develop/cnf-conformance.example.yml) ```yaml= --- #helm_directory: coredns # PATH_TO_CNFS_HELM_CHART ; or -helm_chart_repo: stable/coredns # PUBLISHED_CNFS_HELM_CHART_REPO/NAME +helm_chart: stable/coredns # PUBLISHED_CNFS_HELM_CHART_REPO/NAME git_clone_url: https://github.com/coredns/coredns.git # GIT_REPO_FOR_CNFS_SOURCE_CODE install_script: cnfs/coredns/Makefile # PATH_TO_CNFS_INSTALL_SCRIPT release_name: privileged-coredns # DESIRED_HELM_RELEASE_NAME -deployment_name: privileged-coredns-coredns # CNFS_KUBERNETES_DEPLOYMENT_NAME -application_deployment_names: N/A helm_chart_container_name: privileged-coredns-coredns # POD_SPEC_CONTAINER_NAME -white_list_helm_chart_container_names: [coredns] # [LIST_OF_CONTAINERS_ALLOWED_TO_RUN_PRIVLIDGED] +allowlist_helm_chart_container_names: [coredns] # [LIST_OF_CONTAINERS_ALLOWED_TO_RUN_PRIVLIDGED] +container_names: #[LIST_OF_CONTAINERS_NAMES_AND_VERSION_UPGRADE_TAGS] + - name: sidecar-container1 + rolling_update_test_tag: "1.32.0" + - name: sidecar-container2 + rolling_update_test_tag: "1.32.0" ``` +### Keys and Values + +#### helm_directory +This is the path to the helm chart directory (relative to the location of the cnf-conformance.yml). This or [helm_chart](#helm_chart) must be set, but only one **(mutually exclusive)**. -#### helm_directory: path to the helm chart directory (relative to the location of the cnf-conformance.yml) -MUST BE SET: (Mutually exclusive with helm_chart). Used for doing static tests on the helm chart code e.g. searching for Hardcoded IPs. An example of a helm chart source directory can be found [here](https://github.com/helm/charts/tree/master/stable/coredns). -The Path is also relative to the location of the cnf-conformance.yml. So if the cnf-conformance.yml in the directory ```charts/stable/cnf-conformance.yml``` and helm_directory is set to ```helm_directory: coredns``` the test suite would expect to find the chart under [```charts/stable/coredns```](https://github.com/helm/charts/tree/master/stable/coredns) +The PATH is also relative to the location of the cnf-conformance.yml. So if the cnf-conformance.yml in the directory ```cnfs/coredns/cnf-conformance.yml``` and helm_directory is set to ```helm_directory: coredns``` the test suite would expect to find the chart under [```cnfs/coredns/coredns```](https://github.com/helm/charts/tree/master/stable/coredns) -#### helm_chart: Published helm chart repo and chart name. -MUST BE SET: (Mutually exclusive with helm_directory). -Used for doing static tests on the helm chart code e.g. searching for Hardcoded IPs. +Example Setting: -An example of a publishe helm chart repo/image can be found [here](https://github.com/helm/charts/tree/master/stable/coredns#tldr). +`helm_directory: coredns` + +#### git_clone_url +This setting is for the source code of the CNF being tested. (Optional) + +The value of git_clone_url is used to clone the source code for the CNF being tested and is then seached through for things like total lines of code, hardcoded ips, etc. + +Example setting: + +`git_clone_url: https://github.com/coredns/coredns.git` + +*Note: The install of the CNF from a helm chart will always test the helm chart source even if the complete CNF source is not provided.* + + +#### install_script +This is the location of additional scripts used to install the CNF being tested. (Optional) + +Path to a script used for installing the CNF (relative to the location of the cnf-conformance.yml). This is used by the CNF-Conformance suite to install the CNF if a wrapper around helm is used or helm isn't used at all. If left blank, the CNF will be installed using the helm_chart value. + +Example setting: + +`install_script: cnfs/coredns/Makefile` + +#### release_name +This is the helm release name of the CNF. + +If the CNF isn't pre-deployed to the cluster then the test suite will perform the installation and use this name for the helm release / version. + +This MAY be set. If release_name is not set, a release name will be generated. + +Example setting (with no parameters): + +`release_name: privileged-coredns` + +This is used by the CNF-Conformance suite to interact with the Helm release / installation of the CNF being tested and find meta-data about the CNF. + +For example, the [rolling_update](https://github.com/cncf/cnf-conformance/blob/96cee8cefc9a71e62e971f8f4abad56e5db59866/src/tasks/configuration_lifecycle.cr#L156) test uses the helm release_name to fetch the docker image name and tag of the CNF so it can preform a rolling update. [See: rolling_update test](https://github.com/cncf/cnf-conformance/blob/96cee8cefc9a71e62e971f8f4abad56e5db59866/src/tasks/configuration_lifecycle.cr#L179) -#### git_clone_url: Git-repo for the source code of the CNF being tested. (Optional) -The value of git_clone_url is used to clone the source code for the CNF being tested and is then seached through for things like total lines of code, hardcoded ips, etc. Note: The install of the CNF from a helm chart will always test the helm chart source even if the complete CNF source is not provided. +For a protected docker registry you must use helm parameters in conjunction with the release name: +``` +release_name: coredns --set imageCredentials.registry=https://index.docker.io/v1/ --set imageCredentials.username=$PROTECTED_DOCKERHUB_USERNAME --set imageCredentials.password=$PROTECTED_DOCKERHUB_PASSWORD --set imageCredentials.email=$PROTECTED_DOCKERHUB_EMAIL +``` +In the above example, $PROTECTED_DOCKERHUB_USERNAME and $PROTECTED_DOCKERHUB_PASSWORD are environment variables that were previously exported. The values can then be used as secrets in the helm chart. + +#### deployment_name + +Example setting: + +`deployment_name: coredns-coredns` + +#### deployment_label + +Example setting: + +`deployment_label: k8s-app` + +#### application_deployment_name + +Example setting: + +`application_deployment_names: [coredns-coredns]` +#### docker_repository -#### install_script: Location of additional scripts used to install the CNF being tested. (Optional) +Example setting: + +`docker_repository: coredns/coredns` + +#### helm_repository +This is the URL of your helm repository for your CNF. + +Example setting: + +```yaml= +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +``` + +#### helm_chart +The published helm chart name. Like [helm_directory](#helm_directory), this or [helm_directory](#helm_directory) must be set, but not both **(mutually exclusive)**. + +Exmple setting: + +`helm_chart: stable/coredns` + +An example of a publishe helm chart repo/image can be found [here](https://github.com/helm/charts/tree/master/stable/coredns#tldr). -Path to script used for installing the CNF (relative to the location of the cnf-conformance.yml). This is used by the CNF-Conformance suite to install the CNF if a wrapper around helm is used or helm isn't used at all. If this is blank, the CNF will be installed using the helm_chart value. +#### helm_chart_container_name -#### release_name: The helm release name of the CNF; if the CNF isn't pre-deployed to the cluster then the test suite will perform the installation and use this name for the helm release / version. -This MUST be set. -This is used by the CNF-Conformance suite to interact with the Helm release / installation of the CNF being tested and find meta-data about the CNF. For example the [rolling_update](https://github.com/cncf/cnf-conformance/blob/96cee8cefc9a71e62e971f8f4abad56e5db59866/src/tasks/configuration_lifecycle.cr#L156) test uses the helm release_name to fetch the docker image name and tag of the CNF so it can preform a rolling update. [See: rolling_update test](https://github.com/cncf/cnf-conformance/blob/96cee8cefc9a71e62e971f8f4abad56e5db59866/src/tasks/configuration_lifecycle.cr#L179) +This value is the name of the 'container' defined in the Kubernetes pod spec of the CNF being tested. -#### deployment_name: The Kubernetes deployment name of the CNF after it has been installed to the K8s cluster. -This MUST be set. +This value is used to look up the CNF and determine if it's running in privileged mode (only used within the specs). The containers in the test are now dynamically determined from the helm chart or manifest files (See: ['privileged' test](https://github.com/cncf/cnf-conformance/blob/c8a2d8f06c5e5976acd1a641350978929a2eee12/src/tasks/security.cr#L32)). -#### application_deployment_names: This value isn't currently used by any tests. -This MAY be set. +Example setting: +`helm_chart_container_name: privileged-coredns-coredns` -#### helm_chart_container_name: This value is the name of the 'container' defined in the Kubernetes pod spec of the CNF being tested. (See: [for example](https://github.com/helm/charts/blob/master/stable/coredns/templates/deployment.yaml#L72)) -This MUST be set. -This value is used to look up the CNF and determine if it's running in privileged mode (See: ['privileged' test](https://github.com/cncf/cnf-conformance/blob/c8a2d8f06c5e5976acd1a641350978929a2eee12/src/tasks/security.cr#L32)). +#### allowlist_helm_chart_container_names + +The values of this key are the names of the 'containers' defined in the Kubernetes pod spec of pods that are allowed to be running in privileged mode. (Optional) -#### white_list_helm_chart_container_names: This value is the name of the 'container' defined in the Kubernetes pod spec of pods that are allowed to be running in privileged mode. (Optional) This value is used to allow 'particular' pods to run in privileged mode on the K8s cluster where is CNF being tested is installed. The reason this is needed is because the Test Suite will check, 'all' pods in the cluster, to see if they're running in privileged mode. This is done because it's a common cloud-native practice to delegate 'privileged' networking tasks to only a single app e.g Multus, NSM vs making the CNF privileged itself. As a consequence the whitelist can only be used to exempt 'privileged' infrastructure services running as pods e.g NSM, Multus and cannot be used to exempt the CNF being tested. + +Example setting: + +`allowlist_helm_chart_container_names: [coredns]` + +#### container_names + +This value is the name of the 'containers' defined in the Kubernetes pod spec of pods and must be set. + +Example setting: + +```yaml= +container_names: #[LIST_OF_CONTAINERS_NAMES_AND_VERSION_UPGRADE_TAGS] + - name: + rolling_update_test_tag: + - name: + rolling_update_test_tag: +``` + +This value is used to test the upgradeability of each container image. The image tag version should be a minor version that will be used in conjunction with the kubnetes rollout feature. + +### Creating Your Own cnf-conformance.yml + +- Create a Conformance configuration file called `cnf-conformance.yml` under the your CNF folder (eg. `cnfs/my_ipsec_cnf/cnf-conformance.yml`) + - See example config (See [latest example in repo](https://github.com/cncf/cnf-conformance/blob/main/cnf-conformance.example.yml)): + - Optionally, copy the example configuration file, [`cnf-conformance-example.yml`](https://github.com/cncf/cnf-conformance/blob/main/cnf-conformance.example.yml), and modify appropriately +- (Optional) Setup your CNF for testing and deploy it to the cluster by running `cnf-conformance cnf_setup cnf-config=path_to_your/cnf_folder` + - _NOTE: if you do not want to automatically deploy the using the helm chart defined in the configuration then you MUST pass `deploy_with_chart=false` to the `cnf_setup` command._ + - _NOTE: you can pass the path to your cnf-conformance.yml to the 'all' command which will install the CNF for you (see below)_ + + +A configuration file called `cnf-conformance.yml` needs to be created for each CNF you want to test (eg. `cnfs/my_ipsec_cnf/cnf-conformance.yml`). + +You can start by copying an example cnf-conformance.yml or copy and paste the below to get started and then filling our the appropriate values: + +The [`cnf-conformance.yml`](https://github.com/cncf/cnf-conformance/blob/main/cnf-conformance.example.yml) file can be used (included in source code or below): + ```yaml= +--- +helm_directory: +install_script: +helm_chart: +helm_chart_container_name: +allowlist_helm_chart_container_names: +container_names: + - name: + rolling_update_test_tag: + - name: + rolling_update_test_tag: + ``` + +Below is a fully working example CoreDNS cnf-conformance.yml that tests CoreDNS by installing via helm from a helm repository as a reference: + +```yaml= +--- +helm_directory: +# helm_directory: helm_chart +git_clone_url: +install_script: +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +application_deployment_names: [coredns-coredns] +docker_repository: coredns/coredns +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +helm_chart: stable/coredns +helm_chart_container_name: coredns +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy, kube-multus] + +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +``` + +### Setup and Configuration +Now that you have your own CNF with a cnf-conformance.yml, you should be now be able to setup and run the suite against it. + +#### Quick Setup and Config Reference Steps +This assumes you have already followed [INSTALL](INSTALL.md) and or [SOURCE-INSTALL](SOURCE-INSTALL.md) guides. + + * Run the cleanup tasks to remove prerequisites (useful for starting fresh if you've already run the suite previously) + ``` + ./cnf-conformance cleanup + ``` + + * Run the setup tasks to install any prerequisites (useful for setting up sample cnfs and doesn't hurt to run multiple times) + + ``` + ./cnf-conformance setup + ``` + + * Setup and configure your CNF by installing your CNF into the cnfs directory, download the helm charts, and download the source code: + ``` + ./cnf-conformance cnf_setup cnf-config= + ``` + + * To remove your CNF from the cnfs directory and cluster + ``` + ./cnf-conformance cnf_cleanup cnf-config= + ``` + +### Using a Private Registry +To setup and use a private registry if you are not pulling images from a public repository like Docker Hub, this is the current method to specify a private registry with username and password to pull down images used for the test suite. + +You can pass this information directly in the `cnf-conformance.yml` under the `release_name` setting: + +Example usage: + +``` +release_name: release --set imageCredentials.registry=$PROTECTED_REGISTRY_URL --set imageCredentials.username=$PROTECTED_REGISTRY_USERNAME --set imageCredentials.password=$PROTECTED_REGISTRY_PASSWORD --set imageCredentials.email=$PROTECTED_REGISTRY_EMAIL +``` + +In this example, we are using ENV variables to avoid using usernames and passwords in the actual config files which we highly recommend. + +To set the ENV variables, do the following: + +``` +export PROTECTED_REGISTRY_URL="example.io" +export PROTECTED_REGISTRY_USERNAME=username +export PROTECTED_REGISTRY_PASSWORD=password +export PROTECTED_REGISTRY_EMAIL="email@example.io" +``` + +In some cases, the email is not necessary. You can leave it blank if not required, eg. `export PROTECTED_REGISTRY_EMAIL=""` + +These values are specified in your specific Helm Chart values.yml, e.g.: + +``` +# Default values for your image +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +imageCredentials: + registry: example.io + username: username + password: password + email: email@example.io +``` diff --git a/CODE-STRUCTURE.md b/CODE-STRUCTURE.md index f1651701c..db05a602f 100644 --- a/CODE-STRUCTURE.md +++ b/CODE-STRUCTURE.md @@ -1,9 +1,9 @@ # CNF Conformance Code Structure and Usage -1. TODO: Separate dynamic tests from static tests +1. :heavy_check_mark: Separate dynamic tests from static tests 1. :heavy_check_mark: Separate tests into test categories (category files) 1. :heavy_check_mark: Make static task dependent on all static tests 1. :heavy_check_mark: Make dynamic task dependent on all dynamic tests -1. TODO: Separate the installation/deployment/configuration tasks from the test tasks +1. :heavy_check_mark: Separate the installation/deployment/configuration tasks from the test tasks 1. cloning k8s-infra 1. cloning cnf-testbed 1. TODO: Create instructions for calling CNF Conformance suite on an arbitrary CNF codebase diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7c1d167d..719369303 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Contributing Guidelines --- Welcome! We gladly accept contributions on new conformance tests, example CNFs, updates to documentation, enhancements, bug reports and more. -CNF Conformance is [Apache 2.0 licensed](https://github.com/cncf/cnf-conformance/blob/master/LICENSE) and accepts contributions via GitHub pull requests. Please read the following guidelines carefully to make it easier to get your contribution accepted. +CNF Conformance is [Apache 2.0 licensed](https://github.com/cncf/cnf-conformance/blob/main/LICENSE) and accepts contributions via GitHub pull requests. Please read the following guidelines carefully to make it easier to get your contribution accepted. Support Channels: --- @@ -32,7 +32,7 @@ To request an enhancement, please create a new issue using the [**Feature Reques **2. Report Bugs:** To report a bug, please create a new issue using the [**Bug Report**](https://github.com/cncf/cnf-conformance/issues/new?assignees=&labels=bug&template=bug-report.md&title=%5BBUG%5D) Template. Check out [How to Report Bugs Effectively](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html.). -NOTE: you can enable higher logging level output via the command line or env var. to help with debugging +NOTE: To help with debugging, you can enable higher logging level output via the command line or env var ``` # cmd line @@ -51,7 +51,7 @@ Also setting the verbose option for many tasks will add extra output to help wit crystal src/cnf-conformance.cr test_name verbose ``` -Check [usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md) for more info about invoking commands and loggin +Check [usage documentation](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md) for more info about invoking commands and loggin **3. New Conformance Tests:** - To request a new workload test, please create a new issue using the [**New Workload Test**](https://github.com/cncf/cnf-conformance/issues/new?assignees=&labels=workload&template=new-workload-test.md&title=%5BWorkload%5D) Template @@ -61,7 +61,7 @@ Check [usage documentation](https://github.com/cncf/cnf-conformance/blob/master/ To suggest a new CNF, please create a GitHub issue using the [New Example CNF template](https://github.com/cncf/cnf-conformance/issues/new?assignees=&labels=example+CNF&template=new-example-cnf.md&title=%5BCNF%5D). To install the CNF Conformance test suite and run a CNF, follow instructions at: -- [CNF Developer Install and Usage Guide](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#cnf-developer-install-and-usage-guide) +- [CNF Developer Install and Usage Guide](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#cnf-developer-install-and-usage-guide) Coding Style: --- @@ -74,13 +74,13 @@ Contribution Flow Outline of what a contributor's workflow looks like: 1. Fork it (https://github.com/cncf/cnf-conformance/fork) -1. Create a branch from where you want to base your work (usually master). Example `git checkout -b my-new-feature)` +1. Create a branch from where you want to base your work (usually main). Example `git checkout -b my-new-feature)` 1. Read the [INSTALL.md](install for build and test instructions) 1. Make your changes and arrange them in readable commits. 1. Commit your changes (Ex. `git commit -am 'Add some feature'``) - Make sure your commit messages are in the proper format (see below). 1. Push to the branch (Ex. `git push origin my-new-feature`) -1. Make sure branch is up to date with upstream base branch (eg. `master`) +1. Make sure branch is up to date with upstream base branch (eg. `main`) 1. Make sure all tests pass, and add any new tests as appropriate. 1. Create a new Pull Request (PR) @@ -91,14 +91,35 @@ Once you have implemented the feature or bug fix in your branch, you will open a In order to open a pull request (PR) it is required to be up to date with the latest changes upstream. If other commits are pushed upstream before your PR is merged, you will also need to rebase again before it will be merged. -Using the automated [pull request template](https://github.com/cncf/cnf-conformance/blob/master/.github/PULL_REQUEST_TEMPLATE.md), please note a description of the changes, the type of change, the issue(s) related to the PR, how the changes have been tested and if updates are needed in the documentation. +Using the automated [pull request template](https://github.com/cncf/cnf-conformance/blob/main/.github/PULL_REQUEST_TEMPLATE.md), please note a description of the changes, the type of change, the issue(s) related to the PR, how the changes have been tested and if updates are needed in the documentation. For general advice on how to submit a pull request, please see [Creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request). +Accepting a PR: +--- +**Problem:** Pull requests from forks do not have the permissions to run through the github actions CI, so they will fail + +**Solution:** Pull down the source from the fork and branch, then push up the source to the original cnf-conformance repo. + +1. Make a directory based on the forked user's name in the the pull request. +`mkdir ` +`cd ` +2. Clone the fork. +`git clone git@github.com:/cnf-conformance.git` +`cd cnf-conformance` +3. Add the original cnf-conformance repo. +`git remote add cncf git@github.com:cncf/cnf-conformance.git` +4. Checkout the pull request's branch. +`git checkout ` +5. Push the branch to the original cnf-conformance repo. +`git push ` +6. Observe results of the github actions. +7. (optional) Accept the original pull request if the review and tests pass. +8. (optional -- changes required) Create a new PR, make changes, and merge into main (Github will automatically merge the original PR since it's changes will be included in the new PR) Community Meeting: --- -The CNF Conformance team meets once a week on Thursdays at 14:15-15:00 UTC. +The CNF Conformance team meets once a week on Thursdays at 15:15-16:00 UTC. - Meeting minutes are [here](https://docs.google.com/document/d/1IbrgjqIkOCvrrSG0DRE6X62UUZpBq-818Mn8q0nkkd0/edit#) diff --git a/EXAMPLE-CNFS.md b/EXAMPLE-CNFS.md index 8b8f5948b..09f51f496 100644 --- a/EXAMPLE-CNFS.md +++ b/EXAMPLE-CNFS.md @@ -1,6 +1,8 @@ -### EXAMPLE-CNFs (DRAFT) +### EXAMPLE-CNFs -This is a preliminary list of CNF samples for each layer in the [OSI model](https://www.osi-model.com/presentation-layer/) which we plan to test in the CNF Conformance Test Suite +This is a preliminary list of CNF samples for each layer in the [OSI model](https://www.osi-model.com/presentation-layer/) which we plan to test in the CNF Conformance Test Suite. CNFs can be thought of as functionality occupying one or more of the following network layers: + + **Goals:** @@ -11,7 +13,7 @@ This is a preliminary list of CNF samples for each layer in the [OSI model](http ## [Layer 7 - Application](https://en.wikipedia.org/wiki/Application_layer) -- [CoreDNS Sample CNF](https://github.com/cncf/cnf-conformance/tree/master/sample-cnfs/sample-coredns-cnf) +- [CoreDNS Sample CNF](https://github.com/cncf/cnf-conformance/tree/main/sample-cnfs/sample-coredns-cnf) - [NFF Go Deep Packet Inspection example](https://github.com/intel-go/nff-go/tree/master/examples/dpi) example @@ -35,6 +37,7 @@ This is a preliminary list of CNF samples for each layer in the [OSI model](http ## [Layer 3 - Network](https://en.wikipedia.org/wiki/Network_layer) +- [Pantheon Network Service Mesh NAT](https://github.com/cncf/cnf-conformance/blob/main/example-cnfs/pantheon-nsm-nat/README.md) - [NFF Go IP Forwarding example](https://github.com/intel-go/nff-go/tree/master/examples/forwarding) - [NFF Go IPsec example](https://github.com/intel-go/nff-go/tree/master/examples/ipsec) - [CNF Testbed IPsec example](https://github.com/cncf/cnf-testbed/tree/master/examples/use_case/ipsec) @@ -45,6 +48,7 @@ This is a preliminary list of CNF samples for each layer in the [OSI model](http - [Tungsten Fabric](https://tungsten.io/) - [OpenSwitch NAS Layer 3](https://github.com/open-switch/opx-nas-l3) - CNI K8s add-ons operating on Layer 3 such as the Calico kube-policy-controller container +- [A dockerized version of free5gc](https://github.com/free5gc/free5gc-compose/) ## [Layer 2 - Data](https://en.wikipedia.org/wiki/Data_link_layer) diff --git a/FAQ.md b/FAQ.md index 892c0958a..906230901 100644 --- a/FAQ.md +++ b/FAQ.md @@ -13,7 +13,7 @@ CNF Conformance Test Suite Frequently Asked Questions
Can I contribute to the CNF Conformance Project?

- - Yes. You can start by reading the [CNF Conformance Contributing Guidelines](https://github.com/cncf/cnf-conformance/blob/master/CONTRIBUTING.md). + - Yes. You can start by reading the [CNF Conformance Contributing Guidelines](https://github.com/cncf/cnf-conformance/blob/main/CONTRIBUTING.md).

@@ -21,7 +21,7 @@ CNF Conformance Test Suite Frequently Asked Questions
Does the CNF Conformance community meet?

- - Yes. The CNF Conformance team meets once a week on Thursdays at 14:15-15:00 UTC. You can find more info about the meeting [here.](https://github.com/cncf/cnf-conformance/blob/master/CONTRIBUTING.md#community-meeting) + - Yes. The CNF Conformance team meets once a week on Thursdays at 14:15-15:00 UTC. You can find more info about the meeting [here.](https://github.com/cncf/cnf-conformance/blob/main/CONTRIBUTING.md#community-meeting)

@@ -78,7 +78,7 @@ CNF Conformance Test Suite Frequently Asked Questions
Does CNF Conformance have any pre-requisites or other requirements to run?

- - Yes. There are a few requirements for CNF Conformance. You can read about the requirements in the [INSTALL Guide](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#prerequisites). + - Yes. There are a few requirements for CNF Conformance. You can read about the requirements in the [INSTALL Guide](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites).

@@ -86,7 +86,7 @@ CNF Conformance Test Suite Frequently Asked Questions
How are points assigned for tests?

- - Points are different for each test and workload but in general terms, pass defaults to 5 and fail is a -1. See [points.yml](https://github.com/cncf/cnf-conformance/blob/master/points.yml) for more details on the different points for default scoring. + - Points are different for each test and workload but in general terms, pass defaults to 5 and fail is a -1. See [points.yml](https://github.com/cncf/cnf-conformance/blob/main/points.yml) for more details on the different points for default scoring.

@@ -119,6 +119,12 @@ CNF Conformance Test Suite Frequently Asked Questions

- The short answer is Crystal fit the criteria we looked at in a language at the time which needed to run external programs/test suites and internal tests - [Taylor Carpenter](https://app.slack.com/client/T08PSQ7BQ/G019HM3K54H/user_profile/U7HCKCW90) via https://slack.cncf.io/ + - Usability for Humans - Crystal, puts readablility for humans as a priority, which is why its syntax heavily inspired by Ruby. + - Type checking system to help humans catch their errors earlier + - Compiled language for portability, reduced size, and performance + - Metaprogramming through Crystal's powerful macro system + - Concurrency throughy green threads, called fiberes, which communicate over channels like Go lang and Clojure + - Dependency management for libraries and applications via the [crystal manager Shards](https://github.com/crystal-lang/shards)

@@ -128,7 +134,7 @@ CNF Conformance Test Suite Frequently Asked Questions
Running cnf-conformance says "No found config" or similiar type errors?

- - This may indicate that you are not pointing to a valid cnf-conformance.yml config file for your CNF. You may want to read or review the [CNF Conformance INSTALL](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md) instructions or the [USAGE Documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md). + - This may indicate that you are not pointing to a valid cnf-conformance.yml config file for your CNF. You may want to read or review the [CNF Conformance INSTALL](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md) instructions or the [USAGE Documentation](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md).

diff --git a/INSTALL.md b/INSTALL.md index 97530e554..faa47abcf 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,144 +1,165 @@ Installing the CNF Conformance Test Suite --- -aka CNF Developer Installation Guide +### Overview +This INSTALL guide will detail the minimum requirements needed for cnf-conformance while then providing installation with configuration steps to run the cnf-conformance binary from both a binary installation and source installation method. -# Pre-Requisites +### Table of Contents +* [**Pre-Requisites**](#Pre-Requisites) +* [**Installation**](#Installation) +* [**Preparation**](#Preparation) +* [**Configuration**](#Configuration) +* [**Running cnf-conformance for the first time**](#Running-cnf-conformance-for-the-first-time) +### Pre-Requisites +This will detail the required minimum requirements needed in order to support cnf-conformance. +#### Minimum Requirements +* **kubernetes cluster** *(Working k8s cluster, see [supported k8s and installation details](#Details-on-supported-k8s-clusters-and-installation) on installation.* +* **kubectl** *(run commands against k8 clusters, see [installing kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) for more details.* +* **curl** +* **helm 3.1.1** *or newer* *(cnf-conformance installs if not found locally)* -## Access to a kubernetes Cluster +#### Requirements for source installation +*Everything detailed in the [minimum requirements](https://hackmd.io/6h7NXdHnR4qUYgnnQPy5UA#Required) and the following:* +* **git** *(used to check out code from github)* +* **crystal-lang** version 0.35.1 *(to compile the source and build the binary, see [crystal installation](https://crystal-lang.org/install/))* +* **shards** ([dependency manager](https://github.com/crystal-lang/shards) for crystal-lang) -- [Access](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/) to a working [Certified K8s](https://cncf.io/ck) cluster via [KUBECONFIG environment variable](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#set-the-kubeconfig-environment-variable). (See [K8s Getting started guide](https://kubernetes.io/docs/setup/) for options) -- follow the optional instructions below if you don't already have a k8s cluster setup -
(optional) how to create a k8s cluster if you don't already have one +--- + + +#### Details on supported k8s clusters and installation: +
Click here to drop down details +

-#### via kind +##### Supported k8s Clusters +- [Access](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/) to a working [Certified K8s](https://cncf.io/ck) cluster via [KUBECONFIG environment variable](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#set-the-kubeconfig-environment-variable). (See [K8s Getting started guide](https://kubernetes.io/docs/setup/) for options) +- Follow the optional instructions below if you don't already have a k8s cluster setup -follow the [kind install](KIND-INSTALL.md) instructions to setup a cluster in [kind](https://kind.sigs.k8s.io/) +##### Kind -#### or via k8s-infra +- Follow the [kind install](KIND-INSTALL.md) instructions to setup a cluster in [kind](https://kind.sigs.k8s.io/) -- clone the CNF-Testbed +##### CNF-Testbed + +- You can clone the CNF-Testbed project if you have an account at Equinix Metal (formerly Packet.net). Get the code by running the following: ``` -cd cnfs/ && git clone https://github.com/cncf/cnf-testbed.git +git clone https://github.com/cncf/cnf-testbed.git ``` -- Clone the K8s-infra repo then Follow the [prerequisites](https://github.com/cncf/cnf-testbed/tree/master/tools#pre-requisites) for [deploying a K8s cluster](https://github.com/cncf/cnf-testbed/tree/master/tools#deploying-a-kubernetes-cluster-using-the-makefile--ci-tools) for a Packet host. - - * If you already have IP addresses for your provider, and you want to manually install a K8s cluster, you can use k8s-infra to do this. +- Clone the K8s-infra repo then follow the [prerequisites](https://github.com/cncf/cnf-testbed/tree/master/tools#pre-requisites) for [deploying a K8s cluster](https://github.com/cncf/cnf-testbed/tree/master/tools#deploying-a-kubernetes-cluster-using-the-makefile--ci-tools) for a Equinix Metal host. +- If you already have IP addresses for your provider, and you want to manually install a K8s cluster, you can use k8s-infra to do this within your cnf-testbed repo clone. - ``` - cd tools/ && git clone https://github.com/crosscloudci/k8s-infra.git - ``` +``` +cd tools/ && git clone https://github.com/crosscloudci/k8s-infra.git +``` - * #### Follow the [K8s-infra quick start](https://github.com/crosscloudci/k8s-infra/blob/master/README.md#quick-start) for instructions on how to install +- Now follow the [K8s-infra quick start](https://github.com/crosscloudci/k8s-infra/blob/master/README.md#quick-start) for instructions on how to install.

-## Kubectl installed and configured -- [Kubectl binary is installed](https://kubernetes.io/docs/tasks/tools/install-kubectl/) -- `export KUBECONFIG=$HOME/mycluster.config` - - - Running `kubectl cluster-info` should show a running Kubernetes master in the output - -## Other Prereqs -- helm 3.1.1 (cnf-conformance will install helm if not found) -- wget -- curl -- git - -See https://github.com/cncf/cnf-conformance/blob/master/src/tasks/prereqs.cr for the most up to date list. The prerequisites are checked automatically when the test suite is used and any missing dependencies will be shown on the CLI. - -## CNF **must** have a [helm chart](https://helm.sh/) - -- To pass all current tests -- To support auto deployment of the CNF from the ([cnf-conformance.yml](https://github.com/cncf/cnf-conformance/blob/master/CNF_CONFORMANCE_YML_USAGE.md)) configuration file +--- +### Installation -## Other prereqs: +We support the following methods of installing the cnf-conformance suite: -- helm -- wget -- curl +- [Curl installation](#Curl-Binary-Installation) (via latest binary release) +- [Latest Binary](https://github.com/cncf/cnf-conformance/releases/latest) (manual download) +- From [**Source**](#Source-Install) on github. +#### Curl Binary Installation +There are two methods to install via curl, we prefer the first method (the others including the manual and source install are optional): -# Installation +- This first command using curl will download, install, and export the path automatically (recommended method): -We fully support 2 methods of installing the conformance suite: +``` +source <(curl https://raw.githubusercontent.com/cncf/cnf-conformance/main/curl_install.sh) +``` -- Via the latest [**binary** release](#binary-release-install-instructions) -- and also [from the **source**](#source-install) on github +
Click here for the alternate curl and manual install method +

-**Finally:** please make sure to run the `setup` command after finishing your preferred installation method please *or you are going to have a bad time*. +- The other curl method to download and install requires you to export the PATH to the location of the executable: +``` +curl https://raw.githubusercontent.com/cncf/cnf-conformance/main/curl_install.sh | bash +``` +- The Latest Binary (or you can select a previous release if desired) can be pulled down with wget, curl or you're own preferred method. Once downloaded you'll need to make the binary executable and manually add to your path: +``` +wget https://github.com/cncf/cnf-conformance/releases/download/latest/latest.tar.gz +tar xzf latest.tar.gz +cd cnf-conformance +chmod +x cnf-conformance +export OLDPATH=$PATH; export PATH=$PATH:$(pwd) +``` +

+
+#### Source Install -## Binary release install instructions +This is a brief summary for source installations and [does have requirements](#Requirements-for-source-installation) in order to compile a binary from source. To read more on source installation, see the [SOURCE-INSTALL](SOURCE_INSTALL.md) document. -
(optional) Manual Steps (if you **do not** wish to curl install): +
Click here for brief source install details +

-- Download the latest [binary release](https://github.com/cncf/cnf-conformance/releases) i.e via `wget` -- Make the binary executable (eg. `chmod +x cnf-conformance`) -- Move the downloaded binary to somewhere in your executable PATH (eg. `sudo cp cnf-conformance /usr/local/bin/cnf-conformance`) +Follow these steps to checkout the source from github and compile a cnf-conformance binary: +``` +git clone https://github.com/cncf/cnf-conformance.git +cd cnf-conformance/ +shards install +crystal build src/cnf-conformance.cr +``` +This should build a cnf-conformance binary in the root directory of the git repo clone. +

-### Curl install - -if that's your style. Unpack the CNF Conformance binary and add it to your PATH and you are good to go! +### Preparation -We support 2 ways. +Now that you have cnf-conformance installed, we need to prepare the suite. -- Use the curl command to download, install, and export the path simultaneously: +First make sure your k8s cluster is accessible (part of the [minimum pre-requisites](#Minimum-Requirements)). You can run the following to verify the cluster: ``` -source <(curl https://raw.githubusercontent.com/cncf/cnf-conformance/master/curl_install.sh) +kubectl cluster-info ``` -*or* -- Use the curl command to download and install, but you will have to export the PATH: +And it should print a running kubernetes master in the output. Common kubectl errors and issues might relate to your KUBECONFIG variable. You can export to your k8s config by doing the following: + ``` -curl https://raw.githubusercontent.com/cncf/cnf-conformance/master/curl_install.sh | bash +export KUBECONFIG=path/to/mycluster.config ``` +*Note: We recommend running cnf-conformance on a non-production cluster.* - -### Post Install of binary - -once installed please follow the [setup instructions](#Setup) below while taking care to replace - -references to `crystal src/cnf-conformance.cr` with `cnf-conformance` - -i.e. for setting up your workspace folder +The next step for cnf-conformance is to run the `setup` which prepares the cnf-conformance suite. This runs pre-reqs to verify you have everything needed in order to run the suite, simply run the following: ``` cnf-conformance setup ``` - - -##### (Recommended) coredns example cnf check out [docs below for more on examples](#example-cnfs) - -Download the conformance configuration to test CoreDNS: +The test suite by default will pull docker images from https://docker.io. You can set your own username and password with local environment variables by doing the following: ``` -wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/release-v0.7-beta1/example-cnfs/coredns/cnf-conformance.yml - -crystal src/cnf-conformance.cr cnf_setup cnf-config=./cnf-conformance.yml +export DOCKERHUB_USERNAME= +export DOCKERHUB_PASSWORD= ``` +Please refer to the [CNF_CONFORMANCE_YML_USAGE.md](CNF_CONFORMANCE_YML_USAGE.md#Using-a-Private-Registry) for details on using a private registry. -
(optional) Install tab completion + +
Install Tab Completion for cnf-conformance (Optional) Check out our (experimental) support for tab completion! @@ -151,220 +172,69 @@ source test.sh ```
-## Source Install - - * Install [crystal-lang](https://crystal-lang.org/install/) version 0.35.1 - * `git clone git@github.com:cncf/cnf-conformance.git` - * in the project directory install the project's crystal dependencies - ``` -cd cnf-conformance -shards install - ``` - -### Post Install +### Configuration +Now cnf-conformance is setup, we're ready to configure it to point at a CNF to test. -once installed please follow the [setup instructions](#Setup) below +#### Using an Example CNF -
(Optional) To set up a *sample cnf* for use with cnf-conformance - -Pick this option if you want to quickly kick the tires and see how an already setup cnf works with the conformance suite +- If you want to use an example CNF, you can download our CoreDNS example CNF by doing the following: ``` -crystal src/cnf-conformance.cr sample_coredns_setup +wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml ``` -
- -
(optional): Build binary from source - -we use the official crystal alpine docker image for builds as you can see in our [actions.yml](.github/workflows/actions.yml) - +- The wget gets a working config file, now tell cnf-conformance to use it by doing the following: ``` -# this is how we build for production. its static and DOES NOT have any runtime dependencies. - -docker pull crystallang/crystal:0.35.1-alpine -docker run --rm -it -v $PWD:/workspace -w /workspace crystallang/crystal:0.35.1-alpine crystal build src/cnf-conformance.cr --release --static --link-flags "-lxml2 -llzma" +cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml ``` -then you can invoke the conformance suite from the binary i.e. - - ``` -./cnf-conformance task_name_to_run - ``` - -
- - -# Setup - -aka configuring the conformance suite for testing a CNF +- There are other examples in the [examples-cnfs](https://github.com/cncf/cnf-conformance/tree/master/example-cnfs) directory that can be used for testing as well. +#### Bring Your Own CNF +If you've brought your own CNF to test, review the [CNF_CONFORMANCE_YML_USAGE.md](CNF_CONFORMANCE_YML_USAGE.md) document on formatting and other requirements. -## Run the setup task first to make sure prereqs are setup +If you've followed the [CNF_CONFORMANCE_YML_USAGE.md](CNF_CONFORMANCE_YML_USAGE.md) guide and have your cnf-conformance.yml ready, you can run the same command we ran for the example CNF to set it up: ``` -crystal src/cnf-conformance.cr setup +cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml ``` +### Running cnf-conformance for the first time +#### Running Tests -## Example cnfs - -To use CoreDNS as an example CNF. - -Download the conformance configuration to test CoreDNS: +If you want to run all tests, do the following (this is assuming your `cnf_setup` ran without errors in the [configuration](#Configuration) steps:) +_For complete usage, see the [USAGE.md](USAGE.md) doc._ ``` -wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/release-v0.7-beta1/example-cnfs/coredns/cnf-conformance.yml +cnf-conformance all ``` -Prepare the test suite to use the CNF by running: - +The following will run only workload tests: ``` -crystal src/cnf-conformance.cr cnf_setup cnf-config=./cnf-conformance.yml +cnf-conformance workload ``` - - -Also checkout other examples in the [examples cnfs](https://github.com/cncf/cnf-conformance/tree/master/example-cnfs) folder in our github repo - - - -## Overview (for setting up your own cnf): - -- Initialize the test suite by running `crystal src/cnf-conformance.cr setup` (creates cnfs folder and other items) -- Create a Conformance configuration file called `cnf-conformance.yml` under the your CNF folder (eg. `cnfs/my_ipsec_cnf/cnf-conformance.yml`) - - See example config (See [latest example in repo](https://github.com/cncf/cnf-conformance/blob/master/cnf-conformance.example.yml)): - - Optionally, copy the example configuration file, [`cnf-conformance-example.yml`](https://github.com/cncf/cnf-conformance/blob/master/cnf-conformance.example.yml), and modify appropriately -- (Optional) Setup your CNF for testing and deploy it to the cluster by running `cnf-conformance cnf_setup cnf-config=path_to_your/cnf_folder` - - _NOTE: if you do not want to automatically deploy the using the helm chart defined in the configuration then you MUST pass `deploy_with_chart=false` to the `cnf_setup` command._ - - _NOTE: you can pass the path to your cnf-conformance.yml to the 'all' command which will install the CNF for you (see below)_ - - - -## Detailed Steps (for setting up your own cnf): - - * Make sure you set your KUBECONFIG - ``` - export KUBECONFIG= - ``` - * Modify the [`cnf-conformance.yml`](https://github.com/cncf/cnf-conformance/blob/master/cnf-conformance.example.yml) file settings for your cnfs - ``` - # In .//cnf-conformance.yml - -helm_directory: -install_script: -deployment_name: -helm_chart: -helm_chart_container_name: -white_list_helm_chart_container_names: - ``` - - * Run the setup tasks to install any prerequisites (useful for setting up sample cnfs) - ``` - crystal src/cnf-conformance.cr setup - ``` - * Run the cleanup tasks to remove prerequisites (useful for starting fresh) - ``` - crystal src/cnf-conformance.cr cleanup - ``` - * Install your CNF into the cnfs directory, download the helm charts, and download the source code: - ``` - crystal src/cnf-conformance.cr cnf_setup cnf-config= - ``` - * To remove your CNF from the cnfs directory and cluster - ``` - crystal src/cnf-conformance.cr cnf_cleanup cnf-config= - ``` - - - -## Get ready to rock and roll! - - - -# Running and checking results for the Conformance testing - - -**Running all (workload and platform) tests** - - ``` -cnf-conformance all cnf-config=/cnf-conformance.yml - -# running all of the workload tests -cnf-conformance workload cnf-config=/cnf-conformance.yml - -# running all of the platform tests +The following would run only the platform tests: +``` cnf-conformance platform - ``` +``` -**Checking the results** +#### Checking Results In the console where the test suite runs: - PASSED or FAILED will be displayed for the tests -A test log file, eg. `cnf-conformance-results-20200401.txt`, will be created which lists PASS or FAIL for every test - -**Cleaning up** +A test log file, eg. `cnf-conformance-results-20201216.txt`, will be created which lists PASS or FAIL for every test based on the date. -Run `cnf-conformance cnf_cleanup cnf-config=/cnf-conformance.yml` +For more details on points, see our [POINTS.md](./POINTS.md) documentation. -_NOTE: Does not handle manually deployed CNFs_ +#### Cleaning Up ---- - - - -# More Example Usage (also see the [complete usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md)) - - -``` -# Run all ga tests (generally available workload and platform tests) -crystal src/cnf-conformance.cr all cnf-config=/cnf-conformance.yml - -# Run all beta and ga tests -crystal src/cnf-conformance.cr all beta - -# Run all alpha, beta, and ga tests -crystal src/cnf-conformance.cr all alpha - -# Run all wip, alpha, beta, and ga tests -crystal src/cnf-conformance.cr all wip - -# Run all tests in the configureation lifecycle category -crystal src/cnf-conformance.cr configuration_lifecycle - -# Run all tests in the installability -crystal src/cnf-conformance.cr installability - -# Run only the workload tests -cnf-conformance workload cnf-config=/cnf-conformance.yml - -# Run only the platform tests -cnf-conformance platform +Run the following to cleanup the specific cnf-conformance test (this is assuming you installed the cnf-conformance.yml in your present working directory): ``` - - - -# Development - -The CNF Conformance Test Suite is modeled after make, or if you're familiar with Ruby, [rake](https://github.com/ruby/rake). Conformance tests are created via tasks using the Crystal library, [SAM.cr](https://github.com/imdrasil/sam.cr). - -To run the automated test suite: - -``` -crystal spec +cnf-conformance cnf_cleanup cnf-config=./cnf-conformance.yml ``` +You can also run `cleanall` and cnf-conformance will attempt to cleanup everything. - -
**Binary build (dev)** - -``` -# this is how we build while developing. HAS runtime dependencies -crystal build src/cnf-conformance.cr -# you can safely ignore warnings and errors as long as the binary at ./cnf-conformance is generated properly -sha256sum cnf-conformance -# checksum here used for release validation -``` - -
+_NOTE: Cleanup does not handle manually deployed CNFs_ diff --git a/KIND-INSTALL.md b/KIND-INSTALL.md index 007d3bd0a..36f7f5e37 100644 --- a/KIND-INSTALL.md +++ b/KIND-INSTALL.md @@ -37,4 +37,4 @@ for node in $(kind get nodes); do done ``` -Now you can use CNFs that require Multus and CNIs, e.g. [examples/ip-forwarder](https://github.com/cncf/cnf-conformance/tree/master/example-cnfs/ip-forwarder) +Now you can use CNFs that require Multus and CNIs, e.g. [examples/ip-forwarder](https://github.com/cncf/cnf-conformance/tree/main/example-cnfs/ip-forwarder) diff --git a/POINTS.md b/POINTS.md new file mode 100644 index 000000000..b4fb025f3 --- /dev/null +++ b/POINTS.md @@ -0,0 +1,9 @@ +CNF-CONFORMANCE Points Usage +--- +### Overview +This will detail the points scored for cnf-conformance suite. + +### Table of Contents + + +This document is a work in progress. diff --git a/README-testsuite.md b/README-testsuite.md new file mode 100644 index 000000000..5220da775 --- /dev/null +++ b/README-testsuite.md @@ -0,0 +1,76 @@ +# CNF Conformance Test Suite +| Main | +|---| +|[![Build Status](https://github.com/cncf/cnf-conformance/workflows/Crystal%20Specs/badge.svg)](https://github.com/cncf/cnf-conformance/actions)| + +The CNF Conformance test suite is a tool that makes it possible to validate telco applications, aka Cloud native Network Functions (CNFs), and the underlying Telecom platforms adherence to Cloud native principles and best practices. + +This test suite initiative works closely with the [CNF WG](cnf-wg/README.md) which determines requirements for the CNF Conformance program. + +The CNF Conformance Test Suite will inspect CNFs for the following characteristics: +- **Compatibility** - CNFs should work with any Certified Kubernetes product and any CNI-compatible network that meet their functionality requirements. +- **Statelessness** - The CNF's state should be stored in a custom resource definition or a separate database (e.g. etcd) rather than requiring local storage. The CNF should also be resilient to node failure. +- **Security** - CNF containers should be isolated from one another and the host. +- **Microservice** - The CNF should be developed and delivered as a microservice. +- **Scalability** - CNFs should support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines). +- **Configuration and Lifecycle** - The CNF's configuration and lifecycle should be managed in a declarative manner, using ConfigMaps, Operators, or other declarative interfaces. +- **Observability** - CNFs should externalize their internal states in a way that supports metrics, tracing, and logging. +- **Installable and Upgradeable** - CNFs should use standard, in-band deployment tools such as Helm (version 3) charts. +- **Hardware Resources and Scheduling** - The CNF container should access all hardware and schedule to specific worker nodes by using a device plugin. +- **Resilience** - CNFs should be resilient to failures inevitable in cloud environments. CNF Resilience should be tested to ensure CNFs are designed to deal with non-carrier-grade shared cloud HW/SW platforms. + +See the [Conformance Test Categories Documentation](https://github.com/cncf/cnf-conformance/blob/main/TEST-CATEGORIES.md) for a complete overview of the tests. + +## Contributing + +Welcome! We gladly accept contributions on new conformance tests, example CNFs, updates to documentation, enhancements, bug reports, and more. +- [Contributing guide](https://github.com/cncf/cnf-conformance/blob/main/CONTRIBUTING.md) +- [Good first issues](https://github.com/cncf/cnf-conformance/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) + +## Communication and community meetings + +- Join the conversation on [CNCF's Slack](https://slack.cncf.io/) channels + - [#cnf-conformance](https://cloud-native.slack.com/archives/CV69TQW7Q) + - [#cnf-conformance-dev](https://cloud-native.slack.com/archives/C014TNCEX8R) + +- Join the monthly [Telecom User Group meetings](https://github.com/cncf/telecom-user-group#meeting-time) + - Meetings on the 1st Mondays of the month + - Meeting minutes are [here](https://docs.google.com/document/d/1yhtI7aiwpdAiRBKyUX6mOJDHAbjOog2mI4Ur2k27D7s/edit) + +- Join the weekly developer meetings + - Meetings every Thursday at 14:15 - 15:00 UTC + - Meeting minutes are [here](https://docs.google.com/document/d/1IbrgjqIkOCvrrSG0DRE6X62UUZpBq-818Mn8q0nkkd0/edit) + +## Implementation overview + +The CNF Conformance Test Suite leverages upstream tools such as [OPA Gatekeeper](https://github.com/open-policy-agent/gatekeeper), [Helm linter](https://github.com/helm/chart-testing), and [Promtool](https://prometheus.io/docs/prometheus/latest/configuration/unit_testing_rules/) for testing CNFs. The upstream tool installation, configuration, and versioning has been made repeatable. + +The test framework and tests (using the upstream tools) are written in the human-readable, compiled language, [Crystal](https://crystal-lang.org/). Common capabilities like dependencies between tests and categories are supported. + +Setup of vanilla upstream K8s on [Equinix Metal](https://metal.equinix.com/) is done with the [CNF Testbed](https://github.com/cncf/cnf-testbed/) platform tool chain, which includes [k8s-infra](https://github.com/crosscloudci/k8s-infra), [Kubespray](https://kubespray.io/). To add support for other providers, please submit a [Pull Request](https://github.com/cncf/cnf-testbed/pulls) to the [CNF Testbed](https://github.com/cncf/cnf-testbed/) repo. + + +## Installation +To get the CNF Test Suite up and running, see the [Installation Guide](INSTALL.md). + +#### To give it a try immediately you can use these quick install steps +Prereqs: kubernetes cluster, wget, curl, helm 3.1.1 or greater on your system already. + +1. Install the latest test suite binary: `source <(curl https://raw.githubusercontent.com/cncf/cnf-conformance/main/curl_install.sh)` +2. Run `setup` to prepare the cnf-conformance suite: `cnf-conformance setup` +3. Pull down an example CNF configuration to try: `wget -O cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml` +4. Initialize the test suite for using the CNF: `cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml` +5. Run all of application/workload tests: `cnf-conformance workload` + + +## Usage + +Check out the [usage documentation](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md) for more info about invoking commands and logging. + +## Code of Conduct + +The CNF Conformance community follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). + +## License terms + +CNF Conformance Test Suite is available under the [Apache 2 license](https://github.com/cncf/cnf-conformance/blob/main/LICENSE). diff --git a/README.md b/README.md index d0f91ec9a..a357b6f12 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,31 @@ # CNF Conformance -| Master | -|---| -|[![Build Status](https://github.com/cncf/cnf-conformance/workflows/Crystal%20Specs/badge.svg)](https://github.com/cncf/cnf-conformance/actions)| +The goal of the CNF Conformance Program is to provide an open source test suite to demonstrate conformance and implementation of cloud native best practices for both open and closed source Cloud Native Network Functions. The conformance program is a living thing. The CNCF community, through the [Cloud Native Network Function Working Group](https://github.com/cncf/cnf-wg/blob/master/README.md), oversees and maintains what it means to be a cloud native conformant telco application (including those applications called network functions). It also develops the process and policy around the certification program. Work on the mechanics of the conformance tests occurs in the [CNF Conformance Test Suite](README-testsuite.md). -The CNF Conformance program enables interoperability of Cloud native Network Functions (CNFs) from multiple vendors running on top of Kubernetes. The goal is to provide an open source test suite to demonstrate conformance and implementation of best practices for both open and closed source Cloud native Network Functions. +## Why Conformance Matters +With such a wide array of applications being developed today, workload conformance tests help ensure that developers can follow cloud native best practices when building greenfield applications and/or modernizing existing applications. A conformance passing application provides the following guarantees: -The CNF Conformance Test Suite will inspect CNFs for the following characteristics: -- **Compatibility** - CNFs should work with any Certified Kubernetes product and any CNI-compatible network that meet their functionality requirements. -- **Statelessness** - The CNF's state should be stored in a custom resource definition or a separate database (e.g. etcd) rather than requiring local storage. The CNF should also be resilient to node failure. -- **Security** - CNF containers should be isolated from one another and the host. -- **Microservice** - The CNF should be developed and delivered as a microservice. -- **Scalability** - CNFs should support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines). -- **Configuration and Lifecycle** - The CNF's configuration and lifecycle should be managed in a declarative manner, using ConfigMaps, Operators, or other declarative interfaces. -- **Observability** - CNFs should externalize their internal states in a way that supports metrics, tracing, and logging. -- **Installable and Upgradeable** - CNFs should use standard, in-band deployment tools such as Helm (version 3) charts. -- **Hardware Resources and Scheduling** - The CNF container should access all hardware and schedule to specific worker nodes by using a device plugin. -- **Resilience** - CNFs should be resilient to failures inevitable in cloud environments. CNF Resilience should be tested to ensure CNFs are designed to deal with non-carrier-grade shared cloud HW/SW platform. +Best practices: Your application follows cloud native best practices. This is useful to know whether you are building upon the work of the community or handling your own custom setup. -See the [Conformance Test Categories Documentation](https://github.com/cncf/cnf-conformance/blob/master/TEST-CATEGORIES.md) for a complete overview of the tests. +Predictability: Your application acts in a predictable manner when running on cloud native infrastructure like Kubernetes. Unexpected behavior should be rare because application specific issues are weeded out during the conformance tests. -## Contributing +Interoperability: Workloads can be ported across various cloud native infrastructures. This standardization is a key advantage of open source software and allows you to avoid vendor lock-in. -Welcome! We gladly accept contributions on new conformance tests, example CNFs, updates to documentation, enhancements, bug reports and more. -- [Contributing guide](https://github.com/cncf/cnf-conformance/blob/master/CONTRIBUTING.md) -- [Good first issues](https://github.com/cncf/cnf-conformance/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) +Implementing and running applications in a cloud native manner will enable you to more fully benefit from the advantages of cloud native infrastructure. -## Communication and community meetings +## CNF Conformance Program -- Join the conversation on [CNCF's Slack](https://slack.cncf.io/) channels - - [#cnf-conformance](https://cloud-native.slack.com/archives/CV69TQW7Q) - - [#cnf-conformance-dev](https://cloud-native.slack.com/archives/C014TNCEX8R) - -- Join the monthly [Telecom User Group meetings](https://github.com/cncf/telecom-user-group#meeting-time) - - Meetings on the 1st Mondays of the month - - Meeting minutes are [here](https://docs.google.com/document/d/1yhtI7aiwpdAiRBKyUX6mOJDHAbjOog2mI4Ur2k27D7s/edit) - -- Join the weekly developer meetings - - Meetings every Thursday at 14:15 - 15:00 UTC - - Meeting minutes are [here](https://docs.google.com/document/d/1IbrgjqIkOCvrrSG0DRE6X62UUZpBq-818Mn8q0nkkd0/edit) +- Instructions - TBD +- FAQ - TBD -## Implementation overview +## Working Group Information -The CNF Conformance Test Suite leverages upstream tools such as [OPA Gatekeeper](https://github.com/open-policy-agent/gatekeeper), [Helm linter](https://github.com/helm/chart-testing), and [Promtool](https://prometheus.io/docs/prometheus/latest/configuration/unit_testing_rules/) for testing CNFs. The upstream tool installation, configuration and versioning has been made repeatable. +To participate and contribute to the program itself (including discussion of +issues affecting conformance and certification), join the mailing list and +slack channel. Details: [CNF WG](https://github.com/cncf/cnf-wg/blob/master/README.md). -The test framework and tests (using the upstream tools) are written in the human readable, compiled language, [Crystal](https://crystal-lang.org/). Common capabilities like dependencies between tests and categories are supported. +## Test Suite Information -Setup of vanilla upstream K8s on [Packet](https://www.packet.com/) is done with the [CNF Testbed](https://github.com/cncf/cnf-testbed/) platform tool chain, which includes [k8s-infra](https://github.com/crosscloudci/k8s-infra), [Kubespray](https://kubespray.io/). To add support for other providers, please submit a [Pull Request](https://github.com/cncf/cnf-testbed/pulls) to the [CNF Testbed](https://github.com/cncf/cnf-testbed/) repo. +To contribute to or use the test suite you can join the slack channel, weekly meetings, and interact in GitHub. Details: [Test suite](README-testsuite.md). - -## Installation - -To quickly get CNF Conformance up and running, see the [Installation Guide](INSTALL.md). - -## Usage - -Check out the [usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md) for more info about invoking commands and logging - -## Code of Conduct - -The CNF Conformance community follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). - -## License terms - -CNF Conformance is available under the [Apache 2 license](https://github.com/cncf/cnf-conformance/blob/master/LICENSE). +To quickly get Test Suite up and running, see the [Quick Installation Guide](README-testsuite.md#installation). diff --git a/RELEASE.md b/RELEASE.md index 96c2d865b..af86b39fa 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,15 @@ -# 2020-03-13 - [DRAFT] when to tag a new release on the CNF Conformance repo - ## How to create a tagged release +**[Automated releases]** +- Create a tag off of the main branch +``` +git tag -a 'vMAJOR.MINOR.PATCH' -m "vMAJOR.MINOR.PATCH Release" +git push --tags +``` +- Wait for github actions to complete the build +- Go to https://github.com/cncf/cnf-conformance/releases +- Locate the draft release for the build +- Modify the release notes to reflect the contents for the release +- Mark the release as non-draft See https://help.github.com/en/github/administering-a-repository/managing-releases-in-a-repository#creating-a-release @@ -9,7 +18,7 @@ See https://help.github.com/en/github/administering-a-repository/managing-releas **[PATCH] Releases for backwards compatible bug fixes and updates to existing tests** - bug fixes or trivial update to existing test -- 1 or more updated tests are merged to master +- 1 or more updated tests are merged to main - all automated integration/spec coverage passes - usage documentation updated, if usage changed for test - new test is marked as GA :heavy_check_mark: @@ -22,7 +31,7 @@ _Note: this covers both workload (ie. application) and platform tests_ **[MINOR] Releases for new tests, which do not break existing usage** - new test is moving to GA status. (could be brand new or moved from PoC to GA) -- 1 or more tests are merged to master +- 1 or more tests are merged to main - new test(s) have automated integration/spec coverage - all automated integration/spec coverage passes - all new tests have working usage documentation @@ -41,28 +50,15 @@ _Note: this covers both workload (ie. application) and platform tests_ **[MAJOR] Releases for changes which break existing usage** - Change which breaks backwards compatibility with existing usage -- Change merged to `master` +- Change merged to `main` - All automated integration/spec coverage passes - Change is fully documented for anything affected - Tag with new major version vMAJOR_VERSION.MINOR.PATCH, eg. v2.0.0 _Note: this covers both workload (ie. application) and platform tests_ -**[Automated releases]** -- Create a tag off of the master branch -``` -git tag -a 'vMAJOR.MINOR.PATCH' -m "vMAJOR.MINOR.PATCH Release" -git push --tags -``` -- Wait for github actions to complete the build -- Go to https://github.com/cncf/cnf-conformance/releases -- Locate the draft release for the build -- Modify the release notes to reflect the contents for the release -- Mark the release as non-draft - - **[Manually create builds]** -based on [INSTALL.md#optional-build-binary](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#optional-build-binary) and [Minimal instructions to run the tests from source (as of 2020-06-23)](https://hackmd.io/hcHoJEKaRWuyf_fZ7ITxLw) +based on [INSTALL.md#optional-build-binary](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#optional-build-binary) and [Minimal instructions to run the tests from source (as of 2020-06-23)](https://hackmd.io/hcHoJEKaRWuyf_fZ7ITxLw) - Download source: `git clone https://github.com/cncf/cnf-conformance.git` - `cd cnf-conformance` - Install dependencies: `shards install` diff --git a/ROADMAP-testsuite.md b/ROADMAP-testsuite.md new file mode 100644 index 000000000..280cb1487 --- /dev/null +++ b/ROADMAP-testsuite.md @@ -0,0 +1,38 @@ +Test Suite Roadmap +--- + +This document defines a high level roadmap for the "CNF Conformance" Test Suite. + +The following is a selection of some of the major features the Test Suite team plans to explore. This roadmap will continue to be updated as priorities evolve. + +To get a more complete overview of planned features and current work see the [project board](https://github.com/cncf/cnf-conformance/projects/1), [issue tracker](https://github.com/cncf/cnf-conformance/issues) and [milestones](https://github.com/cncf/cnf-conformance/milestones) in GitHub. + +### Create tests + +- Build tests to assess the cloud nativeness of CNFs and workloads + + +### Onboarding + +- Improve onboarding documentation for new contributors +- Create a Governance structure for test suite maintainers +- Update usage documentation for users of the test suite + + +### Enhance the functionality of the test suite framework + +- Add functionality to test multiple containers within a pod +- Add functionality to test multiple deployments + + +### Assess the cloud nativeness of example CNFs + +- Assess example CNFs that contain multiple containers within a pod +- Assess example CNFs that use multiple deployments + + +### Rename and rebrand test suite + +- Rename the "CNF Conformance" test suite +- Create a logo for the test suite +- Build a landing page for the test suite diff --git a/SOURCE_INSTALL.md b/SOURCE_INSTALL.md new file mode 100644 index 000000000..dbd2bae06 --- /dev/null +++ b/SOURCE_INSTALL.md @@ -0,0 +1,251 @@ +Installing the CNF Conformance Test Suite from Source +--- +### Overview +This INSTALL guide will detail the minimum requirements needed for cnf-conformance to install from source. + +### Table of Contents +* [**Pre-Requisites**](#Pre-Requisites) +* [**Installation**](#Installation) +* [**Setup**](#Setup) +* [**Configuration**](#Configuration) +* [**Running cnf-conformance for the first time**](#Running-cnf-conformance-for-the-first-time) + +### Pre-Requisites + +#### Requirements +* **kubernetes cluster** *(Working k8s cluster, see [supported k8s and installation details](#Details-on-supported-k8s-clusters-and-installation) on installation.* +* **kubectl** *(run commands against k8 clusters, see [installing kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) for more details.* +* **curl** +* **helm 3.1.1** *or newer* *(cnf-conformance installs if not found locally)* +* **git** *(used to check out code from github)* +* **crystal-lang** version 0.35.1 *(to compile the source and build the binary, see [crystal installation](https://crystal-lang.org/install/)) for more information.* +* **shards** ([dependency manager](https://github.com/crystal-lang/shards) for crystal-lang) +##### Optional Requirement +* **docker** (for building from crystal alpine image) + +#### Details on supported k8s clusters and installation: +
Click here to drop down details + +

+ +##### Supported k8s Clusters +- [Access](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/) to a working [Certified K8s](https://cncf.io/ck) cluster via [KUBECONFIG environment variable](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#set-the-kubeconfig-environment-variable). (See [K8s Getting started guide](https://kubernetes.io/docs/setup/) for options) +- Follow the optional instructions below if you don't already have a k8s cluster setup + +##### Kind + +- Follow the [kind install](KIND-INSTALL.md) instructions to setup a cluster in [kind](https://kind.sigs.k8s.io/) + +##### k8s-infra + +- You can clone the CNF-Testbed project if you have an account at Equinix Metal (formerly Packet.net). Get the code by running the following: + +``` +git clone https://github.com/cncf/cnf-testbed.git +``` + +- Clone the K8s-infra repo then Follow the [prerequisites](https://github.com/cncf/cnf-testbed/tree/master/tools#pre-requisites) for [deploying a K8s cluster](https://github.com/cncf/cnf-testbed/tree/master/tools#deploying-a-kubernetes-cluster-using-the-makefile--ci-tools) for a Equinix Metal host. +- If you already have IP addresses for your provider, and you want to manually install a K8s cluster, you can use k8s-infra to do this within your cnf-testbed repo clone. + +``` +cd tools/ && git clone https://github.com/crosscloudci/k8s-infra.git +``` + +- Now follow the [K8s-infra quick start](https://github.com/crosscloudci/k8s-infra/blob/master/README.md#quick-start) for instructions on how to install. + +

+
+ + + +### Installation +We can assume you have access to a working kubernetes cluster. We recommend only running the cnf-conformance suite on dev or test clusters. + +- Verify your KUBECONFIG points to your correct k8s cluster: + ``` + echo $KUBECONFIG + ``` + If there's no output or it's pointed to the wrong config, run the export to the correct config: + ``` + export KUBECONFIG=yourkubeconfig + ``` +- Verify your cluster is accessible with kubectl (this command should provide information about your kubernetes cluster): + ``` + kubectl cluster-info + ``` +- You'll need cystal-lang v0.35.1 or higher installed. You can follow their [install instructions](https://crystal-lang.org/install/) for their many different methods. +- cnf-conformance needs helm-3.1.1 or greater. You can install helm by checking their [installation methods](https://helm.sh/docs/helm/helm_install/) but you can also skip this as cnf-conformance will install if it's not found. +- Checkout the source code with git: + ``` + git clone git@github.com:cncf/cnf-conformance.git + ``` +- Change directory into the source: + ``` + cd cnf-conformance + ``` +- Now we need to run shards to pull down requirements needed to build and compile cnf-conformance: + ``` + shards install + ``` +- Now build a cnf-conformance binary (this method will have runtime dependencies but should not pose any issues): + ``` + crystal build src/cnf-conformance.cr + ``` + This should create an executable `cnf-conformance` binary in your source checkout. + +
(Optional) Build cnf-conformance using Docker Alpine Image +

+ +We use the official crystal alpine docker image for builds; seen in [actions.yml](.github/workflows/actions.yml) + +*This build method is static and DOES NOT have any runtime dependencies.* + +- To build using docker crystal alpine image (great if you don't have crystal installed) + +``` +docker pull crystallang/crystal:0.35.1-alpine +docker run --rm -it -v $PWD:/workspace -w /workspace crystallang/crystal:0.35.1-alpine crystal build src/cnf-conformance.cr --release --static --link-flags "-lxml2 -llzma" +``` +

+
+ +
(Optional) Install Tab Completion + +

+NOTE: Also compatible with the installation styles from kubectl completion install if you prefer +https://kubernetes.io/docs/tasks/tools/install-kubectl/#enable-kubectl-autocompletion + +You will need to have cnf-conformance executable in your current PATH for this to work properly. + +``` +./cnf-conformance completion -l error > test.sh +source test.sh +``` +

+
+ +
Other Information on Crystal Builds +

+The CNF Conformance Test Suite is modeled after make, or if you're familiar with Ruby, [rake](https://github.com/ruby/rake). Conformance tests are created via tasks using the Crystal library, [SAM.cr](https://github.com/imdrasil/sam.cr). + +To run the automated test suite within the source clone: + +``` +crystal spec +``` +

+ +### Setup +Now that we have a `cnf-conformance` binary, we can run `setup` to ensure it has all the pre-requisites needed in order to successfully run tests and setup required cnfs/ directory and other files required for cnf-conformance. + +- Run the following to setup cnf-conformance: + ``` + ./cnf-conformance setup + ``` +- If you have crystal installed, you can also run by: + ``` + crystal src/cnf-conformance.cr setup + ``` +This should display output of all the pre-requisites (and install helm if not found on the system you intend to run from). Any missing requirements will need to be satisfied before proceeding or could result in errors, etc. + +### Configuration +Now that cnf-conformance is installed and setup, we can now run CNF workloads and tests. We recommend installing and running a sample CNF to ensure cnf-conformance is operational and set expectations of the output. + + +#### Configuring an example CNF + +To use CoreDNS as an example CNF. Download the conformance configuration to test CoreDNS: + +- Make sure you are in your cnf-conformance/ source repo checkout directory and do the following: + ``` + curl -o cnf-conformance.yml https://raw.githubusercontent.com/cncf/cnf-conformance/main/example-cnfs/coredns/cnf-conformance.yml + ``` +- Prepare the test suite to use the CNF by running: + ``` + # via built binary + ./cnf-conformance cnf_setup cnf-config=./cnf-conformance.yml + ``` + Or + ``` + # via crystal + crystal src/cnf-conformance.cr cnf_setup cnf-config=./cnf- conformance.yml + ``` + +There are other examples in the [examples cnfs](https://github.com/cncf/cnf-conformance/tree/main/example-cnfs) folder if you would like to test others. + +#### NOTE: CNF **must** have a [helm chart](https://helm.sh/) + +- To pass all current tests +- To support auto deployment of the CNF from the ([cnf-conformance.yml](https://github.com/cncf/cnf-conformance/blob/main/CNF_CONFORMANCE_YML_USAGE.md)) configuration file. + +### Running cnf-conformance for the first time + +#### Running Tests + +If you want to run all tests for CoreDNS Example CNF, do the following (this is assuming your `cnf_setup` ran without errors in the [configuration](#Configuring-an-example-CNF) steps:) +_For complete usage, see the [USAGE.md](USAGE.md) doc._ + +``` +./cnf-conformance all +``` + +The following will run only workload tests: +``` +./cnf-conformance workload +``` + +The following would run only the platform tests: +``` +./cnf-conformance platform +``` +You can also run via `crystal` by replacing the `./cnf-conformance` with `crystal spec src/cnf-conformance.cr` and then the argument. + +#### More Example Usage (also see the [complete usage documentation](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md)) + +``` +# These assume you've already run the cnf_setup pointing at a cnf-conformance.yml config above. You can always specify your config at the end of each command as well, eg: +./cnf-conformance all cnf-config=/cnf-conformance.yml + +# Runs all ga tests (generally available workload and platform tests) +./cnf-conformance all + +# Runs all alpha, beta and ga tests +./cnf-conformance all alpha + +# Runs all beta and ga tests +./cnf-conformance all beta + +# Run all wip, alpha, beta, and ga tests +./cnf-conformance all wip + +# Run all tests in the configureation lifecycle category +./cnf-conformance configuration_lifecycle + +# Run all tests in the installability +./cnf-conformance installability +``` + +#### Checking Results + +In the console where the test suite runs: +- PASSED or FAILED will be displayed for the tests + +A test log file, eg. `cnf-conformance-results-20201216.txt`, will be created which lists PASS or FAIL for every test based on the date. + +For more details on points, see our [POINTS.md](./POINTS.md) documentation. + +#### Cleaning Up + +Run the following to cleanup the specific cnf-conformance test: +``` +./cnf-conformance cnf_cleanup cnf-config=./cnf-conformance.yml +``` +You can also run `cleanall` and cnf-conformance will attempt to cleanup everything. + +_NOTE: Cleanup does not handle manually deployed CNFs_ + +### Ready to Bring Your Own CNF? +You can check out our [CNF_CONFORMANCE_YML_USAGE.md](https://github.com/cncf/cnf-conformance/blob/main/CNF_CONFORMANCE_YML_USAGE.md) document on what is required to bring or use your own CNF. + +- Follow the [INSTALL](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md) or [SOURCE-INSTALL](https://github.com/cncf/cnf-conformance/blob/main/SOURCE-INSTALL.md) to build the binary. +- Now head over to [CNF_CONFORMANCE_YML_USAGE.md](https://github.com/cncf/cnf-conformance/blob/main/CNF_CONFORMANCE_YML_USAGE.md) for more detailed steps. diff --git a/TEST-CATEGORIES.md b/TEST-CATEGORIES.md index ba955ecab..5b2640f2a 100644 --- a/TEST-CATEGORIES.md +++ b/TEST-CATEGORIES.md @@ -1,5 +1,5 @@ # Conformance Test Categories -The CNF Conformance program validates interoperability of CNF **workloads** supplied by multiple different vendors orchestrated by Kubernetes **platforms** that are supplied by multiple different vendors. The goal is to provide an open source test suite to enable both open and closed source CNFs to demonstrate conformance and implementation of best practices. For more detailed CLI documentation see the [usage document.](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md) +The CNF Conformance program validates interoperability of CNF **workloads** supplied by multiple different vendors orchestrated by Kubernetes **platforms** that are supplied by multiple different vendors. The goal is to provide an open source test suite to enable both open and closed source CNFs to demonstrate conformance and implementation of best practices. For more detailed CLI documentation see the [usage document.](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md) ## Compatability Tests #### CNFs should work with any Certified Kubernetes product and any CNI-compatible network that meet their functionality requirements. The CNF Conformance Suite validates this: @@ -40,7 +40,7 @@ The CNF Conformance program validates interoperability of CNF **workloads** supp * Test large scale autoscaling with load test tools like [CNF Testbed](https://github.com/cncf/cnf-testbed) * Test if the CNF control layer responds to retries for failed communication (e.g. using [Pumba](https://github.com/alexei-led/pumba) or [Blockade](https://github.com/worstcase/blockade) for network chaos and [Envoy](https://github.com/envoyproxy/envoy) for retries) -(see [scalability test usage documentation](https://github.com/cncf/cnf-conformance/blob/master/USAGE.md#scaling-tests)) +(see [scalability test usage documentation](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#scaling-tests)) ## Configuration and Lifecycle Tests #### Configuration and lifecycle should be managed in a declarative manner, using [ConfigMaps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/), [Operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), or other [declarative interfaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#understanding-kubernetes-objects). The Conformance suite checks this by: @@ -52,7 +52,8 @@ The CNF Conformance program validates interoperability of CNF **workloads** supp * Checking if the pod/container can be started without mounting a volume (e.g. using [helm configuration](https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/)) that has configuration files * Testing to see if we can start pods/containers and see that the application continues to perform (e.g. using [Litmus](https://github.com/litmuschaos/litmus)) * Testing by reseting any child processes, and when the parent process is started, checking to see if those child processes are reaped (ie. monitoring processes with [Falco](https://github.com/falcosecurity/falco) or [sysdig-inspect](https://github.com/draios/sysdig-inspect)) -* Testing if the CNF can perform a rolling update (i.e. [kubectl rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/)) +* Testing if the CNF can perform a rolling update (also rolling downgrade) (i.e. [kubectl rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/)) +* Testing if the CNF can perform a rollback (i.e. [kubectl_rollout_undo](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-to-a-previous-revision)) * Testing if there are any (non-declarative) hardcoded IP addresses or subnet masks ## Observability Tests diff --git a/USAGE.md b/USAGE.md index a009fed0c..a01f404a6 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,375 +1,532 @@ # CNF Conformance Test CLI Usage Documentation -The CNF Conformance Test suite can be run in developer mode (using crystal lang directly) or in production mode (using an executable). See the [pseudo code documentation](https://github.com/cncf/cnf-conformance/blob/master/PSEUDO-CODE.md) for examples of how the internals of WIP tests might work. +### Table of Contents +* [Overview](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#overview) +* [Syntax and Usage](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#syntax-for-running-any-of-the-tests) +* [Common Examples](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#common-example-commands) +* [Logging Options](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#logging-options) +* [Compatibility Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#compatibility-tests) +* [Statelessness Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#statelessness-tests) +* [Security Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#security-tests) +* [Microservice Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#microservice-tests) +* [Scalability Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#scalability-tests) +* [Configuration and Lifecycle Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#configuration-and-lifecycle-tests) +* [Observability Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#observability-tests) +* [Installable and Upgradeable Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#installable-and-upgradeable-tests) +* [Hardware Resources and Scheduling Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#hardware-resources-and-scheduling-tests) +* [Resilience Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#resilience-tests) +* [Platform Tests](https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#platform-tests) + +### Overview +The CNF Conformance Test suite can be run in production mode (using an executable) or in developer mode (using [crystal lang directly](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#source-install)). See the [pseudo code documentation](https://github.com/cncf/cnf-conformance/blob/main/PSEUDO-CODE.md) for examples of how the internals of WIP tests might work. ### Syntax for running any of the tests ``` -# Developer mode -crystal src/cnf-conformance.cr - # Production mode ./cnf-conformance -``` -### Validating a cnf-conformance.yml file -``` # Developer mode -crystal src/cnf-conformance.cr validate_config cnf-config=[PATH_TO]/cnf-conformance.yml - -# Production mode -./cnf-conformance validate_config cnf-config=[PATH_TO]/cnf-conformance.yml +crystal src/cnf-conformance.cr ``` +:star: *Note: All usage commands in this document will use the production (binary executable) syntax unless otherwise stated. + +* :heavy_check_mark: indicates implemented into stable release +* :bulb: indicates Proof of Concept +* :memo: indicates To Do +* :x: indicates WARNINGS* + +### Results Output + +* :heavy_check_mark: PASSED indicates it meets best practice, positive points given. +* :heavy_multiplication_x: SKIPPED indicates the test was skipped (output should provide a reason), no points given. +* :x: FAILED indicates the test failed, negative points given. -### Building the executable +--- +### Common Example Commands + +#### Building the executable +This is the command to build the binary executable if in developer mode or using the source install method ([requires crystal](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#source-install)): ``` crystal build src/cnf-conformance.cr ``` -## Running all of the CNF Conformance tests (platform and workload) + +#### Validating a cnf-conformance.yml file: +``` +./cnf-conformance validate_config cnf-config=[PATH_TO]/cnf-conformance.yml +``` + +#### Running all of the CNF Conformance tests (platform and workload): ``` -crystal src/cnf-conformance.cr all cnf-config=/cnf-conformance.yml +./cnf-conformance all cnf-config=/cnf-conformance.yml ``` -## Running all of the CNF Conformance tests (including proofs of concepts) +#### Running all of the CNF Conformance tests (including proofs of concepts) ``` -crystal src/cnf-conformance.cr all poc cnf-config=/cnf-conformance.yml +./cnf-conformance all poc cnf-config=/cnf-conformance.yml ``` -## Running all of the workload CNF Conformance tests +#### Running all of the workload CNF Conformance tests ``` crystal src/cnf-conformance.cr workload cnf-config=/cnf-conformance.yml ``` -## Running all of the platform CNF Conformance tests +#### Running all of the platform or workload CNF Conformance tests independently: + +##### Run platform only tests: ``` -crystal src/cnf-conformance.cr platform +./cnf-conformance platform +``` +##### Run workload only tests: +``` +./cnf-conformance workload +``` + +#### Get available options and to see all available tests from command line: +``` +./cnf-conformance help ``` -## Logging +#### Clean up the CNF Conformance test suite, the K8s cluster, and upstream projects: +``` +./cnf-conformance cleanup +``` +--- +### Logging Options + +#### Update the loglevel from command line: ``` # cmd line ./cnf-conformance -l debug test - -# make sure to use -- if running from source +``` +#### If in developer mode, make sure to use - - if running from source: +``` crystal src/cnf-conformance.cr -- -l debug test +``` -# env var +#### You can also use env var for logging: +``` LOGLEVEL=DEBUG ./cnf-conformance test ``` -NOTE: When setting log level precedence highest of following wins +:star: Note: When setting log level, the following is the order of precedence: -1. Cli flag is highest precedence -2. Environment var is next level of precedence -3. [Config file](https://github.com/cncf/cnf-conformance/blob/master/config.yml) is last level of precedence +1. CLI or Command line flag +2. Environment variable +3. CNF-Conformance [Config file](https://github.com/cncf/cnf-conformance/blob/main/config.yml) +##### Verbose Option Also setting the verbose option for many tasks will add extra output to help with debugging ``` -crystal src/cnf-conformance.cr test_name verbose +./cnf-conformance test_name verbose ``` -### Running The Linter +#### Running The Linter in Developer Mode -https://github.com/crystal-ameba/ameba +See https://github.com/crystal-ameba/ameba for more details. Follow the [INSTALL](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md) guide starting at the [Source Install](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#source-install) for more details running cnf-conformance in developer mode. ``` shards install # only for first install crystal bin/ameba.cr ``` -## To see a list of all tasks in the test suite - -``` -crystal src/cnf-conformance.cr help -``` - - -## Compatibility Tests +--- +### Compatibility Tests #### :heavy_check_mark: To run all of the compatibility tests ``` -crystal src/cnf-conformance.cr compatibility +./cnf-conformance compatibility ``` -#### (To Do) To check of the CNF's CNI plugin accepts valid calls from the [CNI specification](https://github.com/containernetworking/cni/blob/master/SPEC.md) + +
Details for Compatibility Tests To Do's +

+ +#### :memo: (To Do) To check of the CNF's CNI plugin accepts valid calls from the [CNI specification](https://github.com/containernetworking/cni/blob/master/SPEC.md) ``` crystal src/cnf-conformance.cr cni_spec ``` -#### (To Do) To check for the use of alpha K8s API endpoints +#### :memo: (To Do) To check for the use of alpha K8s API endpoints ``` crystal src/cnf-conformance.cr api_snoop_alpha ``` -#### (To Do) To check for the use of beta K8s API endpoints +#### :memo: (To Do) To check for the use of beta K8s API endpoints ``` crystal src/cnf-conformance.cr api_snoop_beta ``` -#### (To Do) To check for the use of generally available (GA) K8s API endpoints +#### :memo: (To Do) To check for the use of generally available (GA) K8s API endpoints ``` crystal src/cnf-conformance.cr api_snoop_general_apis ``` +

+
- -## Statelessness Tests +--- +### Statelessness Tests #### :heavy_check_mark: To run all of the statelessness tests ``` -crystal src/cnf-conformance.cr stateless +./cnf-conformance stateless ``` -#### (To Do) To test if the CNF responds properly [when being restarted](//https://github.com/litmuschaos/litmus) + +#### :heavy_check_mark: To test if the CNF uses a volume host path ``` -crystal src/cnf-conformance.cr reset_cnf +./cnf-conformance volume_hostpath_not_found ``` -#### (To Do) To test if, when parent processes are restarted, the [child processes](https://github.com/falcosecurity/falco) are [reaped](https://github.com/draios/sysdig-inspect) + +#### :heavy_check_mark: To test if the CNF uses local storage ``` -crystal src/cnf-conformance.cr check_reaped +./cnf-conformance no_local_volume_configuration ``` -#### :heavy_check_mark: To test if the CNF uses a volume host path +
Details for Statelessness Tests To Do's +

+ +#### :memo: (To Do) To test if the CNF responds properly [when being restarted](//https://github.com/litmuschaos/litmus) +``` +crystal src/cnf-conformance.cr reset_cnf +``` +#### :memo: (To Do) To test if, when parent processes are restarted, the [child processes](https://github.com/falcosecurity/falco) are [reaped](https://github.com/draios/sysdig-inspect) ``` -crystal src/cnf-conformance.cr volume_hostpath_not_found +crystal src/cnf-conformance.cr check_reaped ``` -## Security Tests +

+
+ +--- +### Security Tests #### :heavy_check_mark: To run all of the security tests ``` -crystal src/cnf-conformance.cr security +./cnf-conformance security ``` #### :heavy_check_mark: To check if any containers are running in [privileged mode](https://github.com/open-policy-agent/gatekeeper) ``` -crystal src/cnf-conformance.cr privileged +./cnf-conformance privileged ``` -#### (To Do) To check if there are any [shells running in the container](https://github.com/open-policy-agent/gatekeeper) + +
Details for Security Tests To Do's +

+ +#### :memo: (To Do) To check if there are any [shells running in the container](https://github.com/open-policy-agent/gatekeeper) ``` crystal src/cnf-conformance.cr shells ``` -#### [To Do] To check if there are any [protected directories](https://github.com/open-policy-agent/gatekeeper) or files that are accessed from within the container +#### :memo: (To Do) To check if there are any [protected directories](https://github.com/open-policy-agent/gatekeeper) or files that are accessed from within the container ``` crystal src/cnf-conformance.cr protected_access ``` -## Microservice Tests +

+
+ +--- +### Microservice Tests #### :heavy_check_mark: To run all of the microservice tests ``` -crystal src/cnf-conformance.cr microservice +./cnf-conformance microservice ``` #### :heavy_check_mark: To check if the CNF has a reasonable image size ``` -crystal src/cnf-conformance.cr reasonable_image_size +./cnf-conformance reasonable_image_size ``` #### :heavy_check_mark: To check if the CNF have a reasonable startup time ``` -crystal src/cnf-conformance.cr reasonable_startup_time +./cnf-conformance reasonable_startup_time destructive ``` - -## Scalability Tests - +--- +### Scalability Tests #### :heavy_check_mark: To run all of the scalability tests ``` -crystal src/cnf-conformance.cr scalability +./cnf-conformance scalability ``` #### :heavy_check_mark: To test the [increasing and decreasing of capacity](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#scaling-resources) -Optional: To install the sample coredns cnf: +
Optional: To install the sample coredns cnf: to run test +

+ +``` +./cnf-conformance sample_coredns_setup helm_chart= +``` +Or optionally modify the your cnf's cnf-conformance.yml file to include the helm_chart name, e.g. ``` -crystal src/cnf-conformance.cr sample_coredns_setup helm_chart= -# Or optionally modify the your cnf's cnf-conformance.yml file to include the helm_chart name -# e.g. helm_chart: stable/coredns ``` -To run the capacity test +To run the capacity test: +``` +./cnf-conformance increase_decrease_capacity deployment_name=coredns-coredns +``` +Or optionally modify the your cnf's cnf-conformance.yml file to include the deployment name, e.g. ``` -crystal src/cnf-conformance.cr increase_decrease_capacity deployment_name=coredns-coredns -# Or optionally modify the your cnf's cnf-conformance.yml file to include the deployment name -# e.g. deployment_name: coredns/coredns ``` -#### (To Do) To test small scale autoscaling +

+
+ + +**Remediation for failing this test:** + +Check out the kubectl docs for how to [manually scale your cnf.](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#scaling-resources) + +Also here is some info about [things that could cause failures.](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#failed-deployment) + + +#### :heavy_check_mark: To test if Cluster API is enabled on the platform and manages a node +``` +./cnf-conformance clusterapi_enabled +``` + +
Details for Scalability Tests To Do's +

+ +#### :memo: (To Do) To test small scale autoscaling ``` crystal src/cnf-conformance.cr small_autoscaling ``` -#### (To Do) To test [large scale autoscaling](https://github.com/cncf/cnf-testbed) +#### :memo: (To Do) To test [large scale autoscaling](https://github.com/cncf/cnf-testbed) ``` crystal src/cnf-conformance.cr large_autoscaling ``` -#### (To Do) To test if the CNF responds to [network](https://github.com/alexei-led/pumba) [chaos](https://github.com/worstcase/blockade) +#### :memo: (To Do) To test if the CNF responds to [network](https://github.com/alexei-led/pumba) [chaos](https://github.com/worstcase/blockade) ``` crystal src/cnf-conformance.cr network_chaos ``` -#### (To Do) To test if the CNF control layer uses [external retry logic](https://github.com/envoyproxy/envoy) +#### :memo: (To Do) To test if the CNF control layer uses [external retry logic](https://github.com/envoyproxy/envoy) ``` crystal src/cnf-conformance.cr external_retry ``` +

+
-## Configuration and Lifecycle Tests +--- +### Configuration and Lifecycle Tests #### :heavy_check_mark: To run all of the configuration and lifecycle tests ``` -crystal src/cnf-conformance.cr configuration_lifecycle +./cnf-conformance configuration_lifecycle ``` - -#### (To Do) To test if the CNF is installed with a versioned Helm v3 Chart +#### :heavy_check_mark: To test if there is a liveness entry in the Helm chart ``` -crystal src/cnf-conformance.cr versioned_helm_chart +./cnf-conformance liveness +``` +##### :heavy_check_mark: To test if there is a readiness entry in the Helm chart +``` +./cnf-conformance readiness ``` #### :heavy_check_mark: To test if there are any (non-declarative) hardcoded IP addresses or subnet masks ``` -crystal src/cnf-conformance.cr ip_addresses +./cnf-conformance ip_addresses ``` #### :heavy_check_mark: To test if there are node ports used in the service configuration ``` -crystal src/cnf-conformance.cr nodeport_not_used +./cnf-conformance nodeport_not_used ``` #### :heavy_check_mark: To test if there are any (non-declarative) hardcoded IP addresses or subnet masks in the K8s runtime configuration ``` -crystal src/cnf-conformance.cr hardcoded_ip_addresses_in_k8s_runtime_configuration +./cnf-conformance hardcoded_ip_addresses_in_k8s_runtime_configuration +``` + +#### :heavy_check_mark: To check if a CNF version can be downgraded through a rolling_downgrade +``` +./cnf-conformance rolling_downgrade ``` -#### (PoC) To test if there is a liveness entry in the Helm chart + +#### :heavy_check_mark: To check if a CNF version can be rolled back [rollback](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-a-deployment) +``` +./cnf-conformance rollback ``` -crystal src/cnf-conformance.cr liveness +#### :heavy_check_mark: To check if a CNF uses K8s secrets ``` -#### (PoC) To test if there is a readiness entry in the Helm chart +./cnf-conformance secrets_used ``` -crystal src/cnf-conformance.cr readiness +##Additional information## +Rules for the test: +The whole test passes if *any* workload resource in the cnf uses a (non-exempt) secret. +If no workload resources use a (non-exempt) secret, the test is skipped. + +#### :heavy_check_mark: To check if a CNF version uses [immutable configmaps](https://kubernetes.io/docs/concepts/configuration/configmap/#configmap-immutable) ``` -#### (To Do) Test starting a container without mounting a volume that has configuration files +./cnf-conformance immutable_configmaps +``` + +
Details for Configuration and Lifecycle Tests To Do's +

+ +#### :memo: (To Do) To test if the CNF is installed with a versioned Helm v3 Chart +``` +crystal src/cnf-conformance.cr versioned_helm_chart +``` +#### :memo: (To Do) Test starting a container without mounting a volume that has configuration files ``` crystal src/cnf-conformance.cr no_volume_with_configuration ``` -#### (To Do) To test if the CNF responds properly [when being restarted](//https://github.com/litmuschaos/litmus) +#### :memo: (To Do) To test if the CNF responds properly [when being restarted](//https://github.com/litmuschaos/litmus) ``` crystal src/cnf-conformance.cr reset_cnf ``` -#### (To Do) To test if, when parent processes are restarted, the [child processes](https://github.com/falcosecurity/falco) are [reaped](https://github.com/draios/sysdig-inspect) +#### :memo: (To Do) To test if, when parent processes are restarted, the [child processes](https://github.com/falcosecurity/falco) are [reaped](https://github.com/draios/sysdig-inspect) ``` crystal src/cnf-conformance.cr check_reaped ``` -#### (To Do) To test if the CNF can perform a [rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/) -``` -crystal src/cnf-conformance.cr rolling_update -``` -## Observability Tests +

+
+ +--- +### Observability Tests #### :heavy_check_mark: To run all observability tests ``` -crystal src/cnf-conformance.cr observability +./cnf-conformance observability ``` -#### (To Do) Test if there traffic to Fluentd + +
Details for Observability Tests To Do's +

+ +#### :memo: (To Do) Test if there traffic to Fluentd ``` crystal src/cnf-conformance.cr fluentd_traffic ``` -#### (To Do) Test if there is traffic to Jaeger +#### :memo: (To Do) Test if there is traffic to Jaeger ``` crystal src/cnf-conformance.cr jaeger_traffic ``` -#### (To Do) Test if there is traffic to Prometheus +#### :memo: (To Do) Test if there is traffic to Prometheus ``` crystal src/cnf-conformance.cr prometheus traffic ``` -#### (To Do) Test if tracing calls are compatible with [OpenTelemetry](https://opentracing.io/) +#### :memo: (To Do) Test if tracing calls are compatible with [OpenTelemetry](https://opentracing.io/) ``` crystal src/cnf-conformance.cr opentelemetry_compatible ``` -#### (To Do) Test are if the monitoring calls are compatible with [OpenMetric](https://github.com/OpenObservability/OpenMetrics) +#### :memo: (To Do) Test are if the monitoring calls are compatible with [OpenMetric](https://github.com/OpenObservability/OpenMetrics) ``` crystal src/cnf-conformance.cr openmetric_compatible ``` +

+
-## Installable and Upgradeable Tests +--- +### Installable and Upgradeable Tests #### :heavy_check_mark: To run all installability tests ``` -crystal src/cnf-conformance.cr installability -``` -#### (PoC) Test if the install script uses [Helm v3](https://github.com/helm/) -``` -crystal src/cnf-conformance.cr install_script_helm +./cnf-conformance installability ``` + #### :heavy_check_mark: Test if the Helm chart is published ``` -crystal src/cnf-conformance.cr helm_chart_published +./cnf-conformance helm_chart_published ``` #### :heavy_check_mark: Test if the [Helm chart is valid](https://github.com/helm/chart-testing)) ``` -crystal src/cnf-conformance.cr helm_chart_valid +./cnf-conformance helm_chart_valid ``` #### :heavy_check_mark: Test if the Helm deploys +Use a cnf-conformance.yml to manually call helm_deploy, e.g.: +Copy your CNF into the `cnfs` directory: +``` +cp -rf cnfs/ +``` +Now run the test: +``` +./cnf-conformance helm_deploy destructive cnfs//cnf-conformance.yml +``` +#### :heavy_check_mark: Test if the install script uses [Helm v3](https://github.com/helm/) ``` -# Use a cnf-conformance.yml to manually call helm_deploy -# e.g. cp -rf cnfs/ -crystal src/cnf-conformance.cr helm_deploy cnfs//cnf-conformance.yml +./cnf-conformance install_script_helm ``` -#### (To Do) To test if the CNF can perform a [rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/) + +#### :heavy_check_mark: To test if the CNF can perform a [rolling update](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/) ``` -crystal src/cnf-conformance.cr rolling_update +./cnf-conformance rolling_update ``` -## Hardware Resources and Scheduling Tests +--- +### Hardware Resources and Scheduling Tests #### :heavy_check_mark: Run all hardware resources and scheduling tests ``` -crystal src/cnf-conformance.cr hardware_affinity +crystal src/cnf-conformance.cr hardware_and_scheduling + ``` +
Details for Hardware and Scheduling Tests To Do's +

-#### (To Do) Test if the CNF is accessing hardware in its configuration files +#### :memo: (To Do) Test if the CNF is accessing hardware in its configuration files ``` crystal src/cnf-conformance.cr static_accessing_hardware ``` -#### (To Do) Test if the CNF is accessing hardware directly during run-time (e.g. accessing the host /dev or /proc from a mount) +#### :memo: (To Do) Test if the CNF is accessing hardware directly during run-time (e.g. accessing the host /dev or /proc from a mount) ``` crystal src/cnf-conformance.cr dynamic_accessing_hardware ``` -#### (To Do) Test if the CNF is accessing hugepages directly instead of via [Kubernetes resources](https://github.com/cncf/cnf-testbed/blob/c4458634deca5e8ab73adf118eedde32904c8458/examples/use_case/external-packet-filtering-on-k8s-nsm-on-packet/gateway.yaml#L29) +#### :memo: (To Do) Test if the CNF is accessing hugepages directly instead of via [Kubernetes resources](https://github.com/cncf/cnf-testbed/blob/c4458634deca5e8ab73adf118eedde32904c8458/examples/use_case/external-packet-filtering-on-k8s-nsm-on-packet/gateway.yaml#L29) ``` crystal src/cnf-conformance.cr direct_hugepages ``` -#### (To Do) Test if the CNF Testbed performance output shows adequate throughput and sessions using the [CNF Testbed](https://github.com/cncf/cnf-testbed) (vendor neutral) hardware environment +#### :memo: (To Do) Test if the CNF Testbed performance output shows adequate throughput and sessions using the [CNF Testbed](https://github.com/cncf/cnf-testbed) (vendor neutral) hardware environment ``` crystal src/cnf-conformance.cr performance ``` +

+
-## Resilience Tests +--- +### Resilience Tests #### :heavy_check_mark: To run all resilience tests ``` -crystal src/cnf-conformance.cr resilience +./cnf-conformance resilience ``` #### :heavy_check_mark: Test if the CNF crashes when network loss occurs ``` -crystal src/cnf-conformance.cr chaos_network_loss +./cnf-conformance chaos_network_loss ``` #### :heavy_check_mark: Test if the CNF crashes under high CPU load ``` -crystal src/cnf-conformance.cr chaos_cpu_hog +./cnf-conformance chaos_cpu_hog ``` #### :heavy_check_mark: Test if the CNF restarts after container is killed ``` -crystal src/cnf-conformance.cr chaos_container_kill +./cnf-conformance chaos_container_kill +``` +#### :heavy_check_mark: Test if the CNF crashes when network latency occurs +``` +./cnf-conformance pod_network_latency +``` + +#### :heavy_check_mark: Test if the CNF crashes when disk fill occurs +``` +./cnf-conformance disk_fill ``` -## Platform Tests +--- +### Platform Tests #### :heavy_check_mark: Run all platform tests ``` -crystal src/cnf-conformance.cr platform +./cnf-conformance platform ``` #### :heavy_check_mark: Run the K8s conformance tests ``` -crystal src/cnf-conformance.cr k8s_conformance +./cnf-conformance k8s_conformance ``` -#### (PoC) Run All platform resilience tests +#### :heavy_check_mark: Run All platform harware and scheduling tests ``` -crystal src/cnf-conformance.cr platform:resilience poc - +./cnf-conformance platform:hardware_and_scheduling ``` -#### (PoC) Run All platform observability tests +#### :heavy_check_mark: Run runtime compliance test ``` -crystal src/cnf-conformance.cr platform:observability poc - +./cnf-conformance platform:oci_compliant ``` -#### (PoC) Run node failure test **warning** this is a destructive test and will reboot your *host* node! -#### Don't run this unless you have completely separate cluster (e.g. you are not running KIND on a dev box) +#### Proof of Concepts for Platform Tests +##### :bulb: (PoC) Run All platform resilience tests ``` -crystal src/cnf-conformance.cr platform:node_failure poc destructive +./cnf-conformance platform:resilience poc ``` -#### :heavy_check_mark: Run runtime compliance test +##### :bulb: (PoC) Run All platform observability tests ``` -crystal src/cnf-conformance.cr platform:oci_compliant - +./cnf-conformance platform:observability poc ``` +##### :x: :bulb: (PoC) Run node failure test. WARNING this is a destructive test and will reboot your *host* node! +##### Do not run this unless you have completely separate cluster, e.g. development or test cluster. +``` +./cnf-conformance platform:node_failure poc destructive +``` diff --git a/cnf-conformance.example.yml b/cnf-conformance.example.yml index 7cec75d8e..c1a397a20 100644 --- a/cnf-conformance.example.yml +++ b/cnf-conformance.example.yml @@ -1,11 +1,15 @@ --- #helm_directory: coredns # PATH_TO_CNFS_HELM_CHART ; or -helm_chart_repo: stable/coredns # PUBLISHED_CNFS_HELM_CHART_REPO/NAME +helm_chart: stable/coredns + +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable git_clone_url: https://github.com/coredns/coredns.git # GIT_REPO_FOR_CNFS_SOURCE_CODE install_script: cnfs/coredns/Makefile # PATH_TO_CNFS_INSTALL_SCRIPT -release_name: privileged-coredns # DESIRED_HELM_RELEASE_NAME -deployment_name: privileged-coredns-coredns # CNFS_KUBERNETES_DEPLOYMENT_NAME -helm_chart_container_name: privileged-coredns-coredns # POD_SPEC_CONTAINER_NAME -white_list_helm_chart_container_names: [coredns] # [LIST_OF_CONTAINERS_ALLOWED_TO_RUN_PRIVLIDGED] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [coredns] # [LIST_OF_CONTAINERS_ALLOWED_TO_RUN_PRIVLIDGED] diff --git a/spec/fixtures/chaos_container_kill.yml b/embedded_files/chaos_container_kill.yml similarity index 100% rename from spec/fixtures/chaos_container_kill.yml rename to embedded_files/chaos_container_kill.yml diff --git a/spec/fixtures/chaos_cpu_hog.yml b/embedded_files/chaos_cpu_hog.yml similarity index 100% rename from spec/fixtures/chaos_cpu_hog.yml rename to embedded_files/chaos_cpu_hog.yml diff --git a/spec/fixtures/chaos_network_loss.yml b/embedded_files/chaos_network_loss.yml similarity index 100% rename from spec/fixtures/chaos_network_loss.yml rename to embedded_files/chaos_network_loss.yml diff --git a/example-cnfs/coredns/README.md b/example-cnfs/coredns/README.md index b8737fde5..92babef09 100644 --- a/example-cnfs/coredns/README.md +++ b/example-cnfs/coredns/README.md @@ -8,7 +8,7 @@ CoreDNS can listen for DNS requests coming in over UDP/TCP, TLS (RFC 7858), also # Prerequistes -Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#prerequisites), including +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including - Set the KUBECONFIG environment to point to the remote K8s cluster - Downloading the binary cnf-conformance release diff --git a/example-cnfs/coredns/cnf-conformance.yml b/example-cnfs/coredns/cnf-conformance.yml index c859e8576..00c16617a 100644 --- a/example-cnfs/coredns/cnf-conformance.yml +++ b/example-cnfs/coredns/cnf-conformance.yml @@ -1,6 +1,4 @@ --- -helm_directory: cnfs/coredns/helm_chart/coredns -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -11,8 +9,15 @@ application_deployment_names: [coredns-coredns] docker_repository: coredns/coredns helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy, kube-multus] +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy, kube-multus] + +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + diff --git a/example-cnfs/envoy/README.md b/example-cnfs/envoy/README.md index d5ad5a342..ec2075450 100644 --- a/example-cnfs/envoy/README.md +++ b/example-cnfs/envoy/README.md @@ -5,7 +5,7 @@ lie several filters that provide a rich set of features for observing, securing, and routing network traffic to microservices ## Pre-req: -Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#prerequisites), including +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including Set the KUBECONFIG environment to point to the remote K8s cluster ### Automated Envoy installation diff --git a/example-cnfs/envoy/cnf-conformance.yml b/example-cnfs/envoy/cnf-conformance.yml index 14286039e..ee7e919af 100644 --- a/example-cnfs/envoy/cnf-conformance.yml +++ b/example-cnfs/envoy/cnf-conformance.yml @@ -1,5 +1,4 @@ --- -helm_directory: helm_chart git_clone_url: install_script: release_name: envoy @@ -10,8 +9,10 @@ service_name: envoy docker_repository: envoyproxy/envoy helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/envoy helm_chart_container_name: envoy -white_list_helm_chart_container_names: [falco, nginx, envoy, calico-node, kube-proxy, nginx-proxy, node-cache] -rolling_update_tag: v1.12.2 +allowlist_helm_chart_container_names: [falco, nginx, envoy, calico-node, kube-proxy, nginx-proxy, node-cache] +container_names: + - name: envoy + rolling_update_test_tag: 1.8.0 diff --git a/example-cnfs/ip-forwarder/cnf-conformance.yml b/example-cnfs/ip-forwarder/cnf-conformance.yml index 5665e3cbe..88f6686c8 100644 --- a/example-cnfs/ip-forwarder/cnf-conformance.yml +++ b/example-cnfs/ip-forwarder/cnf-conformance.yml @@ -8,7 +8,9 @@ deployment_label: app service_name: "" application_deployment_names: [vpp] docker_repository: soelvkaer/vppcontainer -helm_chart: helm_chart_container_name: vpp-1 -rolling_update_tag: latest -white_list_helm_chart_container_names: [falco, nginx, calico-node, kube-proxy, nginx-proxy, node-cache, kube-multus] +rolling_update_test_tag: latest +allowlist_helm_chart_container_names: [falco, nginx, calico-node, kube-proxy, nginx-proxy, node-cache, kube-multus] +container_names: + - name: ipp_forwarder + rolling_update_test_tag: 1.0.0 diff --git a/example-cnfs/linkerd2/README.md b/example-cnfs/linkerd2/README.md index 76bd6b735..2179cab9c 100644 --- a/example-cnfs/linkerd2/README.md +++ b/example-cnfs/linkerd2/README.md @@ -3,7 +3,7 @@ Linkerd is a service mesh, designed to give platform-wide observability, reliabi ## Pre-req: -Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/master/INSTALL.md#prerequisites), including +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including Set the KUBECONFIG environment to point to the remote K8s cluster ### Automated Envoy installation diff --git a/example-cnfs/linkerd2/cnf-conformance.yml b/example-cnfs/linkerd2/cnf-conformance.yml index 0733f2b26..3d3655a5e 100644 --- a/example-cnfs/linkerd2/cnf-conformance.yml +++ b/example-cnfs/linkerd2/cnf-conformance.yml @@ -1,5 +1,4 @@ --- -helm_directory: helm_chart git_clone_url: install_script: release_name: linkerd @@ -8,5 +7,7 @@ deployment_label: linkerd.io/control-plane-component application_deployment_names: [linkerd2] helm_chart: linkerd/linkerd2 helm_chart_container_name: linkerd2 -white_list_helm_chart_container_names: [falco, nginx, linkerd, calico-node, kube-proxy, nginx-proxy, node-cache] -rolling_update_tag: v18.9.1 +allowlist_helm_chart_container_names: [falco, nginx, linkerd, calico-node, kube-proxy, nginx-proxy, node-cache] +container_names: + - name: linkerd2 + rolling_update_test_tag: 1.0.0 diff --git a/example-cnfs/nsm/.helmignore b/example-cnfs/nsm/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/example-cnfs/nsm/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/example-cnfs/nsm/README.md b/example-cnfs/nsm/README.md new file mode 100644 index 000000000..b3120643e --- /dev/null +++ b/example-cnfs/nsm/README.md @@ -0,0 +1,32 @@ +# What is [NSM](https://https://networkservicemesh.io//) + +Network Service Mesh (NSM) is a novel approach solving complicated L2/L3 use cases in Kubernetes that are tricky to address with the existing Kubernetes Network Model. Inspired by Istio, Network Service Mesh maps the concept of a Service Mesh to L2/L3 payloads as part of an attempt to re-imagine NFV in a Cloud-native way. + +# Prerequistes +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including +- Set the KUBECONFIG environment to point to the remote K8s cluster +- Downloading the binary cnf-conformance release + +### Automated CNF installation + +Initialize the conformance suite +``` +crystal src/cnf-conformance.cr setup +``` + +Configure and deploy NSM as the target CNF +``` +crystal src/cnf-conformance.cr cnf_setup cnf-config=./example-cnfs/nsm/cnf-conformance.yml deploy_with_chart=false +``` + +Run the all the tests +``` +crystal src/cnf-conformance.cr all +``` + +Check the results file + +Cleanup the cnf test setup (including undeployment of NSM) +``` +crystal src/cnf-conformance.cr cnf_cleanup cnf-config=./example-cnfs/nsm/cnf-conformance.yml +``` diff --git a/example-cnfs/nsm/cnf-conformance.yml b/example-cnfs/nsm/cnf-conformance.yml new file mode 100644 index 000000000..11b233b61 --- /dev/null +++ b/example-cnfs/nsm/cnf-conformance.yml @@ -0,0 +1,46 @@ +--- +helm_directory: helm_chart +git_clone_url: +install_script: +release_name: nsm --set insecure=true +service_name: nsm-admission-webhook-svc +docker_repository: conformance/vppagent-forwarder +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +container_names: + - name: nsm + rolling_update_test_tag: 1.0.0 +# allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy, kube-multus] +allowlist_helm_chart_container_names: [] +container_names: + - name: nsm-admission-webhook + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: v0.2.0 + rolling_version_change_test_tag: master + rollback_from_tag: master + - name: prefix-service + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: master + rolling_version_change_test_tag: master + rollback_from_tag: master + - name: vppagent-forwarder + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: v0.2.0 + rolling_version_change_test_tag: master + rollback_from_tag: master + - name: nsmdp + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: v0.2.0 + rolling_version_change_test_tag: master + rollback_from_tag: master + - name: nsmd + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: v0.2.0 + rolling_version_change_test_tag: master + rollback_from_tag: master + - name: nsmd-k8s + rolling_update_test_tag: "master" + rolling_downgrade_test_tag: v0.2.0 + rolling_version_change_test_tag: master + rollback_from_tag: master diff --git a/example-cnfs/nsm/helm_chart/Chart.yaml b/example-cnfs/nsm/helm_chart/Chart.yaml new file mode 100644 index 000000000..eb5c3db3c --- /dev/null +++ b/example-cnfs/nsm/helm_chart/Chart.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +appVersion: "0.2.0" +description: Basic Network Service Mesh Infrastructure +name: nsm +version: 0.2.0 diff --git a/example-cnfs/nsm/helm_chart/charts/admission-webhook/.helmignore b/example-cnfs/nsm/helm_chart/charts/admission-webhook/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/admission-webhook/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/example-cnfs/nsm/helm_chart/charts/admission-webhook/Chart.yaml b/example-cnfs/nsm/helm_chart/charts/admission-webhook/Chart.yaml new file mode 100644 index 000000000..8f665a14d --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/admission-webhook/Chart.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +appVersion: "0.2.0" +description: A Helm chart for Kubernetes +name: admission-webhook +version: 0.2.0 diff --git a/example-cnfs/nsm/helm_chart/charts/admission-webhook/templates/admission-webhook-secret.tpl b/example-cnfs/nsm/helm_chart/charts/admission-webhook/templates/admission-webhook-secret.tpl new file mode 100644 index 000000000..bf9c48228 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/admission-webhook/templates/admission-webhook-secret.tpl @@ -0,0 +1,109 @@ +{{- $ca := genCA "admission-controller-ca" 3650 -}} +{{- $cn := printf "nsm-admission-webhook-svc" -}} +{{- $altName1 := printf "%s.%s" $cn .Release.Namespace }} +{{- $altName2 := printf "%s.%s.svc" $cn .Release.Namespace }} +{{- $cert := genSignedCert $cn nil (list $altName1 $altName2) 3650 $ca -}} + +apiVersion: v1 +kind: Secret +metadata: + name: nsm-admission-webhook-certs + namespace: {{ .Release.Namespace }} +type: Opaque +data: + tls.key: {{ $cert.Key | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nsm-admission-webhook + namespace: {{ .Release.Namespace }} + labels: + app: nsm-admission-webhook +spec: + replicas: 1 + selector: + matchLabels: + app: nsm-admission-webhook + template: + metadata: + labels: + app: nsm-admission-webhook + spec: + containers: + - name: nsm-admission-webhook + image: {{ .Values.registry }}/{{ .Values.org }}/admission-webhook:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + env: + - name: REPO + value: "{{ .Values.org }}" + - name: TAG + value: "{{ .Values.tag }}" + - name: NSM_NAMESPACE + value: "{{ .Values.clientNamespace }}" + - name: TRACER_ENABLED + value: {{ .Values.global.JaegerTracing | default false | quote }} + - name: JAEGER_AGENT_HOST + value: jaeger.nsm-system + - name: JAEGER_AGENT_PORT + value: "6831" + - name: ENFORCE_LIMITS + value: {{ .Values.enforceLimits | quote }} + volumeMounts: + - name: webhook-certs + mountPath: /etc/webhook/certs + readOnly: true + livenessProbe: + httpGet: + path: /liveness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /readiness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + volumes: + - name: webhook-certs + secret: + secretName: nsm-admission-webhook-certs +--- +apiVersion: v1 +kind: Service +metadata: + name: nsm-admission-webhook-svc + namespace: {{ .Release.Namespace }} + labels: + app: nsm-admission-webhook +spec: + ports: + - port: 443 + targetPort: 443 + selector: + app: nsm-admission-webhook +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: nsm-admission-webhook-cfg + namespace: {{ .Release.Namespace }} + labels: + app: nsm-admission-webhook +webhooks: + - name: admission-webhook.networkservicemesh.io + clientConfig: + service: + name: nsm-admission-webhook-svc + namespace: {{ .Release.Namespace }} + path: "/mutate" + caBundle: {{ $ca.Cert | b64enc }} + rules: + - operations: ["CREATE"] + apiGroups: ["apps", "extensions", ""] + apiVersions: ["v1", "v1beta1"] + resources: ["deployments", "services", "pods"] diff --git a/example-cnfs/nsm/helm_chart/charts/admission-webhook/values.yaml b/example-cnfs/nsm/helm_chart/charts/admission-webhook/values.yaml new file mode 100644 index 000000000..db1beadaf --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/admission-webhook/values.yaml @@ -0,0 +1,11 @@ +--- +# Default values for admission-webhook. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +registry: docker.io +org: networkservicemesh +tag: master +pullPolicy: IfNotPresent +clientNamespace: nsm-system +enforceLimits: false diff --git a/example-cnfs/nsm/helm_chart/charts/config/.helmignore b/example-cnfs/nsm/helm_chart/charts/config/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/example-cnfs/nsm/helm_chart/charts/config/Chart.yaml b/example-cnfs/nsm/helm_chart/charts/config/Chart.yaml new file mode 100644 index 000000000..380c41a2c --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/Chart.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: config +version: 0.1.0 diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-admin.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-admin.yaml new file mode 100644 index 000000000..6726ae940 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-admin.yaml @@ -0,0 +1,24 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: nsm-role + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: + - apiGroups: ["networkservicemesh.io"] + resources: + - "networkservices" + - "networkserviceendpoints" + - "networkservicemanagers" + verbs: ["*"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["*"] + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "update"] + - apiGroups: [""] + resources: ["nodes", "services", "namespaces"] + verbs: ["get", "list", "watch"] diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-binding.tpl b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-binding.tpl new file mode 100644 index 000000000..57c155577 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-binding.tpl @@ -0,0 +1,13 @@ +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: nsm-role-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nsm-role +subjects: + - kind: ServiceAccount + name: nsmgr-acc + namespace: {{ .Release.Namespace }} diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-view.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-view.yaml new file mode 100644 index 000000000..88e09aa2d --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/cluster-role-view.yaml @@ -0,0 +1,12 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-network-services-view + labels: + # Add these permissions to the "view" default role. + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: + - apiGroups: ["networkservicemesh.io"] + resources: ["networkservices"] + verbs: ["get", "list", "watch"] diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkserviceendpoints.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkserviceendpoints.yaml new file mode 100644 index 000000000..9855ab87c --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkserviceendpoints.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: networkserviceendpoints.networkservicemesh.io +spec: + conversion: + strategy: None + group: networkservicemesh.io + names: + kind: NetworkServiceEndpoint + listKind: NetworkServiceEndpointList + plural: networkserviceendpoints + shortNames: + - nse + - nses + singular: networkserviceendpoint + scope: Namespaced + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservicemanagers.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservicemanagers.yaml new file mode 100644 index 000000000..b1b181e27 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservicemanagers.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: networkservicemanagers.networkservicemesh.io +spec: + conversion: + strategy: None + group: networkservicemesh.io + names: + kind: NetworkServiceManager + listKind: NetworkServiceManagerList + plural: networkservicemanagers + shortNames: + - nsm + - nsms + singular: networkservicemanager + scope: Namespaced + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservices.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservices.yaml new file mode 100644 index 000000000..3041fd04f --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/crd-networkservices.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: networkservices.networkservicemesh.io +spec: + conversion: + strategy: None + group: networkservicemesh.io + names: + kind: NetworkService + listKind: NetworkServiceList + plural: networkservices + shortNames: + - netsvc + - netsvcs + singular: networkservice + scope: Namespaced + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/example-cnfs/nsm/helm_chart/charts/config/templates/nsm-configmap.yaml b/example-cnfs/nsm/helm_chart/charts/config/templates/nsm-configmap.yaml new file mode 100644 index 000000000..200907e5c --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/templates/nsm-configmap.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: nsm-config +data: + excluded_prefixes.yaml: '' diff --git a/example-cnfs/nsm/helm_chart/charts/config/values.yaml b/example-cnfs/nsm/helm_chart/charts/config/values.yaml new file mode 100644 index 000000000..1ad705363 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/config/values.yaml @@ -0,0 +1,3 @@ +# Default values for config. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. diff --git a/example-cnfs/nsm/helm_chart/charts/prefix-service/.helmignore b/example-cnfs/nsm/helm_chart/charts/prefix-service/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/prefix-service/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/example-cnfs/nsm/helm_chart/charts/prefix-service/Chart.yaml b/example-cnfs/nsm/helm_chart/charts/prefix-service/Chart.yaml new file mode 100644 index 000000000..2e0bb3ddf --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/prefix-service/Chart.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: prefix-service +version: 0.1.0 diff --git a/example-cnfs/nsm/helm_chart/charts/prefix-service/templates/deployment.tpl b/example-cnfs/nsm/helm_chart/charts/prefix-service/templates/deployment.tpl new file mode 100644 index 000000000..43f49587a --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/prefix-service/templates/deployment.tpl @@ -0,0 +1,18 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Chart.Name }} +spec: + selector: + matchLabels: + app: {{ .Chart.Name }} + template: + metadata: + labels: + app: {{ .Chart.Name }} + spec: + serviceAccountName: {{ .Values.serviceAccount.name }} + containers: + - name: {{ .Chart.Name }} + image: {{ .Values.registry }}/{{ .Values.org }}/{{ .Chart.Name }}:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} diff --git a/example-cnfs/nsm/helm_chart/charts/prefix-service/values.yaml b/example-cnfs/nsm/helm_chart/charts/prefix-service/values.yaml new file mode 100644 index 000000000..939e9ff15 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/prefix-service/values.yaml @@ -0,0 +1,13 @@ +--- +# Default values for prefix-service. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# NOTE: the variables might be overriden by helm command line options, see helm.mk +registry: docker.io +org: networkservicemesh +tag: master +pullPolicy: IfNotPresent + +serviceAccount: + name: nsmgr-acc diff --git a/example-cnfs/nsm/helm_chart/charts/spire/.helmignore b/example-cnfs/nsm/helm_chart/charts/spire/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/example-cnfs/nsm/helm_chart/charts/spire/Chart.yaml b/example-cnfs/nsm/helm_chart/charts/spire/Chart.yaml new file mode 100644 index 000000000..f53c879c9 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/Chart.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: spire +version: 0.1.0 diff --git a/example-cnfs/nsm/helm_chart/charts/spire/registration.json b/example-cnfs/nsm/helm_chart/charts/spire/registration.json new file mode 100644 index 000000000..de96aa902 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/registration.json @@ -0,0 +1,64 @@ +{ + "entries": [ + { + "selectors": [ + { + "type": "k8s_sat", + "value": "agent_sa:spire-agent" + } + ], + "spiffe_id": "spiffe://test.com/spire-agent", + "parent_id": "spiffe://test.com/spire/server" + }, + { + "selectors": [ + { + "type": "k8s", + "value": "sa:nsmgr-acc" + } + ], + "spiffe_id": "spiffe://test.com/nsmgr", + "parent_id": "spiffe://test.com/spire-agent" + }, + { + "selectors": [ + { + "type": "k8s", + "value": "sa:nse-acc" + } + ], + "spiffe_id": "spiffe://test.com/nse", + "parent_id": "spiffe://test.com/spire-agent" + }, + { + "selectors": [ + { + "type": "k8s", + "value": "sa:nsc-acc" + } + ], + "spiffe_id": "spiffe://test.com/nsc", + "parent_id": "spiffe://test.com/spire-agent" + }, + { + "selectors": [ + { + "type": "k8s", + "value": "sa:forward-plane-acc" + } + ], + "spiffe_id": "spiffe://test.com/forward-plane", + "parent_id": "spiffe://test.com/spire-agent" + }, + { + "selectors": [ + { + "type": "k8s", + "value": "sa:nsmrs-acc" + } + ], + "spiffe_id": "spiffe://test.com/nsmrs", + "parent_id": "spiffe://test.com/spire-agent" + } + ] +} diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-account.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-account.tpl new file mode 100644 index 000000000..1f38aadae --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-account.tpl @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + namespace: {{ .Values.namespace }} diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-configmap.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-configmap.tpl new file mode 100644 index 000000000..a4f75c385 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-configmap.tpl @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent + namespace: {{ .Values.namespace }} +data: + agent.conf: | + agent { + data_dir = "/run/spire" + log_level = "DEBUG" + server_address = "spire-server" + server_port = "8081" + socket_path = "/run/spire/sockets/agent.sock" + trust_bundle_path = "/run/spire/bundle/bundle.crt" + trust_domain = "test.com" + } + plugins { + NodeAttestor "k8s_sat" { + plugin_data { + # NOTE: Change this to your cluster name + cluster = "kubernetes" + } + } + KeyManager "memory" { + plugin_data { + } + } + WorkloadAttestor "k8s" { + plugin_data { + {{- if .Values.azure }} + kubelet_read_only_port = 10255 + {{- else }} + skip_kubelet_verification = true + {{- end }} + } + } + } diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-daemonset.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-daemonset.tpl new file mode 100644 index 000000000..b246c190e --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/agent-daemonset.tpl @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + namespace: {{ .Values.namespace }} + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + template: + metadata: + namespace: spire + labels: + app: spire-agent + spec: + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: "spire-agent" + initContainers: + - name: init + # This is a small image with wait-for-it, choose whatever image + # you prefer that waits for a service to be up. This image is built + # from https://github.com/lqhl/wait-for-it + image: gcr.io/spiffe-io/wait-for-it + args: ["-t", "30", "spire-server:8081"] + containers: + - name: spire-agent + image: gcr.io/spiffe-io/spire-agent:0.11.0 + args: ["-config", "/run/spire/config/agent.conf"] + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: false + - name: spire-bundle + mountPath: /run/spire/bundle + readOnly: true + livenessProbe: + exec: + command: + - /bin/sh + - -c + - "/opt/spire/bin/spire-agent api fetch -socketPath /run/spire/sockets/agent.sock 2>&1 | grep -vqE 'connection refused|no such file or directory'" + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: spire-bundle + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/registration-configmap.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/registration-configmap.tpl new file mode 100644 index 000000000..c9ada9ae3 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/registration-configmap.tpl @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-entries + namespace: {{ .Values.namespace }} +data: + registration.json: |- +{{ .Files.Get "registration.json" | indent 4}} diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/server-account.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-account.tpl new file mode 100644 index 000000000..6c2d1b578 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-account.tpl @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server + namespace: {{ .Values.namespace }} diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/server-configmap.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-configmap.tpl new file mode 100644 index 000000000..7d078768a --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-configmap.tpl @@ -0,0 +1,69 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-bundle + namespace: {{ .Values.namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server + namespace: {{ .Values.namespace }} +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "8081" + trust_domain = "test.com" + data_dir = "/run/spire/data" + log_level = "DEBUG" + default_svid_ttl = "1h" + registration_uds_path = "/run/spire/sockets/registration.sock" + ca_subject = { + country = ["US"], + organization = ["SPIFFE"], + common_name = "", + } + } + plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/data/datastore.sqlite3" + } + } + NodeAttestor "k8s_sat" { + plugin_data { + clusters = { + # NOTE: Change this to your cluster name + "kubernetes" = { + use_token_review_api_validation = true + service_account_whitelist = ["{{ .Values.namespace }}:spire-agent"] + } + } + } + } + NodeResolver "noop" { + plugin_data {} + } + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + } + {{- if not .Values.selfSignedCA }} + UpstreamAuthority "disk" { + plugin_data { + ttl = "12h" + key_file_path = "/run/spire/secret/bootstrap.key" + cert_file_path = "/run/spire/secret/bootstrap.crt" + } + } + {{- end }} + Notifier "k8sbundle" { + plugin_data { + # This plugin updates the bundle.crt value in the spire:spire-bundle + # ConfigMap by default, so no additional configuration is necessary. + } + } + } diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/server-service.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-service.tpl new file mode 100644 index 000000000..8fae7619e --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-service.tpl @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: spire-server + namespace: {{ .Values.namespace }} +spec: + type: NodePort + ports: + - name: grpc + port: 8081 + targetPort: 8081 + protocol: TCP + selector: + app: spire-server diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/server-statefulset.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-statefulset.tpl new file mode 100644 index 000000000..54a9e8d84 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/server-statefulset.tpl @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: spire-server + namespace: {{ .Values.namespace }} + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + serviceName: spire-server + template: + metadata: + namespace: spire + labels: + app: spire-server + spec: + serviceAccountName: spire-server + shareProcessNamespace: true + containers: + - name: nsm-spire + securityContext: + privileged: true + image: {{ .Values.registry }}/{{ .Values.org }}/nsm-spire:{{ .Values.tag }} + volumeMounts: + - name: spire-server-socket + mountPath: /run/spire/sockets + readOnly: true + - name: spire-entries + mountPath: /run/spire/entries + readOnly: true + + - name: spire-server + image: gcr.io/spiffe-io/spire-server:0.11.0 + args: + - -config + - /run/spire/config/server.conf + ports: + - containerPort: 8081 + volumeMounts: + - name: spire-server-socket + mountPath: /run/spire/sockets + readOnly: false + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-data + mountPath: /run/spire/data + readOnly: false + - name: spire-secret + mountPath: /run/spire/secret + livenessProbe: + tcpSocket: + port: 8081 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + volumes: + - name: spire-server-socket + hostPath: + path: /run/spire/server-sockets + type: DirectoryOrCreate + - name: spire-config + configMap: + name: spire-server + - name: spire-secret + secret: + secretName: spire-secret + - name: spire-entries + configMap: + name: spire-entries + - name: spire-data + hostPath: + path: /var/spire-data + type: DirectoryOrCreate diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-roles.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-roles.tpl new file mode 100644 index 000000000..6f375249f --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-roles.tpl @@ -0,0 +1,49 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-agent-role +rules: + - apiGroups: [""] + resources: ["nodes/proxy"] + verbs: ["get", "watch", "list", "create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-server-role +rules: + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["get", "watch", "list", "create"] + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["spire-bundle"] + verbs: ["get", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace. +kind: ClusterRoleBinding +metadata: + name: spire-agent-binding +subjects: + - kind: ServiceAccount + name: spire-agent + namespace: {{ .Values.namespace }} +roleRef: + kind: ClusterRole + name: spire-agent-role + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace. +kind: ClusterRoleBinding +metadata: + name: spire-server-binding +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Values.namespace }} +roleRef: + kind: ClusterRole + name: spire-server-role + apiGroup: rbac.authorization.k8s.io diff --git a/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-secret.tpl b/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-secret.tpl new file mode 100644 index 000000000..a916ae9b7 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/templates/spire-secret.tpl @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Secret +metadata: + name: spire-secret + namespace: {{ .Values.namespace }} +type: Opaque +data: + bootstrap.key: |- +{{ .Files.Get "key.pem" | b64enc | indent 4 }} + bootstrap.crt: |- +{{ .Files.Get "cert.pem" | b64enc | indent 4 }} diff --git a/example-cnfs/nsm/helm_chart/charts/spire/values.yaml b/example-cnfs/nsm/helm_chart/charts/spire/values.yaml new file mode 100644 index 000000000..0d116e6a6 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/charts/spire/values.yaml @@ -0,0 +1,14 @@ +--- +# Default values for spire. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +registry: docker.io +org: networkservicemesh +tag: master +pullPolicy: IfNotPresent + +# workaround since Azure doesn't support by default 10250 security port for kubelet +azure: false +namespace: spire +selfSignedCA: true diff --git a/example-cnfs/nsm/helm_chart/requirements.yaml b/example-cnfs/nsm/helm_chart/requirements.yaml new file mode 100644 index 000000000..2ff69fa6f --- /dev/null +++ b/example-cnfs/nsm/helm_chart/requirements.yaml @@ -0,0 +1,9 @@ +--- +dependencies: + - name: spire + version: 0.1.0 + condition: spire.enabled + - name: prefix-service + version: 0.1.0 + - name: config + version: 0.1.0 diff --git a/example-cnfs/nsm/helm_chart/templates/forwarding-plane.tpl b/example-cnfs/nsm/helm_chart/templates/forwarding-plane.tpl new file mode 100644 index 000000000..c977fe7cb --- /dev/null +++ b/example-cnfs/nsm/helm_chart/templates/forwarding-plane.tpl @@ -0,0 +1,77 @@ +{{ $fp := .Values.forwardingPlane }} + +apiVersion: apps/v1 +kind: DaemonSet +spec: + selector: + matchLabels: + app: nsm-{{ $fp }}-plane + template: + metadata: + labels: + app: nsm-{{ $fp }}-plane + spec: + hostPID: true + hostNetwork: true + serviceAccount: forward-plane-acc + containers: + - name: {{ (index .Values $fp).image }} + securityContext: + privileged: true + image: {{ .Values.registry }}/{{ .Values.org }}/{{ (index .Values $fp).image }}:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + env: + - name: INSECURE + value: {{ .Values.insecure | default false | quote }} + - name: METRICS_COLLECTOR_ENABLED + value: {{ .Values.metricsCollectorEnabled | default false | quote }} + - name: TRACER_ENABLED + value: {{ .Values.global.JaegerTracing | default false | quote }} + - name: JAEGER_AGENT_HOST + value: jaeger.nsm-system + - name: JAEGER_AGENT_PORT + value: "6831" + - name: NSM_FORWARDER_SRC_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + volumeMounts: + - name: workspace + mountPath: /var/lib/networkservicemesh/ + mountPropagation: Bidirectional + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + livenessProbe: + httpGet: + path: /liveness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /readiness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + {{- if (index .Values $fp).resources }} + resources: + limits: + cpu: {{ (index .Values $fp).resources.limitCPU }} + requests: + cpu: {{ (index .Values $fp).resources.requestsCPU }} + {{- end }} + volumes: + - hostPath: + path: /var/lib/networkservicemesh + type: DirectoryOrCreate + name: workspace + - hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + name: spire-agent-socket +metadata: + name: nsm-{{ $fp }}-forwarder + namespace: {{ .Release.Namespace }} diff --git a/example-cnfs/nsm/helm_chart/templates/nsmgr.tpl b/example-cnfs/nsm/helm_chart/templates/nsmgr.tpl new file mode 100644 index 000000000..6cbc8957a --- /dev/null +++ b/example-cnfs/nsm/helm_chart/templates/nsmgr.tpl @@ -0,0 +1,123 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: nsmgr + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: + app: nsmgr-daemonset + template: + metadata: + labels: + app: nsmgr-daemonset + spec: + serviceAccount: nsmgr-acc + containers: + - name: nsmdp + image: {{ .Values.registry }}/{{ .Values.org }}/nsmdp:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + env: + - name: INSECURE + value: {{ .Values.insecure | default false | quote }} + - name: TRACER_ENABLED + value: {{ .Values.global.JaegerTracing | default false | quote }} + - name: JAEGER_AGENT_HOST + value: jaeger.nsm-system + - name: JAEGER_AGENT_PORT + value: "6831" + - name: PREFERRED_REMOTE_MECHANISM + value: {{ .Values.preferredRemoteMechanism | quote }} + ports: + - containerPort: 5001 + hostPort: 5001 + volumeMounts: + - name: kubelet-socket + mountPath: /var/lib/kubelet/device-plugins + - name: nsm-socket + mountPath: /var/lib/networkservicemesh + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + - name: nsmd + image: {{ .Values.registry }}/{{ .Values.org }}/nsmd:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + env: + - name: INSECURE + value: {{ .Values.insecure | default false | quote }} + - name: TRACER_ENABLED + value: {{ .Values.global.JaegerTracing | default false | quote }} + - name: JAEGER_AGENT_HOST + value: jaeger.nsm-system + - name: JAEGER_AGENT_PORT + value: "6831" + - name: PREFERRED_REMOTE_MECHANISM + value: {{ .Values.preferredRemoteMechanism | quote }} + volumeMounts: + - name: nsm-socket + mountPath: /var/lib/networkservicemesh + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + - name: nsm-config-volume + mountPath: /var/lib/networkservicemesh/config + livenessProbe: + httpGet: + host: "127.0.0.1" + path: /liveness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + readinessProbe: + httpGet: + host: "127.0.0.1" + path: /readiness + port: 5555 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + - name: nsmd-k8s + image: {{ .Values.registry }}/{{ .Values.org }}/nsmd-k8s:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + volumeMounts: + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + env: + - name: INSECURE + value: {{ .Values.insecure | default false | quote }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: TRACER_ENABLED + value: {{ .Values.global.JaegerTracing | default false | quote }} + - name: JAEGER_AGENT_HOST + value: jaeger.nsm-system + - name: JAEGER_AGENT_PORT + value: "6831" + volumes: + - hostPath: + path: /var/lib/kubelet/device-plugins + type: DirectoryOrCreate + name: kubelet-socket + - hostPath: + path: /var/lib/networkservicemesh + type: DirectoryOrCreate + name: nsm-socket + - name: nsm-config-volume + configMap: + name: nsm-config + - hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + name: spire-agent-socket diff --git a/example-cnfs/nsm/helm_chart/templates/service-accounts.tpl b/example-cnfs/nsm/helm_chart/templates/service-accounts.tpl new file mode 100644 index 000000000..9881506d5 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/templates/service-accounts.tpl @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nse-acc + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nsc-acc + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nsmgr-acc + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: forward-plane-acc + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/example-cnfs/nsm/helm_chart/values.yaml b/example-cnfs/nsm/helm_chart/values.yaml new file mode 100644 index 000000000..a3964cc18 --- /dev/null +++ b/example-cnfs/nsm/helm_chart/values.yaml @@ -0,0 +1,44 @@ +--- +# Default values for nsm. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +registry: docker.io +org: conformance +# org: networkservicemesh +tag: master +pullPolicy: IfNotPresent + +forwardingPlane: vpp +insecure: false +preferredRemoteMechanism: +networkservice: icmp-responder +prometheus: false + +admission-webhook: + org: conformance + # org: networkservicemesh + tag: master + +prefix-service: + org: conformance + # org: networkservicemesh + tag: master + +vpp: + image: vppagent-forwarder + +kernel: + image: kernel-forwarder + resources: + limitCPU: 1 + requestsCPU: 1m + +spire: + enabled: false + +global: + # set to true to enable Jaeger tracing for NSM components + JaegerTracing: false + +metricsCollectorEnabled: false diff --git a/example-cnfs/pantheon-nsm-nat/README.md b/example-cnfs/pantheon-nsm-nat/README.md new file mode 100644 index 000000000..795de1518 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/README.md @@ -0,0 +1,43 @@ +# What is [Pantheon NSM NAT](https://github.com/PANTHEONtech/cnf-examples/tree/master/nsm/LFNWebinar) + +In this simple example we demonstrate the capabilities of the NSM agent - a control-plane for Cloud-native Network Functions deployed in Kubernetes cluster. The NSM agent seamlessly integrates Ligato framework for Linux and VPP network configuration management together with Network Service Mesh (NSM) for separation of data plane from control plane connectivity between containers and external endpoints. + +In the presented use-case we simulate scenario in which a client from a local network needs to access a web server with a public IP address. The necessary Network Address Translation (NAT) is performed in-between the client and the web server by the high-performance VPP NAT plugin, deployed as a true CNF (Cloud-Native Network Functions) inside a container. For simplicity the client is represented by a K8s Pod running image with cURL installed (as opposed to being an external endpoint as it would be in a real-world scenario). For the server side the minimalistic TestHTTPServer implemented in VPP is utilized. + +In all the three Pods an instance of NSM Agent is run to communicate with the NSM manager via NSM SDK and negotiate additional network connections to connect the pods into a chain client <-> NAT-CNF <-> web-server (see diagrams below). The agents then use the features of Ligato framework to further configure Linux and VPP networking around the additional interfaces provided by NSM (e.g. routes, NAT). + +The configuration to apply is described declaratively and submitted to NSM agents in a Kubernetes native way through our own Custom Resource called CNFConfiguration. The controller for this CRD (installed by cnf-crd.yaml) simply reflects the content of applied CRD instances into an etcd datastore from which it is read by NSM agents. For example, the configuration for the NSM agent managing the central NAT CNF can be found in cnf-nat44.yaml. + +More information about cloud-native tools and network functions provided by PANTHEON.tech can be found on our website cdnf.io. + +# Prerequistes +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including +- Set the KUBECONFIG environment to point to the remote K8s cluster +- Downloading the binary cnf-conformance release + +### Automated CNF installation + +Initialize the conformance suite +``` +crystal src/cnf-conformance.cr setup +``` + +Configure and deploy nsm and nsm-nat as the target CNF +``` +crystal src/cnf-conformance.cr cnf_setup cnf-config=./example-cnfs/nsm/cnf-conformance.yml deploy_with_chart=false + +crystal src/cnf-conformance.cr cnf_setup cnf-config=./example-cnfs/pantheon-nsm-nat/cnf-conformance.yml deploy_with_chart=false +``` + +Run the all the tests +``` +crystal src/cnf-conformance.cr all +``` + +Check the results file + +Cleanup the cnf test setup (including undeployment of nsm-nat) +``` +crystal src/cnf-conformance.cr cnf_cleanup cnf-config=./example-cnfs/pantheon-nsm-nat/cnf-conformance.yml +crystal src/cnf-conformance.cr cnf_cleanup cnf-config=./example-cnfs/nsm/cnf-conformance.yml +``` diff --git a/example-cnfs/pantheon-nsm-nat/cnf-conformance.yml b/example-cnfs/pantheon-nsm-nat/cnf-conformance.yml new file mode 100644 index 000000000..52c3f72b3 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/cnf-conformance.yml @@ -0,0 +1,15 @@ +--- +helm_directory: nat-cnf +git_clone_url: +install_script: +release_name: cnf-nat +deployment_name: cnf-nat44 +deployment_label: cnf-nat44 +service_name: +application_deployment_names: [cnf-nat44] +docker_repository: pantheontech/nsm-agent-vpp:v3.1.0 +helm_chart_container_name: cnf-nat44 +container_names: + - name: pantheon + rolling_update_test_tag: 1.0.0 +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy, kube-multus] diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/Chart.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/Chart.yaml new file mode 100644 index 000000000..b7dfd43e7 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/Chart.yaml @@ -0,0 +1,4 @@ +--- +description: Pantheon CNF chaining using Ligato and NSM +name: nat-cnf +version: 0.0.1 diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/README.md b/example-cnfs/pantheon-nsm-nat/nat-cnf/README.md new file mode 100644 index 000000000..15640e099 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/README.md @@ -0,0 +1,31 @@ +# What is [NAT-CNF](https://github.com/PANTHEONtech/cnf-examples/tree/master/nsm/LFNWebinar) +* See the ../README.md for the workload defintion of this CNF. NSM should be installed before this CNF is installed +# Prerequistes + +Follow [Pre-req steps](https://github.com/cncf/cnf-conformance/blob/main/INSTALL.md#prerequisites), including +- Set the KUBECONFIG environment to point to the remote K8s cluster +- Downloading the binary cnf-conformance release + +### Automated CNF installation + +Initialize the conformance suite +``` +crystal src/cnf-conformance.cr setup +``` + +Configure and deploy nsm-nat as the target CNF +``` +crystal src/cnf-conformance.cr cnf_setup cnf-config=./example-cnfs/pantheon-nsm-nat/cnf-conformance.yml deploy_with_chart=false +``` + +Run the all the tests +``` +crystal src/cnf-conformance.cr all +``` + +Check the results file + +Cleanup the cnf test setup (including undeployment of nsm-nat) +``` +crystal src/cnf-conformance.cr cnf_cleanup cnf-config=./example-cnfs/pantheon-nsm-nat/cnf-conformance.yml +``` diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/client.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/client.yaml new file mode 100644 index 000000000..ece44bdaa --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/client.yaml @@ -0,0 +1,59 @@ +--- +# DHCP configuration +apiVersion: pantheon.tech/v1 +kind: CNFConfiguration +metadata: + name: client +spec: + microservice: client + configItems: + - module: cnf.nsm + version: v1 + type: client + data: |- + name: access-to-cnf-network + network_service: cnf-nat-example + outgoing_labels: + - key: app + value: client + interface_name: tap0 + interface_type: KERNEL_INTERFACE + ipAddresses: + - "192.168.100.10/24" + - module: linux.l3 + type: route + data: |- + outgoing_interface: tap0 + scope: GLOBAL + dst_network: 80.80.80.0/24 + gw_addr: 192.168.100.1 + +--- +apiVersion: v1 +kind: Pod +metadata: + name: client + labels: + cnf: client +spec: + containers: + - name: client + image: pantheontech/nsm-agent-linux:v3.1.0 + imagePullPolicy: IfNotPresent + securityContext: + privileged: true + env: + - name: ETCD_CONFIG + value: "/etc/etcd/etcd.conf" + - name: MICROSERVICE_LABEL + value: "client" + resources: + limits: + networkservicemesh.io/socket: 1 + volumeMounts: + - name: etcd-cfg + mountPath: /etc/etcd + volumes: + - name: etcd-cfg + configMap: + name: cnf-etcd-cfg diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-crd.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-crd.yaml new file mode 100644 index 000000000..eb4d2afc0 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-crd.yaml @@ -0,0 +1,143 @@ +--- +# This cluster role defines a set of permissions required for cnf-crd. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: cnf-crd + namespace: default +rules: + - apiGroups: + - apiextensions.k8s.io + - pantheon.tech + resources: + - customresourcedefinitions + - cnfconfigurations + verbs: + - "*" + +--- +# This defines a service account for cnf-crd. +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cnf-crd + namespace: default + +--- +# This binds the cnf-crd cluster role with cnf-crd service account. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: cnf-crd +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cnf-crd +subjects: + - kind: ServiceAccount + name: cnf-crd + namespace: default + +--- +apiVersion: v1 +kind: Pod +metadata: + name: cnf-crd + namespace: default + labels: + app: cnf-crd +spec: + serviceAccountName: cnf-crd + initContainers: + # This init container waits until etcd is started + - name: wait-foretcd + image: busybox:1.29.3 + imagePullPolicy: IfNotPresent + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + command: + - /bin/sh + args: + - -c + - | + until nc -w 2 $HOST_IP:31379; do echo waiting for etcd; sleep 2; done; + containers: + - name: cnf-crd + image: pantheontech/cnf-crd:latest + imagePullPolicy: IfNotPresent + env: + - name: ETCD_CONFIG + value: "/etc/etcd/etcd.conf" + volumeMounts: + - name: etcd-cfg + mountPath: /etc/etcd + volumes: + - name: etcd-cfg + configMap: + name: cnf-etcd-cfg + +--- +# etcd config used by CNFs deployed in the host network namespace +apiVersion: v1 +kind: ConfigMap +metadata: + name: cnf-etcd-cfg-for-nodeport +data: + etcd.conf: | + dial-timeout: 10000000000 + allow-delayed-start: true + insecure-transport: true + endpoints: + - "__HOST_IP__:31379" + +--- +# etcd config used by CNF with their own network namespace +apiVersion: v1 +kind: ConfigMap +metadata: + name: cnf-etcd-cfg +data: + etcd.conf: | + dial-timeout: 10000000000 + allow-delayed-start: true + insecure-transport: true + endpoints: + - "cnf-etcd.default.svc.cluster.local:12379" + +--- +apiVersion: v1 +kind: Service +metadata: + name: cnf-etcd +spec: + type: NodePort + selector: + app: cnf-etcd + ports: + - port: 12379 + nodePort: 31379 # 32379 is used by contiv-etcd + +--- +apiVersion: v1 +kind: Pod +metadata: + name: cnf-etcd + labels: + app: cnf-etcd +spec: + containers: + - name: cnf-etcd + image: quay.io/coreos/etcd:v3.3.11 + imagePullPolicy: IfNotPresent + env: + - name: ETCDCTL_API + value: "3" + command: + - /bin/sh + args: + - -c + - /usr/local/bin/etcd --name=cnf-etcd --data-dir=/var/cnf-etcd/data + --advertise-client-urls=http://0.0.0.0:12379 --listen-client-urls=http://0.0.0.0:12379 --listen-peer-urls=http://0.0.0.0:12380 \ No newline at end of file diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-nat44.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-nat44.yaml new file mode 100644 index 000000000..eec742b84 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/cnf-nat44.yaml @@ -0,0 +1,105 @@ +--- +# NAT44 configuration +apiVersion: pantheon.tech/v1 +kind: CNFConfiguration +metadata: + name: cnf-nat44 +spec: + microservice: cnf-nat44 + configItems: + - module: cnf.nsm + version: v1 + type: endpoint + data: |- + network_service: cnf-nat-example + advertised_labels: + - key: app + value: nat44 + interface_name_prefix: memif # full name: memif0 + interface_type: MEM_INTERFACE + single_client: true + ipAddresses: + - "192.168.100.1/24" + + - module: cnf.nsm + version: v1 + type: client + data: |- + name: access-to-external-network + network_service: cnf-nat-example + outgoing_labels: + - key: app + value: nat44 + interface_name: memif1 + interface_type: MEM_INTERFACE + ipAddresses: + - "80.80.80.100/24" + + - module: vpp.nat + type: nat44-interface + data: |- + name: memif1 + nat_outside: true + output_feature: true + + - module: vpp.nat + type: nat44-interface + data: |- + name: memif0 + nat_inside: true + + - module: vpp.nat + type: nat44-pool + data: |- + first_ip: 80.80.80.100 + last_ip: 80.80.80.105 + +--- +# CNF-NAT44 pod definition +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cnf-nat44 + labels: + cnf: cnf-nat44 +spec: + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + cnf: "cnf-nat44" + template: + metadata: + labels: + cnf: "cnf-nat44" + spec: + containers: + - name: cnf-nat44 + image: pantheontech/nsm-agent-vpp:v3.1.0 + imagePullPolicy: IfNotPresent + securityContext: + privileged: true + ports: + - containerPort: 9191 + name: http + env: + - name: ETCD_CONFIG + value: "/etc/etcd/etcd.conf" + - name: MICROSERVICE_LABEL + value: "cnf-nat44" + - name: ETCD_EXPAND_ENV_VARS + value: "true" + resources: + limits: + networkservicemesh.io/socket: 1 + volumeMounts: + - name: etcd-cfg + mountPath: /etc/etcd + volumes: + - name: etcd-cfg + configMap: + name: cnf-etcd-cfg diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/network-service.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/network-service.yaml new file mode 100644 index 000000000..42d66fe48 --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/network-service.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: networkservicemesh.io/v1alpha1 +kind: NetworkService +metadata: + name: cnf-nat-example +spec: + payload: IP + matches: + # connect client to the (local side of) cnf-nat44 + - match: + sourceSelector: + app: client + route: + - destination: + destinationSelector: + app: nat44 + # connect the (external side of) cnf-nat44 to the webserver + - match: + sourceSelector: + app: nat44 + route: + - destination: + destinationSelector: + app: webserver \ No newline at end of file diff --git a/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/webserver.yaml b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/webserver.yaml new file mode 100644 index 000000000..602622a5d --- /dev/null +++ b/example-cnfs/pantheon-nsm-nat/nat-cnf/templates/webserver.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: pantheon.tech/v1 +kind: CNFConfiguration +metadata: + name: webserver +spec: + microservice: webserver + configItems: + - module: cnf.nsm + version: v1 + type: endpoint + data: |- + network_service: cnf-nat-example + advertised_labels: + - key: app + value: webserver + interface_name_prefix: memif # full name: memif0 + interface_type: MEM_INTERFACE + single_client: true + ipAddresses: + - "80.80.80.80/24" + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: vpp-startup-cfg +data: + vpp.conf: | + unix { + nodaemon + cli-listen /run/vpp/cli.sock + cli-no-pager + log /tmp/vpp.log + coredump-size unlimited + full-coredump + poll-sleep-usec 50 + startup-config /etc/vpp/cli-config.txt + } + plugins { + plugin dpdk_plugin.so { + disable + } + } + api-trace { + on + } + socksvr { + default + } + statseg { + default + per-node-counters on + } + nat { + endpoint-dependent + translation hash buckets 1048576 + translation hash memory 268435456 + user hash buckets 1024 + max translations per user 10000 + } + cli-config.txt: | + comment { start HTTP server } + test http server + +--- +apiVersion: v1 +kind: Pod +metadata: + name: webserver + labels: + app: webserver +spec: + containers: + - name: webserver + image: pantheontech/nsm-agent-vpp:v3.1.0 + env: + - name: ETCD_CONFIG + value: "/etc/etcd/etcd.conf" + - name: MICROSERVICE_LABEL + value: "webserver" + resources: + limits: + networkservicemesh.io/socket: 1 + volumeMounts: + - name: etcd-cfg + mountPath: /etc/etcd + - name: vpp-startup-cfg + mountPath: /etc/vpp + volumes: + - name: etcd-cfg + configMap: + name: cnf-etcd-cfg + - name: vpp-startup-cfg + configMap: + name: vpp-startup-cfg diff --git a/example-cnfs/vpp-3c2n-csp-use-case/cnf-conformance.yml b/example-cnfs/vpp-3c2n-csp-use-case/cnf-conformance.yml index accbc88ce..eb1faab68 100644 --- a/example-cnfs/vpp-3c2n-csp-use-case/cnf-conformance.yml +++ b/example-cnfs/vpp-3c2n-csp-use-case/cnf-conformance.yml @@ -6,7 +6,8 @@ release_name: ip-forwarder-csp deployment_name: ip-forwarder-csp deployment_label: app application_deployment_names: [ip-forwarder-csp] -helm_chart: helm_chart_container_name: ip-forwarder-csp -white_list_helm_chart_container_names: [falco, nginx, calico-node, kube-proxy, nginx-proxy, node-cache] -rolling_update_tag: latest +allowlist_helm_chart_container_names: [falco, nginx, calico-node, kube-proxy, nginx-proxy, node-cache] +container_names: + - name: csp + rolling_update_test_tag: 1.0.0 diff --git a/points-all.yml b/points-all.yml index 8e67cc224..aaa39be1c 100644 --- a/points-all.yml +++ b/points-all.yml @@ -3,6 +3,7 @@ tags: pass: 5 fail: -1 + skipped: 0 - name: reasonable_image_size tags: microservice, dynamic @@ -22,6 +23,8 @@ tags: statelessness, dynamic, configuration_lifecycle - name: check_reaped tags: statelessness, dynamic, configuration_lifecycle +- name: volume_hostpath_not_found + tags: statelessness, dynamic - name: privileged tags: security, dynamic @@ -60,6 +63,10 @@ tags: configuration_lifecycle, dynamic - name: rolling_update tags: configuration_lifecycle, dynamic +- name: rolling_downgrade + tags: configuration_lifecycle, dynamic +- name: rolling_version_change + tags: configuration_lifecycle, dynamic - name: nodeport_not_used tags: configuration_lifecycle, dynamic - name: hardcoded_ip_addresses_in_k8s_runtime_configuration @@ -85,7 +92,7 @@ - name: helm_chart_published tags: installability, dynamic -- name: hardware_affinity +- name: hardware_and_scheduling tags: hardware, dynamic - name: static_accessing_hardware tags: hardware, static diff --git a/points.yml b/points.yml index 51b5217f9..d18d97fdc 100644 --- a/points.yml +++ b/points.yml @@ -3,6 +3,7 @@ tags: pass: 5 fail: -1 + skipped: 0 - name: reasonable_image_size tags: microservice, dynamic, workload @@ -45,6 +46,10 @@ # tags: scalability, dynamic, workload - name: network_chaos tags: scalability, dynamic, workload +- name: pod_network_latency + tags: scalability, dynamic, workload +- name: disk_fill + tags: scalability, dynamic, workload #- name: external_retry # tags: scalability, dynamic, workload @@ -62,10 +67,24 @@ # tags: configuration_lifecycle, dynamic - name: rolling_update tags: configuration_lifecycle, dynamic, workload +- name: rolling_downgrade + tags: configuration_lifecycle, dynamic, workload +- name: rolling_version_change + tags: configuration_lifecycle, dynamic, workload +- name: rollback + tags: configuration_lifecycle, dynamic, workload - name: nodeport_not_used tags: configuration_lifecycle, dynamic, workload - name: hardcoded_ip_addresses_in_k8s_runtime_configuration tags: configuration_lifecycle, dynamic, workload +- name: secrets_used + tags: configuration_lifecycle, dynamic, workload + pass: 5 + fail: 0 +- name: immutable_configmap + tags: configuration_lifecycle, dynamic, workload + pass: 1 + fail: 0 #- name: fluentd_traffic # tags: observability, dynamic, workload @@ -96,7 +115,9 @@ - name: volume_hostpath_not_found tags: statelessness, dynamic, workload -#- name: hardware_affinity +- name: no_local_volume_configuration + tags: statelessness, dynamic, workload +#- name: hardware_and_scheduling # tags: hardware, dynamic, workload #- name: static_accessing_hardware # tags: hardware, static, workload diff --git a/sample-cnfs/k8s-multiple-deployments/README.md b/sample-cnfs/k8s-multiple-deployments/README.md new file mode 100644 index 000000000..135b9d97f --- /dev/null +++ b/sample-cnfs/k8s-multiple-deployments/README.md @@ -0,0 +1,2 @@ +# k8s-sidecar-container-pattern +Example project for How to implement sidecar pattern diff --git a/sample-cnfs/k8s-multiple-deployments/chart/Chart.yaml b/sample-cnfs/k8s-multiple-deployments/chart/Chart.yaml new file mode 100755 index 000000000..16a292612 --- /dev/null +++ b/sample-cnfs/k8s-multiple-deployments/chart/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: K8s Sidecar example + Services +home: +icon: +keywords: +- sidecar +maintainers: +- email: + name: bbachi +name: k8s-sidecar-container-pattern +sources: +- https://github.com/bbachi/k8s-sidecar-container-pattern +version: 1.10.0 diff --git a/sample-cnfs/k8s-multiple-deployments/chart/templates/manifest.yml b/sample-cnfs/k8s-multiple-deployments/chart/templates/manifest.yml new file mode 100644 index 000000000..910f04685 --- /dev/null +++ b/sample-cnfs/k8s-multiple-deployments/chart/templates/manifest.yml @@ -0,0 +1,200 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: nginx-webapp + name: nginx-webapp +spec: + replicas: 5 + selector: + matchLabels: + app: nginx-webapp + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: nginx-webapp + spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 1' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container1 + resources: {} + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 2' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container2 + resources: {} + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: nginx + name: main-container + resources: {} + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + - containerPort: 80 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} +status: {} + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: nginx-webapp-deployment2 + name: nginx-webapp-deployment2 +spec: + replicas: 2 + selector: + matchLabels: + app: nginx-webapp-deployment2 + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: nginx-webapp-deployment2 + spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 1' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container3 + resources: {} + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 2' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container4 + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + - image: nginx + name: main-container2 + resources: {} + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - touch + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} +status: {} + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nginx-webapp-deployment2 + labels: + run: nginx-webapp-deployment2 +spec: + ports: + - port: 80 + protocol: TCP + selector: + app: nginx-webapp-deployment2 + type: NodePort diff --git a/sample-cnfs/k8s-multiple-deployments/chart/values.yaml b/sample-cnfs/k8s-multiple-deployments/chart/values.yaml new file mode 100755 index 000000000..af59ed3aa --- /dev/null +++ b/sample-cnfs/k8s-multiple-deployments/chart/values.yaml @@ -0,0 +1,7 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: busybox + tag: "latest" diff --git a/sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml b/sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml new file mode 100644 index 000000000..696f08893 --- /dev/null +++ b/sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml @@ -0,0 +1,46 @@ +--- +helm_directory: chart +git_clone_url: +install_script: +release_name: sidecar-container-demo +deployment_name: nginx-webapp-deployment2 +deployment_label: app +service_name: +application_deployment_names: [nginx-webapp] +docker_repository: coredns/coredns +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +helm_chart_container_name: busybox +container_names: + - name: sidecar-container1 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: sidecar-container2 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: sidecar-container3 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: sidecar-container4 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: main-container + rolling_update_test_tag: "1.16.1" + rolling_downgrade_test_tag: "1.16" + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: main-container2 + rolling_update_test_tag: "1.16.1" + rolling_downgrade_test_tag: "1.16" + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/k8s-non-helm/README.md b/sample-cnfs/k8s-non-helm/README.md new file mode 100644 index 000000000..135b9d97f --- /dev/null +++ b/sample-cnfs/k8s-non-helm/README.md @@ -0,0 +1,2 @@ +# k8s-sidecar-container-pattern +Example project for How to implement sidecar pattern diff --git a/sample-cnfs/k8s-non-helm/cnf-conformance.yml b/sample-cnfs/k8s-non-helm/cnf-conformance.yml new file mode 100644 index 000000000..93b878eec --- /dev/null +++ b/sample-cnfs/k8s-non-helm/cnf-conformance.yml @@ -0,0 +1,31 @@ +--- +manifest_directory: manifests +git_clone_url: +install_script: +release_name: nginx-webapp +deployment_name: nginx-webapp +deployment_label: app +service_name: +application_deployment_names: [nginx-webapp] +docker_repository: +helm_repository: + name: + repo_url: +helm_chart_container_name: +container_names: + - name: sidecar-container1 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: sidecar-container2 + rolling_update_test_tag: "1.32.0" + rolling_downgrade_test_tag: 1.32.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: main-container + rolling_update_test_tag: "1.16.0" + rolling_downgrade_test_tag: 1.16.0 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/k8s-non-helm/manifests/manifest.yml b/sample-cnfs/k8s-non-helm/manifests/manifest.yml new file mode 100644 index 000000000..df2645760 --- /dev/null +++ b/sample-cnfs/k8s-non-helm/manifests/manifest.yml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: nginx-webapp + name: nginx-webapp +spec: + replicas: 5 + selector: + matchLabels: + app: nginx-webapp + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: nginx-webapp + spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 1' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container1 + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 2' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container2 + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: nginx + name: main-container + resources: {} + ports: + - containerPort: 80 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} +status: {} + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nginx-webapp + labels: + run: nginx-webapp +spec: + ports: + - port: 80 + protocol: TCP + selector: + app: nginx-webapp + type: NodePort diff --git a/sample-cnfs/k8s-non-helm/manifests/pod.yml b/sample-cnfs/k8s-non-helm/manifests/pod.yml new file mode 100644 index 000000000..b52113095 --- /dev/null +++ b/sample-cnfs/k8s-non-helm/manifests/pod.yml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: sidecar-container-demo +spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: nginx + name: main-container + resources: {} + ports: + - containerPort: 80 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} \ No newline at end of file diff --git a/sample-cnfs/k8s-sidecar-container-pattern/README.md b/sample-cnfs/k8s-sidecar-container-pattern/README.md new file mode 100644 index 000000000..135b9d97f --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/README.md @@ -0,0 +1,2 @@ +# k8s-sidecar-container-pattern +Example project for How to implement sidecar pattern diff --git a/sample-cnfs/k8s-sidecar-container-pattern/chart/Chart.yaml b/sample-cnfs/k8s-sidecar-container-pattern/chart/Chart.yaml new file mode 100755 index 000000000..16a292612 --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/chart/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: K8s Sidecar example + Services +home: +icon: +keywords: +- sidecar +maintainers: +- email: + name: bbachi +name: k8s-sidecar-container-pattern +sources: +- https://github.com/bbachi/k8s-sidecar-container-pattern +version: 1.10.0 diff --git a/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/manifest.yml b/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/manifest.yml new file mode 100644 index 000000000..df2645760 --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/manifest.yml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: nginx-webapp + name: nginx-webapp +spec: + replicas: 5 + selector: + matchLabels: + app: nginx-webapp + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: nginx-webapp + spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 1' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container1 + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 2' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container2 + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: nginx + name: main-container + resources: {} + ports: + - containerPort: 80 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} +status: {} + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nginx-webapp + labels: + run: nginx-webapp +spec: + ports: + - port: 80 + protocol: TCP + selector: + app: nginx-webapp + type: NodePort diff --git a/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/pod.yml b/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/pod.yml new file mode 100644 index 000000000..b52113095 --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/chart/templates/pod.yml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: sidecar-container-demo +spec: + containers: + - image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container' >> /var/log/index.html; sleep 5;done"] + name: sidecar-container + resources: {} + volumeMounts: + - name: var-logs + mountPath: /var/log + - image: nginx + name: main-container + resources: {} + ports: + - containerPort: 80 + volumeMounts: + - name: var-logs + mountPath: /usr/share/nginx/html + dnsPolicy: Default + volumes: + - name: var-logs + emptyDir: {} \ No newline at end of file diff --git a/sample-cnfs/k8s-sidecar-container-pattern/chart/values.yaml b/sample-cnfs/k8s-sidecar-container-pattern/chart/values.yaml new file mode 100755 index 000000000..af59ed3aa --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/chart/values.yaml @@ -0,0 +1,7 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: busybox + tag: "latest" diff --git a/sample-cnfs/k8s-sidecar-container-pattern/cnf-conformance.yml b/sample-cnfs/k8s-sidecar-container-pattern/cnf-conformance.yml new file mode 100644 index 000000000..ba1c33ada --- /dev/null +++ b/sample-cnfs/k8s-sidecar-container-pattern/cnf-conformance.yml @@ -0,0 +1,23 @@ +--- +helm_directory: chart +git_clone_url: +install_script: +release_name: sidecar-container-demo +deployment_name: nginx-webapp +deployment_label: app +service_name: +application_deployment_names: [nginx-webapp] +docker_repository: coredns/coredns +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +helm_chart_container_name: busybox +rolling_update_test_tag: 1.6.7 +container_names: + - name: sidecar-container1 + rolling_update_test_tag: "1.32.0" + - name: sidecar-container2 + rolling_update_test_tag: "1.32.0" + - name: main-container + rolling_update_test_tag: "1.16.0" +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml b/sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml index 39cb20064..b943c521b 100644 --- a/sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml +++ b/sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml @@ -1,6 +1,5 @@ --- helm_directory: cnfs/coredns/helm_chart/coredns -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -11,7 +10,8 @@ application_deployment_names: [coredns-coredns] helm_repository: name: stable repo_url: https://bad-helm-repo.googleapis.com -helm_chart: helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-bad-helm-repo/cnf-conformance.yml b/sample-cnfs/sample-bad-helm-repo/cnf-conformance.yml index ab42ccc3f..0713fc316 100644 --- a/sample-cnfs/sample-bad-helm-repo/cnf-conformance.yml +++ b/sample-cnfs/sample-bad-helm-repo/cnf-conformance.yml @@ -1,6 +1,4 @@ --- -helm_directory: cnfs/coredns/helm_chart/coredns -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -13,5 +11,7 @@ helm_repository: repo_url: https://bad-helm-repo.googleapis.com helm_chart: badrepo/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-bad_helm_coredns-cnf/cnf-conformance.yml b/sample-cnfs/sample-bad_helm_coredns-cnf/cnf-conformance.yml index 3e8c66b55..a96a36c74 100644 --- a/sample-cnfs/sample-bad_helm_coredns-cnf/cnf-conformance.yml +++ b/sample-cnfs/sample-bad_helm_coredns-cnf/cnf-conformance.yml @@ -7,6 +7,8 @@ deployment_name: bad-helm-coredns-coredns deployment_label: k8s-app service_name: bad-helm-coredns-coredns application_deployment_names: [bad-helm-coredns] -helm_chart: stable/coredns helm_chart_container_name: coredns -white_list_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +allowlist_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/sample-cnfs/sample-coredns-cnf-bad-chart/cnf-conformance.yml b/sample-cnfs/sample-coredns-cnf-bad-chart/cnf-conformance.yml index 49a6a38ae..7d557d27b 100644 --- a/sample-cnfs/sample-coredns-cnf-bad-chart/cnf-conformance.yml +++ b/sample-cnfs/sample-coredns-cnf-bad-chart/cnf-conformance.yml @@ -1,6 +1,4 @@ --- -helm_directory: cnfs/coredns/helm_chart/coredns -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -11,8 +9,10 @@ application_deployment_names: [coredns-coredns] docker_repository: coredns/coredns helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/corsdsdsdedns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml b/sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml index b0398f03d..78797adc1 100644 --- a/sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml +++ b/sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml @@ -1,6 +1,4 @@ --- -helm_directory: helm_chart/coredns -# helm_directory: helm_chart git_clone_url: https://github.com/coredns/coredns.git install_script: coredns/Makefile release_name: coredns @@ -10,4 +8,7 @@ service_name: coredns-coredns application_deployment_names: [coredns-coredns] helm_chart: stable/coredns helm_chart_container_name: coredns -white_list_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +allowlist_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/sample-cnfs/sample-coredns-cnf/cnf-conformance.yml b/sample-cnfs/sample-coredns-cnf/cnf-conformance.yml index 967893167..8daaeba51 100644 --- a/sample-cnfs/sample-coredns-cnf/cnf-conformance.yml +++ b/sample-cnfs/sample-coredns-cnf/cnf-conformance.yml @@ -1,5 +1,4 @@ --- -helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -10,8 +9,13 @@ application_deployment_names: [coredns-coredns] docker_repository: coredns/coredns helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-fragile-state/cnf-conformance.yml b/sample-cnfs/sample-fragile-state/cnf-conformance.yml index 0c254819d..51f4fb21e 100644 --- a/sample-cnfs/sample-fragile-state/cnf-conformance.yml +++ b/sample-cnfs/sample-fragile-state/cnf-conformance.yml @@ -7,7 +7,9 @@ deployment_name: coredns-coredns deployment_label: k8s-app service_name: coredns-coredns application_deployment_names: [coredns] -helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [] +rolling_update_test_tag: 1.6.7 +allowlist_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/sample-cnfs/sample-generic-cnf/cnf-conformance.yml b/sample-cnfs/sample-generic-cnf/cnf-conformance.yml index df1578ad8..956101492 100644 --- a/sample-cnfs/sample-generic-cnf/cnf-conformance.yml +++ b/sample-cnfs/sample-generic-cnf/cnf-conformance.yml @@ -1,16 +1,25 @@ --- -helm_directory: helm_chart git_clone_url: https://github.com/coredns/coredns.git install_script: cnfs/coredns/Makefile -release_name: coredns -deployment_name: coredns-coredns +release_name: coredns-1609263557 +deployment_name: coredns-coredns deployment_label: k8s-app -service_name: coredns-coredns -application_deployment_names: [coredns-coredns] +service_name: coredns-coredns +application_deployment_names: +- coredns-coredns docker_repository: coredns/coredns helm_repository: - name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + name: stable + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/coredns helm_chart_container_name: coredns -white_list_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +allowlist_helm_chart_container_names: +- falco +- nginx +- coredns +- calico-node +- kube-proxy +- nginx-proxy +container_names: +- name: coredns + rolling_update_test_tag: 1.8.0 diff --git a/sample-cnfs/sample-large-cnf/cnf-conformance.yml b/sample-cnfs/sample-large-cnf/cnf-conformance.yml index da96c18bc..1f4968a9c 100644 --- a/sample-cnfs/sample-large-cnf/cnf-conformance.yml +++ b/sample-cnfs/sample-large-cnf/cnf-conformance.yml @@ -1,6 +1,5 @@ --- helm_directory: chart -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns @@ -11,8 +10,9 @@ application_deployment_names: [coredns-coredns] docker_repository: coredns/coredns helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com -helm_chart: stable/coredns + repo_url: https://cncf.gitlab.io/stable helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] diff --git a/sample-cnfs/sample-local-storage/Dockerfile b/sample-cnfs/sample-local-storage/Dockerfile new file mode 100644 index 000000000..a5faaa264 --- /dev/null +++ b/sample-cnfs/sample-local-storage/Dockerfile @@ -0,0 +1,4 @@ +FROM debian:latest +COPY entrypoint.sh /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/sample-cnfs/sample-local-storage/chart/.helmignore b/sample-cnfs/sample-local-storage/chart/.helmignore new file mode 100755 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample-local-storage/chart/Chart.yaml b/sample-cnfs/sample-local-storage/chart/Chart.yaml new file mode 100755 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample-local-storage/chart/README.md b/sample-cnfs/sample-local-storage/chart/README.md new file mode 100755 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample-local-storage/chart/templates/NOTES.txt b/sample-cnfs/sample-local-storage/chart/templates/NOTES.txt new file mode 100755 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample-local-storage/chart/templates/_helpers.tpl b/sample-cnfs/sample-local-storage/chart/templates/_helpers.tpl new file mode 100755 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample-local-storage/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample-local-storage/chart/templates/clusterrole-autoscaler.yaml new file mode 100755 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/clusterrole.yaml b/sample-cnfs/sample-local-storage/chart/templates/clusterrole.yaml new file mode 100755 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100755 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding.yaml new file mode 100755 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample-local-storage/chart/templates/configmap-autoscaler.yaml new file mode 100755 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/configmap.yaml b/sample-cnfs/sample-local-storage/chart/templates/configmap.yaml new file mode 100755 index 000000000..b7e1a667f --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample-local-storage/chart/templates/deployment-autoscaler.yaml new file mode 100755 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/deployment.yaml b/sample-cnfs/sample-local-storage/chart/templates/deployment.yaml new file mode 100755 index 000000000..e08f0fc2c --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/deployment.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: task-pv-storage + mountPath: /home + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + volumes: + - name: task-pv-storage + persistentVolumeClaim: + claimName: foo-pvc diff --git a/sample-cnfs/sample-local-storage/chart/templates/persistent-volume-claim.yaml b/sample-cnfs/sample-local-storage/chart/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..a0978d1b0 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/persistent-volume-claim.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: foo-pvc + namespace: default +spec: + storageClassName: local-storage + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Mi + volumeName: example-pv diff --git a/sample-cnfs/sample-local-storage/chart/templates/persistent-volume.yaml b/sample-cnfs/sample-local-storage/chart/templates/persistent-volume.yaml new file mode 100644 index 000000000..4e1a3474e --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/persistent-volume.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: example-pv +spec: + capacity: + storage: 10Mi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + storageClassName: local-storage + local: + path: /var/tmp + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - "{{ .Values.worker_node }}" diff --git a/sample-cnfs/sample-local-storage/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample-local-storage/chart/templates/poddisruptionbudget.yaml new file mode 100755 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample-local-storage/chart/templates/podsecuritypolicy.yaml new file mode 100755 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/service-metrics.yaml b/sample-cnfs/sample-local-storage/chart/templates/service-metrics.yaml new file mode 100755 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/service.yaml b/sample-cnfs/sample-local-storage/chart/templates/service.yaml new file mode 100755 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample-local-storage/chart/templates/serviceaccount-autoscaler.yaml new file mode 100755 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/serviceaccount.yaml b/sample-cnfs/sample-local-storage/chart/templates/serviceaccount.yaml new file mode 100755 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/templates/servicemonitor.yaml b/sample-cnfs/sample-local-storage/chart/templates/servicemonitor.yaml new file mode 100755 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample-local-storage/chart/values.yaml b/sample-cnfs/sample-local-storage/chart/values.yaml new file mode 100755 index 000000000..916d89991 --- /dev/null +++ b/sample-cnfs/sample-local-storage/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "latest" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample-local-storage/cnf-conformance.yml b/sample-cnfs/sample-local-storage/cnf-conformance.yml new file mode 100644 index 000000000..a9d65f6a2 --- /dev/null +++ b/sample-cnfs/sample-local-storage/cnf-conformance.yml @@ -0,0 +1,15 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: +- coredns +helm_chart_container_name: coredns +container_names: +- name: coredns + rolling_update_test_tag: 1.8.0 +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample-local-storage/entrypoint.sh b/sample-cnfs/sample-local-storage/entrypoint.sh new file mode 100755 index 000000000..6c10e39b9 --- /dev/null +++ b/sample-cnfs/sample-local-storage/entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/bash +if [ -f /home/pod_status ]; then + echo "State found, exiting" + exit 1 +else + touch /home/pod_status + sleep infinity +fi + diff --git a/sample-cnfs/sample-minimal-cnf/README.md b/sample-cnfs/sample-minimal-cnf/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample-minimal-cnf/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample-minimal-cnf/cnf-conformance.yml b/sample-cnfs/sample-minimal-cnf/cnf-conformance.yml new file mode 100644 index 000000000..d213f3fa7 --- /dev/null +++ b/sample-cnfs/sample-minimal-cnf/cnf-conformance.yml @@ -0,0 +1,9 @@ +--- +helm_chart: stable/coredns +container_names: +- name: coredns + rolling_update_test_tag: 1.8.0 + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +release_name: coredns-1614713069 diff --git a/sample-cnfs/sample-statefulset-cnf/README.md b/sample-cnfs/sample-statefulset-cnf/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample-statefulset-cnf/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml b/sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml new file mode 100644 index 000000000..a6e123614 --- /dev/null +++ b/sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml @@ -0,0 +1,26 @@ +--- +git_clone_url: +install_script: +release_name: my-release --set mariadb.primary.persistence.enabled=false --set persistence.enabled=false +# deployment_name: my-release-wordpress +# deployment_label: app.kubernetes.io/name +service_name: +# application_deployment_names: [my-release-wordpress] +docker_repository: bitnami/wordpress +helm_repository: + name: bitnami + repo_url: https://charts.bitnami.com/bitnami +helm_chart: bitnami/wordpress +helm_chart_container_name: busybox +allowlist_helm_chart_container_names: [falco, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: wordpress + rolling_update_test_tag: "5.6.0-debian-10-r11" + rolling_downgrade_test_tag: 5.6.0-debian-10-r10 + rolling_version_change_test_tag: latest + rollback_from_tag: latest + - name: mariadb + rolling_update_test_tag: "10.5.8-debian-10-r21" + rolling_downgrade_test_tag: 10.5.8-debian-10-r20 + rolling_version_change_test_tag: latest + rollback_from_tag: latest diff --git a/sample-cnfs/sample_coredns/cnf-conformance.yml b/sample-cnfs/sample_coredns/cnf-conformance.yml index 0c254819d..8b7f46fbc 100644 --- a/sample-cnfs/sample_coredns/cnf-conformance.yml +++ b/sample-cnfs/sample_coredns/cnf-conformance.yml @@ -7,7 +7,11 @@ deployment_name: coredns-coredns deployment_label: k8s-app service_name: coredns-coredns application_deployment_names: [coredns] -helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: 1.8.0 + rollback_from_tag: 1.8.0 +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml b/sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml index dd7c9de68..7cc92dfdf 100644 --- a/sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml +++ b/sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml @@ -7,6 +7,8 @@ deployment_name: bad-liveness-coredns deployment_label: k8s-app service_name: bad-liveness-coredns application_deployment_names: [bad-liveness-coredns] -helm_chart: stable/coredns helm_chart_container_name: bad-liveness-coredns -white_list_helm_chart_container_names: [] +allowlist_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml b/sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml index 1a4426975..f2d1ce534 100644 --- a/sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml +++ b/sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml @@ -6,7 +6,8 @@ release_name: coredns deployment_name: coredns-coredns deployment_label: k8s-app application_deployment_names: [coredns-coredns] -helm_chart: helm_chart_container_name: coredns-coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_coredns_hardcoded_ips/cnf-conformance.yml b/sample-cnfs/sample_coredns_hardcoded_ips/cnf-conformance.yml index 36aea7de9..a01de0639 100644 --- a/sample-cnfs/sample_coredns_hardcoded_ips/cnf-conformance.yml +++ b/sample-cnfs/sample_coredns_hardcoded_ips/cnf-conformance.yml @@ -7,7 +7,8 @@ deployment_name: coredns-coredns deployment_label: k8s-app service_name: coredns-coredns application_deployment_names: [coredns-coredns] -helm_chart: helm_chart_container_name: coredns-coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_coredns_invalid_version/README.md b/sample-cnfs/sample_coredns_invalid_version/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/.helmignore b/sample-cnfs/sample_coredns_invalid_version/chart/.helmignore new file mode 100755 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/Chart.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/Chart.yaml new file mode 100755 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/README.md b/sample-cnfs/sample_coredns_invalid_version/chart/README.md new file mode 100755 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/NOTES.txt b/sample-cnfs/sample_coredns_invalid_version/chart/templates/NOTES.txt new file mode 100755 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/_helpers.tpl b/sample-cnfs/sample_coredns_invalid_version/chart/templates/_helpers.tpl new file mode 100755 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole-autoscaler.yaml new file mode 100755 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole.yaml new file mode 100755 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100755 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding.yaml new file mode 100755 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap-autoscaler.yaml new file mode 100755 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap.yaml new file mode 100755 index 000000000..b7e1a667f --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment-autoscaler.yaml new file mode 100755 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment.yaml new file mode 100755 index 000000000..11db35a0f --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/poddisruptionbudget.yaml new file mode 100755 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/podsecuritypolicy.yaml new file mode 100755 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/service-metrics.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/service-metrics.yaml new file mode 100755 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/service.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/service.yaml new file mode 100755 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount-autoscaler.yaml new file mode 100755 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount.yaml new file mode 100755 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/templates/servicemonitor.yaml new file mode 100755 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_coredns_invalid_version/chart/values.yaml b/sample-cnfs/sample_coredns_invalid_version/chart/values.yaml new file mode 100755 index 000000000..d7e074d93 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml b/sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml new file mode 100644 index 000000000..30a9506f5 --- /dev/null +++ b/sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "this_is_not_a_valid_version" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_coredns_protected/README.md b/sample-cnfs/sample_coredns_protected/README.md new file mode 100644 index 000000000..3e0e9c0e9 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/README.md @@ -0,0 +1,44 @@ +# Set up Sample CoreDNS CNF + +This CoreDNS sample uses a modified Helm chart supporting a private Docker Hub registry. The access credentials are passed to the helm command line through the cnf-conformance.yml key [release_name](https://github.com/cncf/cnf-conformance/blob/master/sample-cnfs/sample_coredns_protected/cnf-conformance.yml#L5). + + +You need to set the environment options listed in the [cnf-conformance.yml](cnf-conformance.yml). + +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_coredns_protected/chart/.helmignore b/sample-cnfs/sample_coredns_protected/chart/.helmignore new file mode 100755 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_coredns_protected/chart/Chart.yaml b/sample-cnfs/sample_coredns_protected/chart/Chart.yaml new file mode 100755 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_coredns_protected/chart/README.md b/sample-cnfs/sample_coredns_protected/chart/README.md new file mode 100755 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/NOTES.txt b/sample-cnfs/sample_coredns_protected/chart/templates/NOTES.txt new file mode 100755 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/_helpers.tpl b/sample-cnfs/sample_coredns_protected/chart/templates/_helpers.tpl new file mode 100755 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole-autoscaler.yaml new file mode 100755 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole.yaml new file mode 100755 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100755 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding.yaml new file mode 100755 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/configmap-autoscaler.yaml new file mode 100755 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/configmap.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/configmap.yaml new file mode 100755 index 000000000..b7e1a667f --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/deployment-autoscaler.yaml new file mode 100755 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/deployment.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/deployment.yaml new file mode 100755 index 000000000..731269604 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/deployment.yaml @@ -0,0 +1,125 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + imagePullSecrets: + - name: myregistrykey + - name: myregistrykey2 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/poddisruptionbudget.yaml new file mode 100755 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/podsecuritypolicy.yaml new file mode 100755 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/secret.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/secret.yaml new file mode 100644 index 000000000..8bd29b46b --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/secret.yaml @@ -0,0 +1,21 @@ +{{- define "imagePullSecret" }} +{{- with .Values.imageCredentials }} +{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: myregistrykey +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ template "imagePullSecret" . }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: myregistrykey2 +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ template "imagePullSecret" . }} + diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/service-metrics.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/service-metrics.yaml new file mode 100755 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/service.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/service.yaml new file mode 100755 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount-autoscaler.yaml new file mode 100755 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount.yaml new file mode 100755 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_coredns_protected/chart/templates/servicemonitor.yaml new file mode 100755 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_coredns_protected/chart/values.yaml b/sample-cnfs/sample_coredns_protected/chart/values.yaml new file mode 100755 index 000000000..2260c9abd --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/chart/values.yaml @@ -0,0 +1,204 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +imageCredentials: + registry: quay.io + username: username + password: password + email: someone@host.com + +image: + repository: goppa/protected + tag: "latest" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_coredns_protected/cnf-conformance.yml b/sample-cnfs/sample_coredns_protected/cnf-conformance.yml new file mode 100644 index 000000000..defd74ea3 --- /dev/null +++ b/sample-cnfs/sample_coredns_protected/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns --set imageCredentials.registry=https://index.docker.io/v1/ --set imageCredentials.username=$PROTECTED_DOCKERHUB_USERNAME --set imageCredentials.password=$PROTECTED_DOCKERHUB_PASSWORD --set imageCredentials.email=$PROTECTED_DOCKERHUB_EMAIL +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml b/sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml index 281722700..08b2cdbf8 100644 --- a/sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml +++ b/sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml @@ -1,6 +1,5 @@ --- helm_directory: chart -helm_chart: git_clone_url: install_script: release_name: envoy @@ -9,5 +8,7 @@ deployment_label: app service_name: envoy application_deployment_names: [envoy] helm_chart_container_name: envoy -white_list_helm_chart_container_names: [falco, nginx, envoy, calico-node, kube-proxy, nginx-proxy, node-cache] -rolling_update_tag: v1.12.2 +allowlist_helm_chart_container_names: [falco, nginx, envoy, calico-node, kube-proxy, nginx-proxy, node-cache] +container_names: + - name: envoy + rolling_update_test_tag: "v1.11.0" diff --git a/sample-cnfs/sample_immutable_configmap_all/README.md b/sample-cnfs/sample_immutable_configmap_all/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/.helmignore b/sample-cnfs/sample_immutable_configmap_all/chart/.helmignore new file mode 100644 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/Chart.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/Chart.yaml new file mode 100644 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/README.md b/sample-cnfs/sample_immutable_configmap_all/chart/README.md new file mode 100644 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/NOTES.txt b/sample-cnfs/sample_immutable_configmap_all/chart/templates/NOTES.txt new file mode 100644 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/_helpers.tpl b/sample-cnfs/sample_immutable_configmap_all/chart/templates/_helpers.tpl new file mode 100644 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole-autoscaler.yaml new file mode 100644 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole.yaml new file mode 100644 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100644 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap-autoscaler.yaml new file mode 100644 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap.yaml new file mode 100644 index 000000000..5bf9242cd --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/configmap.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +immutable: true +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment-autoscaler.yaml new file mode 100644 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment.yaml new file mode 100644 index 000000000..11db35a0f --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/poddisruptionbudget.yaml new file mode 100644 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/service-metrics.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/service-metrics.yaml new file mode 100644 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/service.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/service.yaml new file mode 100644 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount-autoscaler.yaml new file mode 100644 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount.yaml new file mode 100644 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/templates/servicemonitor.yaml new file mode 100644 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all/chart/values.yaml b/sample-cnfs/sample_immutable_configmap_all/chart/values.yaml new file mode 100644 index 000000000..d7e074d93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml b/sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml new file mode 100644 index 000000000..6f925573a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/README.md b/sample-cnfs/sample_immutable_configmap_all_plus_env/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/.helmignore b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/.helmignore new file mode 100644 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/Chart.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/Chart.yaml new file mode 100644 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/README.md b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/README.md new file mode 100644 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/NOTES.txt b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/NOTES.txt new file mode 100644 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/_helpers.tpl b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/_helpers.tpl new file mode 100644 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole-autoscaler.yaml new file mode 100644 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole.yaml new file mode 100644 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100644 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap-autoscaler.yaml new file mode 100644 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap.yaml new file mode 100644 index 000000000..2134c3320 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/configmap.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +immutable: true +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} + willsTestValue: "true" diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment-autoscaler.yaml new file mode 100644 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment.yaml new file mode 100644 index 000000000..5547020d0 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/deployment.yaml @@ -0,0 +1,128 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + env: + - name: WILLS_MADEUP_SPECIAL_LEVEL_KEY_ENV_VAR + valueFrom: + configMapKeyRef: + name: {{ template "coredns.fullname" . }} + key: willsTestValue + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/poddisruptionbudget.yaml new file mode 100644 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service-metrics.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service-metrics.yaml new file mode 100644 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service.yaml new file mode 100644 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount-autoscaler.yaml new file mode 100644 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount.yaml new file mode 100644 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/servicemonitor.yaml new file mode 100644 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/values.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/values.yaml new file mode 100644 index 000000000..d7e074d93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env/cnf-conformance.yml b/sample-cnfs/sample_immutable_configmap_all_plus_env/cnf-conformance.yml new file mode 100644 index 000000000..6f925573a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/README.md b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/.helmignore b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/.helmignore new file mode 100644 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/Chart.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/Chart.yaml new file mode 100644 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/README.md b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/README.md new file mode 100644 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/NOTES.txt b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/NOTES.txt new file mode 100644 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/_helpers.tpl b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/_helpers.tpl new file mode 100644 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole-autoscaler.yaml new file mode 100644 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole.yaml new file mode 100644 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100644 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-autoscaler.yaml new file mode 100644 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-wills-test.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-wills-test.yaml new file mode 100644 index 000000000..d0d56893d --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap-wills-test.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }}-will-test +data: + willsTestValue: "true" diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap.yaml new file mode 100644 index 000000000..2134c3320 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/configmap.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +immutable: true +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} + willsTestValue: "true" diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment-autoscaler.yaml new file mode 100644 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment.yaml new file mode 100644 index 000000000..df06bace8 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/deployment.yaml @@ -0,0 +1,128 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + env: + - name: WILLS_MADEUP_SPECIAL_LEVEL_KEY_ENV_VAR + valueFrom: + configMapKeyRef: + name: {{ template "coredns.fullname" . }}-will-test + key: willsTestValue + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/poddisruptionbudget.yaml new file mode 100644 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service-metrics.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service-metrics.yaml new file mode 100644 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service.yaml new file mode 100644 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount-autoscaler.yaml new file mode 100644 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount.yaml new file mode 100644 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/servicemonitor.yaml new file mode 100644 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/values.yaml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/values.yaml new file mode 100644 index 000000000..d7e074d93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/cnf-conformance.yml b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/cnf-conformance.yml new file mode 100644 index 000000000..6f925573a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_immutable_configmap_some/README.md b/sample-cnfs/sample_immutable_configmap_some/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/.helmignore b/sample-cnfs/sample_immutable_configmap_some/chart/.helmignore new file mode 100644 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/Chart.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/Chart.yaml new file mode 100644 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/README.md b/sample-cnfs/sample_immutable_configmap_some/chart/README.md new file mode 100644 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/NOTES.txt b/sample-cnfs/sample_immutable_configmap_some/chart/templates/NOTES.txt new file mode 100644 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/_helpers.tpl b/sample-cnfs/sample_immutable_configmap_some/chart/templates/_helpers.tpl new file mode 100644 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole-autoscaler.yaml new file mode 100644 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole.yaml new file mode 100644 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100644 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-autoscaler.yaml new file mode 100644 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-test-not-immutable.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-test-not-immutable.yaml new file mode 100644 index 000000000..f4bdf4a73 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap-test-not-immutable.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +data: + api.server: "https://example.com" +kind: ConfigMap +metadata: + name: myapp diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap.yaml new file mode 100644 index 000000000..5bf9242cd --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/configmap.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +immutable: true +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment-autoscaler.yaml new file mode 100644 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment.yaml new file mode 100644 index 000000000..11db35a0f --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/poddisruptionbudget.yaml new file mode 100644 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/service-metrics.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/service-metrics.yaml new file mode 100644 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/service.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/service.yaml new file mode 100644 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount-autoscaler.yaml new file mode 100644 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount.yaml new file mode 100644 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/templates/servicemonitor.yaml new file mode 100644 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_immutable_configmap_some/chart/values.yaml b/sample-cnfs/sample_immutable_configmap_some/chart/values.yaml new file mode 100644 index 000000000..d7e074d93 --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_immutable_configmap_some/cnf-conformance.yml b/sample-cnfs/sample_immutable_configmap_some/cnf-conformance.yml new file mode 100644 index 000000000..6f925573a --- /dev/null +++ b/sample-cnfs/sample_immutable_configmap_some/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_local_registry/README.md b/sample-cnfs/sample_local_registry/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_local_registry/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_local_registry/chart/.helmignore b/sample-cnfs/sample_local_registry/chart/.helmignore new file mode 100755 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_local_registry/chart/Chart.yaml b/sample-cnfs/sample_local_registry/chart/Chart.yaml new file mode 100755 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_local_registry/chart/README.md b/sample-cnfs/sample_local_registry/chart/README.md new file mode 100755 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_local_registry/chart/templates/NOTES.txt b/sample-cnfs/sample_local_registry/chart/templates/NOTES.txt new file mode 100755 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_local_registry/chart/templates/_helpers.tpl b/sample-cnfs/sample_local_registry/chart/templates/_helpers.tpl new file mode 100755 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_local_registry/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_local_registry/chart/templates/clusterrole-autoscaler.yaml new file mode 100755 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/clusterrole.yaml b/sample-cnfs/sample_local_registry/chart/templates/clusterrole.yaml new file mode 100755 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100755 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding.yaml new file mode 100755 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_local_registry/chart/templates/configmap-autoscaler.yaml new file mode 100755 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/configmap.yaml b/sample-cnfs/sample_local_registry/chart/templates/configmap.yaml new file mode 100755 index 000000000..b7e1a667f --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_local_registry/chart/templates/deployment-autoscaler.yaml new file mode 100755 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/deployment.yaml b/sample-cnfs/sample_local_registry/chart/templates/deployment.yaml new file mode 100755 index 000000000..11db35a0f --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_local_registry/chart/templates/poddisruptionbudget.yaml new file mode 100755 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_local_registry/chart/templates/podsecuritypolicy.yaml new file mode 100755 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/service-metrics.yaml b/sample-cnfs/sample_local_registry/chart/templates/service-metrics.yaml new file mode 100755 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/service.yaml b/sample-cnfs/sample_local_registry/chart/templates/service.yaml new file mode 100755 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_local_registry/chart/templates/serviceaccount-autoscaler.yaml new file mode 100755 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_local_registry/chart/templates/serviceaccount.yaml new file mode 100755 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_local_registry/chart/templates/servicemonitor.yaml new file mode 100755 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_local_registry/chart/values.yaml b/sample-cnfs/sample_local_registry/chart/values.yaml new file mode 100755 index 000000000..045ea872f --- /dev/null +++ b/sample-cnfs/sample_local_registry/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: registry:5000/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_local_registry/cnf-conformance.yml b/sample-cnfs/sample_local_registry/cnf-conformance.yml new file mode 100644 index 000000000..808ae93d0 --- /dev/null +++ b/sample-cnfs/sample_local_registry/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: 1.8.0 + rollback_from_tag: 1.8.0 +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_local_registry_org_image/README.md b/sample-cnfs/sample_local_registry_org_image/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_local_registry_org_image/chart/.helmignore b/sample-cnfs/sample_local_registry_org_image/chart/.helmignore new file mode 100755 index 000000000..7c04072e1 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +OWNERS diff --git a/sample-cnfs/sample_local_registry_org_image/chart/Chart.yaml b/sample-cnfs/sample_local_registry_org_image/chart/Chart.yaml new file mode 100755 index 000000000..862d36cde --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- email: hello@acale.ph + name: Acaleph +- email: shashidhara.huawei@gmail.com + name: shashidharatd +- email: andor44@gmail.com + name: andor44 +- email: manuel@rueg.eu + name: mrueg +name: coredns +sources: +- https://github.com/coredns/coredns +version: 1.10.0 diff --git a/sample-cnfs/sample_local_registry_org_image/chart/README.md b/sample-cnfs/sample_local_registry_org_image/chart/README.md new file mode 100755 index 000000000..b4fbbc91b --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/README.md @@ -0,0 +1,138 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + + - CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. + - CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. + - CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm install --name coredns --namespace=kube-system stable/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +|:----------------------------------------|:--------------------------------------------------------------------------------------|:------------------------------------------------------------| +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from | `v1.6.7` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalTrafficPolicy` | Enable client source IP preservation | `[]` | +| `service.annotations` | Annotations to add to service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}`| +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | k8s.gcr.io/cluster-proportional-autoscaler-amd64 | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.7.1` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install --name coredns \ + --set rbac.create=false \ + stable/coredns +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install --name coredns -f values.yaml stable/coredns +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/NOTES.txt b/sample-cnfs/sample_local_registry_org_image/chart/templates/NOTES.txt new file mode 100755 index 000000000..3a1883b3a --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/_helpers.tpl b/sample-cnfs/sample_local_registry_org_image/chart/templates/_helpers.tpl new file mode 100755 index 000000000..a2efcb43e --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {port: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {port: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq .use_tcp true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// on both tcp & udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- if index $innerdict "isudp" -}} + {{- printf "- {containerPort: %v, protocol: UDP, name: udp-%s}\n" $port $port -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- printf "- {containerPort: %v, protocol: TCP, name: tcp-%s}\n" $port $port -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole-autoscaler.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole-autoscaler.yaml new file mode 100755 index 000000000..748c62bf7 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole.yaml new file mode 100755 index 000000000..029d13e27 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding-autoscaler.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding-autoscaler.yaml new file mode 100755 index 000000000..eafb38f9e --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding.yaml new file mode 100755 index 000000000..49da9b548 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap-autoscaler.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap-autoscaler.yaml new file mode 100755 index 000000000..50895ae5b --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap-autoscaler.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations }} + annotations: + {{- toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": true + } +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap.yaml new file mode 100755 index 000000000..b7e1a667f --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +data: + Corefile: |- + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment-autoscaler.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment-autoscaler.yaml new file mode 100755 index 000000000..7ca185239 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment-autoscaler.yaml @@ -0,0 +1,77 @@ +{{- if .Values.autoscaler.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ template "coredns.fullname" . }} + - --logtostderr=true + - --v=2 +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment.yaml new file mode 100755 index 000000000..11db35a0f --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + {{- if not .Values.autoscaler.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 10% + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/critical-pod: '' + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + spec: + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: 400 +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/poddisruptionbudget.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/poddisruptionbudget.yaml new file mode 100755 index 000000000..8ade224f8 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/poddisruptionbudget.yaml @@ -0,0 +1,28 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/podsecuritypolicy.yaml new file mode 100755 index 000000000..754943fe5 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/podsecuritypolicy.yaml @@ -0,0 +1,57 @@ +{{- if .Values.rbac.pspEnable }} +{{ if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +apiVersion: extensions/v1beta1 +{{ end -}} +kind: PodSecurityPolicy +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- else }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # Add back CAP_NET_BIND_SERVICE so that coredns can run on port 53 + allowedCapabilities: + - CAP_NET_BIND_SERVICE + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/service-metrics.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/service-metrics.yaml new file mode 100755 index 000000000..ae213c043 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/service-metrics.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/service.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/service.yaml new file mode 100755 index 000000000..4098664bb --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + selector: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount-autoscaler.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount-autoscaler.yaml new file mode 100755 index 000000000..972c74612 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name }}-autoscaler + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount.yaml new file mode 100755 index 000000000..bced7ca3d --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/templates/servicemonitor.yaml b/sample-cnfs/sample_local_registry_org_image/chart/templates/servicemonitor.yaml new file mode 100755 index 000000000..0a4ffb581 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ .Chart.Name | quote }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + endpoints: + - port: metrics +{{- end }} diff --git a/sample-cnfs/sample_local_registry_org_image/chart/values.yaml b/sample-cnfs/sample_local_registry_org_image/chart/values.yaml new file mode 100755 index 000000000..913fe1ab1 --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/chart/values.yaml @@ -0,0 +1,198 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: registry:5000/coredns/coredns + tag: "1.6.7" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +serviceType: "ClusterIP" + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + +service: +# clusterIP: "" +# loadBalancerIP: "" +# externalTrafficPolicy: "" + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: + +rbac: + # If true, create & use RBAC resources + create: true + # If true, create and use PodSecurityPolicy + pspEnable: false + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + # name: + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + port: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 5s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# - name: some-fancy-secret +# mountPath: /etc/wherever + +# Custom labels to apply to Deployment, Pod, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + + image: + repository: k8s.gcr.io/cluster-proportional-autoscaler-amd64 + tag: "1.7.1" + pullPolicy: IfNotPresent + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} diff --git a/sample-cnfs/sample_local_registry_org_image/cnf-conformance.yml b/sample-cnfs/sample_local_registry_org_image/cnf-conformance.yml new file mode 100644 index 000000000..6f925573a --- /dev/null +++ b/sample-cnfs/sample_local_registry_org_image/cnf-conformance.yml @@ -0,0 +1,17 @@ +--- +helm_directory: chart +git_clone_url: +install_script: chart +release_name: coredns +deployment_name: coredns-coredns +deployment_label: k8s-app +service_name: coredns-coredns +application_deployment_names: [coredns] +helm_chart_container_name: coredns +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_network_loss/cnf-conformance.yml b/sample-cnfs/sample_network_loss/cnf-conformance.yml index 84d214abe..fa1f55357 100644 --- a/sample-cnfs/sample_network_loss/cnf-conformance.yml +++ b/sample-cnfs/sample_network_loss/cnf-conformance.yml @@ -1,6 +1,5 @@ --- helm_directory: chart -helm_chart: git_clone_url: install_script: chart release_name: coredns @@ -9,5 +8,7 @@ deployment_label: k8s-app service_name: coredns-coredns application_deployment_names: [coredns] helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_nodeport/cnf-conformance.yml b/sample-cnfs/sample_nodeport/cnf-conformance.yml index b6b0b19d9..f4790fd6a 100644 --- a/sample-cnfs/sample_nodeport/cnf-conformance.yml +++ b/sample-cnfs/sample_nodeport/cnf-conformance.yml @@ -7,7 +7,11 @@ deployment_name: unifi deployment_label: app.kubernetes.io/name service_name: unifi-controller application_deployment_names: [unifi] -helm_chart: stable/unifi +# helm_chart: stable/unifi helm_chart_container_name: unifi -rolling_update_tag: latest -white_list_helm_chart_container_names: [] +container_names: + - name: unifi + rolling_update_test_tag: "5.12.34" + rolling_downgrade_test_tag: "5.12.12" + rolling_version_change_test_tag: latest +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_privileged_cnf/cnf-conformance.yml b/sample-cnfs/sample_privileged_cnf/cnf-conformance.yml index bd13117f9..8ac4a3d49 100644 --- a/sample-cnfs/sample_privileged_cnf/cnf-conformance.yml +++ b/sample-cnfs/sample_privileged_cnf/cnf-conformance.yml @@ -3,10 +3,11 @@ helm_directory: chart git_clone_url: install_script: release_name: privileged-coredns -deployment_name: privileged-coredns-coredns +deployment_name: privileged-coredns deployment_label: k8s-app -service_name: privileged-coredns-coredns -application_deployment_names: [privileged-coredns-coredns] -helm_chart: stable/coredns -helm_chart_container_name: privileged-coredns-coredns -white_list_helm_chart_container_names: [] +service_name: privileged-coredns +helm_chart_container_name: +allowlist_helm_chart_container_names: [] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/sample-cnfs/sample_secret_env/README.md b/sample-cnfs/sample_secret_env/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_secret_env/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_secret_env/cnf-conformance.yml b/sample-cnfs/sample_secret_env/cnf-conformance.yml new file mode 100644 index 000000000..acc776928 --- /dev/null +++ b/sample-cnfs/sample_secret_env/cnf-conformance.yml @@ -0,0 +1,10 @@ +--- +helm_directory: postgresql +git_clone_url: +install_script: chart +release_name: postgresql +service_name: postgresql +container_names: + - name: postgresql + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_secret_env/postgresql/.helmignore b/sample-cnfs/sample_secret_env/postgresql/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/sample-cnfs/sample_secret_env/postgresql/Chart.lock b/sample-cnfs/sample_secret_env/postgresql/Chart.lock new file mode 100644 index 000000000..00ef82278 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.1.2 +digest: sha256:5a5d1b6e8a55efef1c07768b6bb264c60c98e230792b9a63f85468b95cf58c45 +generated: "2020-12-11T12:22:28.510708+01:00" diff --git a/sample-cnfs/sample_secret_env/postgresql/Chart.yaml b/sample-cnfs/sample_secret_env/postgresql/Chart.yaml new file mode 100644 index 000000000..332cb9650 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/Chart.yaml @@ -0,0 +1,29 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 11.10.0 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.x.x +description: Chart for PostgreSQL, an object-relational database management system + (ORDBMS) with an emphasis on extensibility and on standards-compliance. +home: https://github.com/bitnami/charts/tree/master/bitnami/postgresql +icon: https://bitnami.com/assets/stacks/postgresql/img/postgresql-stack-110x117.png +keywords: +- postgresql +- postgres +- database +- sql +- replication +- cluster +maintainers: +- email: containers@bitnami.com + name: Bitnami +- email: cedric@desaintmartin.fr + name: desaintmartin +name: postgresql +sources: +- https://github.com/bitnami/bitnami-docker-postgresql +- https://www.postgresql.org/ +version: 10.2.0 diff --git a/sample-cnfs/sample_secret_env/postgresql/README.md b/sample-cnfs/sample_secret_env/postgresql/README.md new file mode 100644 index 000000000..9cf7c4128 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/README.md @@ -0,0 +1,798 @@ +# PostgreSQL + +[PostgreSQL](https://www.postgresql.org/) is an object-relational database management system (ORDBMS) with an emphasis on extensibility and on standards-compliance. + +For HA, please see [this repo](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) + +## TL;DR + +```console +$ helm repo add bitnami https://charts.bitnami.com/bitnami +$ helm install my-release bitnami/postgresql +``` + +## Introduction + +This chart bootstraps a [PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart +To install the chart with the release name `my-release`: + +```console +$ helm install my-release bitnami/postgresql +``` + +The command deploys PostgreSQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components but PVC's associated with the chart and deletes the release. + +To delete the PVC's associated with `my-release`: + +```console +$ kubectl delete pvc -l release=my-release +``` + +> **Note**: Deleting the PVC's will delete postgresql data as well. Please be cautious before doing it. + +## Parameters + +The following tables lists the configurable parameters of the PostgreSQL chart and their default values. + +| Parameter | Description | Default | +|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| +| `global.imageRegistry` | Global Docker Image registry | `nil` | +| `global.postgresql.postgresqlDatabase` | PostgreSQL database (overrides `postgresqlDatabase`) | `nil` | +| `global.postgresql.postgresqlUsername` | PostgreSQL username (overrides `postgresqlUsername`) | `nil` | +| `global.postgresql.existingSecret` | Name of existing secret to use for PostgreSQL passwords (overrides `existingSecret`) | `nil` | +| `global.postgresql.postgresqlPassword` | PostgreSQL admin password (overrides `postgresqlPassword`) | `nil` | +| `global.postgresql.servicePort` | PostgreSQL port (overrides `service.port`) | `nil` | +| `global.postgresql.replicationPassword` | Replication user password (overrides `replication.password`) | `nil` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | +| `global.storageClass` | Global storage class for dynamic provisioning | `nil` | +| `image.registry` | PostgreSQL Image registry | `docker.io` | +| `image.repository` | PostgreSQL Image name | `bitnami/postgresql` | +| `image.tag` | PostgreSQL Image tag | `{TAG_NAME}` | +| `image.pullPolicy` | PostgreSQL Image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `image.debug` | Specify if debug values should be set | `false` | +| `nameOverride` | String to partially override common.names.fullname template with a string (will prepend the release name) | `nil` | +| `fullnameOverride` | String to fully override common.names.fullname template with a string | `nil` | +| `volumePermissions.enabled` | Enable init container that changes volume permissions in the data directory (for cases where the default k8s `runAsUser` and `fsUser` values do not work) | `false` | +| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | +| `volumePermissions.image.repository` | Init container volume-permissions image name | `bitnami/minideb` | +| `volumePermissions.image.tag` | Init container volume-permissions image tag | `buster` | +| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `Always` | +| `volumePermissions.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container (when facing issues in OpenShift or uid unknown, try value "auto") | `0` | +| `usePasswordFile` | Have the secrets mounted as a file instead of env vars | `false` | +| `ldap.enabled` | Enable LDAP support | `false` | +| `ldap.existingSecret` | Name of existing secret to use for LDAP passwords | `nil` | +| `ldap.url` | LDAP URL beginning in the form `ldap[s]://host[:port]/basedn[?[attribute][?[scope][?[filter]]]]` | `nil` | +| `ldap.server` | IP address or name of the LDAP server. | `nil` | +| `ldap.port` | Port number on the LDAP server to connect to | `nil` | +| `ldap.scheme` | Set to `ldaps` to use LDAPS. | `nil` | +| `ldap.tls` | Set to `1` to use TLS encryption | `nil` | +| `ldap.prefix` | String to prepend to the user name when forming the DN to bind | `nil` | +| `ldap.suffix` | String to append to the user name when forming the DN to bind | `nil` | +| `ldap.search_attr` | Attribute to match against the user name in the search | `nil` | +| `ldap.search_filter` | The search filter to use when doing search+bind authentication | `nil` | +| `ldap.baseDN` | Root DN to begin the search for the user in | `nil` | +| `ldap.bindDN` | DN of user to bind to LDAP | `nil` | +| `ldap.bind_password` | Password for the user to bind to LDAP | `nil` | +| `replication.enabled` | Enable replication | `false` | +| `replication.user` | Replication user | `repl_user` | +| `replication.password` | Replication user password | `repl_password` | +| `replication.readReplicas` | Number of read replicas replicas | `1` | +| `replication.synchronousCommit` | Set synchronous commit mode. Allowed values: `on`, `remote_apply`, `remote_write`, `local` and `off` | `off` | +| `replication.numSynchronousReplicas` | Number of replicas that will have synchronous replication. Note: Cannot be greater than `replication.readReplicas`. | `0` | +| `replication.applicationName` | Cluster application name. Useful for advanced replication settings | `my_application` | +| `existingSecret` | Name of existing secret to use for PostgreSQL passwords. The secret has to contain the keys `postgresql-password` which is the password for `postgresqlUsername` when it is different of `postgres`, `postgresql-postgres-password` which will override `postgresqlPassword`, `postgresql-replication-password` which will override `replication.password` and `postgresql-ldap-password` which will be sed to authenticate on LDAP. The value is evaluated as a template. | `nil` | +| `postgresqlPostgresPassword` | PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`, in which case`postgres` is the admin username). | _random 10 character alphanumeric string_ | +| `postgresqlUsername` | PostgreSQL user (creates a non-admin user when `postgresqlUsername` is not `postgres`) | `postgres` | +| `postgresqlPassword` | PostgreSQL user password | _random 10 character alphanumeric string_ | +| `postgresqlDatabase` | PostgreSQL database | `nil` | +| `postgresqlDataDir` | PostgreSQL data dir folder | `/bitnami/postgresql` (same value as persistence.mountPath) | +| `extraEnv` | Any extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `[]` | +| `extraEnvVarsCM` | Name of a Config Map containing extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `nil` | +| `postgresqlInitdbArgs` | PostgreSQL initdb extra arguments | `nil` | +| `postgresqlInitdbWalDir` | PostgreSQL location for transaction log | `nil` | +| `postgresqlConfiguration` | Runtime Config Parameters | `nil` | +| `postgresqlExtendedConf` | Extended Runtime Config Parameters (appended to main or default configuration) | `nil` | +| `pgHbaConfiguration` | Content of pg_hba.conf | `nil (do not create pg_hba.conf)` | +| `postgresqlSharedPreloadLibraries` | Shared preload libraries (comma-separated list) | `pgaudit` | +| `postgresqlMaxConnections` | Maximum total connections | `nil` | +| `postgresqlPostgresConnectionLimit` | Maximum total connections for the postgres user | `nil` | +| `postgresqlDbUserConnectionLimit` | Maximum total connections for the non-admin user | `nil` | +| `postgresqlTcpKeepalivesInterval` | TCP keepalives interval | `nil` | +| `postgresqlTcpKeepalivesIdle` | TCP keepalives idle | `nil` | +| `postgresqlTcpKeepalivesCount` | TCP keepalives count | `nil` | +| `postgresqlStatementTimeout` | Statement timeout | `nil` | +| `postgresqlPghbaRemoveFilters` | Comma-separated list of patterns to remove from the pg_hba.conf file | `nil` | +| `customLivenessProbe` | Override default liveness probe | `nil` | +| `customReadinessProbe` | Override default readiness probe | `nil` | +| `audit.logHostname` | Add client hostnames to the log file | `false` | +| `audit.logConnections` | Add client log-in operations to the log file | `false` | +| `audit.logDisconnections` | Add client log-outs operations to the log file | `false` | +| `audit.pgAuditLog` | Add operations to log using the pgAudit extension | `nil` | +| `audit.clientMinMessages` | Message log level to share with the user | `nil` | +| `audit.logLinePrefix` | Template string for the log line prefix | `nil` | +| `audit.logTimezone` | Timezone for the log timestamps | `nil` | +| `configurationConfigMap` | ConfigMap with the PostgreSQL configuration files (Note: Overrides `postgresqlConfiguration` and `pgHbaConfiguration`). The value is evaluated as a template. | `nil` | +| `extendedConfConfigMap` | ConfigMap with the extended PostgreSQL configuration files. The value is evaluated as a template. | `nil` | +| `initdbScripts` | Dictionary of initdb scripts | `nil` | +| `initdbUser` | PostgreSQL user to execute the .sql and sql.gz scripts | `nil` | +| `initdbPassword` | Password for the user specified in `initdbUser` | `nil` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`). The value is evaluated as a template. | `nil` | +| `initdbScriptsSecret` | Secret with initdb scripts that contain sensitive information (Note: can be used with `initdbScriptsConfigMap` or `initdbScripts`). The value is evaluated as a template. | `nil` | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.port` | PostgreSQL port | `5432` | +| `service.nodePort` | Kubernetes Service nodePort | `nil` | +| `service.annotations` | Annotations for PostgreSQL service | `{}` (evaluated as a template) | +| `service.loadBalancerIP` | loadBalancerIP if service type is `LoadBalancer` | `nil` | +| `service.loadBalancerSourceRanges` | Address that are allowed when svc is LoadBalancer | `[]` (evaluated as a template) | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `shmVolume.enabled` | Enable emptyDir volume for /dev/shm for primary and read replica(s) Pod(s) | `true` | +| `shmVolume.chmod.enabled` | Run at init chmod 777 of the /dev/shm (ignored if `volumePermissions.enabled` is `false`) | `true` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim`, the value is evaluated as a template. | `nil` | +| `persistence.mountPath` | Path to mount the volume at | `/bitnami/postgresql` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `persistence.storageClass` | PVC Storage Class for PostgreSQL volume | `nil` | +| `persistence.accessModes` | PVC Access Mode for PostgreSQL volume | `[ReadWriteOnce]` | +| `persistence.size` | PVC Storage Request for PostgreSQL volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume (this value is evaluated as a template) | `{}` | +| `commonAnnotations` | Annotations to be added to all deployed resources (rendered as a template) | `{}` | +| `primary.podAffinityPreset` | PostgreSQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | PostgreSQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | PostgreSQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | PostgreSQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | PostgreSQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.nodeSelector` | Node labels for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.tolerations` | Tolerations for PostgreSQL primary pods assignment | `[]` (evaluated as a template) | + +| `primary.anotations` | Map of annotations to add to the statefulset (postgresql primary) | `{}` | +| `primary.labels` | Map of labels to add to the statefulset (postgresql primary) | `{}` | +| `primary.podAnnotations` | Map of annotations to add to the pods (postgresql primary) | `{}` | +| `primary.podLabels` | Map of labels to add to the pods (postgresql primary) | `{}` | +| `primary.priorityClassName` | Priority Class to use for each pod (postgresql primary) | `nil` | +| `primary.extraInitContainers` | Additional init containers to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumes` | Additional volumes to add to the pods (postgresql primary) | `[]` | +| `primary.sidecars` | Add additional containers to the pod | `[]` | +| `primary.service.type` | Allows using a different service type for primary | `nil` | +| `primary.service.nodePort` | Allows using a different nodePort for primary | `nil` | +| `primary.service.clusterIP` | Allows using a different clusterIP for primary | `nil` | +| `primaryAsStandBy.enabled` | Whether to enable current cluster's primary as standby server of another cluster or not. | `false` | +| `primaryAsStandBy.primaryHost` | The Host of replication primary in the other cluster. | `nil` | +| `primaryAsStandBy.primaryPort ` | The Port of replication primary in the other cluster. | `nil` | +| `readReplicas.podAffinityPreset` | PostgreSQL read only pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.podAntiAffinityPreset` | PostgreSQL read only pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `readReplicas.nodeAffinityPreset.type` | PostgreSQL read only node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.nodeAffinityPreset.key` | PostgreSQL read only node label key to match Ignored if `primary.affinity` is set. | `""` | +| `readReplicas.nodeAffinityPreset.values` | PostgreSQL read only node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `readReplicas.affinity` | Affinity for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.nodeSelector` | Node labels for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.anotations` | Map of annotations to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.resources` | CPU/Memory resource requests/limits override for readReplicass. Will fallback to `values.resources` if not defined. | `{}` | +| `readReplicas.labels` | Map of labels to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.podAnnotations` | Map of annotations to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.podLabels` | Map of labels to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.priorityClassName` | Priority Class to use for each pod (postgresql readReplicas) | `nil` | +| `readReplicas.extraInitContainers` | Additional init containers to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumes` | Additional volumes to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.sidecars` | Add additional containers to the pod | `[]` | +| `readReplicas.service.type` | Allows using a different service type for readReplicas | `nil` | +| `readReplicas.service.nodePort` | Allows using a different nodePort for readReplicas | `nil` | +| `readReplicas.service.clusterIP` | Allows using a different clusterIP for readReplicas | `nil` | +| `readReplicas.persistence.enabled` | Whether to enable readReplicas replicas persistence | `true` | +| `terminationGracePeriodSeconds` | Seconds the pod needs to terminate gracefully | `nil` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | +| `securityContext.*` | Other pod security context to be included as-is in the pod spec | `{}` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the pod | `1001` | +| `containerSecurityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `containerSecurityContext.enabled` | Enable container security context | `true` | +| `containerSecurityContext.runAsUser` | User ID for the container | `1001` | +| `serviceAccount.enabled` | Enable service account (Note: Service Account will only be automatically created if `serviceAccount.name` is not set) | `false` | +| `serviceAccount.name` | Name of existing service account | `nil` | +| `livenessProbe.enabled` | Would you like a livenessProbe to be enabled | `true` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed | `{}` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `tls.enabled` | Enable TLS traffic support | `false` | +| `tls.preferServerCiphers` | Whether to use the server's TLS cipher preferences rather than the client's | `true` | +| `tls.certificatesSecret` | Name of an existing secret that contains the certificates | `nil` | +| `tls.certFilename` | Certificate filename | `""` | +| `tls.certKeyFilename` | Certificate key filename | `""` | +| `tls.certCAFilename` | CA Certificate filename. If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate. | `nil` | +| `tls.crlFilename` | File containing a Certificate Revocation List | `nil` | +| `metrics.enabled` | Start a prometheus exporter | `false` | +| `metrics.service.type` | Kubernetes Service type | `ClusterIP` | +| `service.clusterIP` | Static clusterIP or None for headless services | `nil` | +| `metrics.service.annotations` | Additional annotations for metrics exporter pod | `{ prometheus.io/scrape: "true", prometheus.io/port: "9187"}` | +| `metrics.service.loadBalancerIP` | loadBalancerIP if redis metrics service type is `LoadBalancer` | `nil` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.namespace` | Optional namespace in which to create ServiceMonitor | `nil` | +| `metrics.serviceMonitor.interval` | Scrape interval. If not set, the Prometheus default scrape interval is used | `nil` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout. If not set, the Prometheus default scrape timeout is used | `nil` | +| `metrics.prometheusRule.enabled` | Set this to true to create prometheusRules for Prometheus operator | `false` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so prometheusRules will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.namespace` | namespace where prometheusRules resource should be created | the same namespace as postgresql | +| `metrics.prometheusRule.rules` | [rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) to be created, check values for an example. | `[]` | +| `metrics.image.registry` | PostgreSQL Exporter Image registry | `docker.io` | +| `metrics.image.repository` | PostgreSQL Exporter Image name | `bitnami/postgres-exporter` | +| `metrics.image.tag` | PostgreSQL Exporter Image tag | `{TAG_NAME}` | +| `metrics.image.pullPolicy` | PostgreSQL Exporter Image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `metrics.customMetrics` | Additional custom metrics | `nil` | +| `metrics.extraEnvVars` | Extra environment variables to add to exporter | `{}` (evaluated as a template) | +| `metrics.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `metrics.securityContext.enabled` | Enable security context for metrics | `false` | +| `metrics.securityContext.runAsUser` | User ID for the container for metrics | `1001` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `metrics.livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `metrics.readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 5 | +| `metrics.readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `updateStrategy` | Update strategy policy | `{type: "RollingUpdate"}` | +| `psp.create` | Create Pod Security Policy | `false` | +| `rbac.create` | Create Role and RoleBinding (required for PSP to work) | `false` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template). | `nil` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install my-release \ + --set postgresqlPassword=secretpassword,postgresqlDatabase=my-database \ + bitnami/postgresql +``` + +The above command sets the PostgreSQL `postgres` account password to `secretpassword`. Additionally it creates a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +$ helm install my-release -f values.yaml bitnami/postgresql +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) + +It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. + +Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. + +### Production configuration and horizontal scaling + +This chart includes a `values-production.yaml` file where you can find some parameters oriented to production configuration in comparison to the regular `values.yaml`. You can use this file instead of the default one. + +- Enable replication: +```diff +- replication.enabled: false ++ replication.enabled: true +``` + +- Number of read replicas: +```diff +- replication.readReplicas: 1 ++ replication.readReplicas: 2 +``` + +- Set synchronous commit mode: +```diff +- replication.synchronousCommit: "off" ++ replication.synchronousCommit: "on" +``` + +- Number of replicas that will have synchronous replication: +```diff +- replication.numSynchronousReplicas: 0 ++ replication.numSynchronousReplicas: 1 +``` + +- Start a prometheus exporter: +```diff +- metrics.enabled: false ++ metrics.enabled: true +``` + +To horizontally scale this chart, you can use the `--replicas` flag to modify the number of nodes in your PostgreSQL deployment. Also you can use the `values-production.yaml` file or modify the parameters shown above. + +### Customizing primary and read replica services in a replicated configuration + +At the top level, there is a service object which defines the services for both primary and readReplicas. For deeper customization, there are service objects for both the primary and read types individually. This allows you to override the values in the top level service object so that the primary and read can be of different service types and with different clusterIPs / nodePorts. Also in the case you want the primary and read to be of type nodePort, you will need to set the nodePorts to different values to prevent a collision. The values that are deeper in the primary.service or readReplicas.service objects will take precedence over the top level service object. + +### Change PostgreSQL version + +To modify the PostgreSQL version used in this chart you can specify a [valid image tag](https://hub.docker.com/r/bitnami/postgresql/tags/) using the `image.tag` parameter. For example, `image.tag=X.Y.Z`. This approach is also applicable to other images like exporters. + +### postgresql.conf / pg_hba.conf files as configMap + +This helm chart also supports to customize the whole configuration file. + +Add your custom file to "files/postgresql.conf" in your working directory. This file will be mounted as configMap to the containers and it will be used for configuring the PostgreSQL server. + +Alternatively, you can specify PostgreSQL configuration parameters using the `postgresqlConfiguration` parameter as a dict, using camelCase, e.g. {"sharedBuffers": "500MB"}. + +In addition to these options, you can also set an external ConfigMap with all the configuration files. This is done by setting the `configurationConfigMap` parameter. Note that this will override the two previous options. + +### Allow settings to be loaded from files other than the default `postgresql.conf` + +If you don't want to provide the whole PostgreSQL configuration file and only specify certain parameters, you can add your extended `.conf` files to "files/conf.d/" in your working directory. +Those files will be mounted as configMap to the containers adding/overwriting the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +Alternatively, you can also set an external ConfigMap with all the extra configuration files. This is done by setting the `extendedConfConfigMap` parameter. Note that this will override the previous option. + +### Initialize a fresh instance + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image allows you to use your custom scripts to initialize a fresh instance. In order to execute the scripts, they must be located inside the chart folder `files/docker-entrypoint-initdb.d` so they can be consumed as a ConfigMap. + +Alternatively, you can specify custom scripts using the `initdbScripts` parameter as dict. + +In addition to these options, you can also set an external ConfigMap with all the initialization scripts. This is done by setting the `initdbScriptsConfigMap` parameter. Note that this will override the two previous options. If your initialization scripts contain sensitive information such as credentials or passwords, you can use the `initdbScriptsSecret` parameter. + +The allowed extensions are `.sh`, `.sql` and `.sql.gz`. + +### Securing traffic using TLS + +TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the chart: + +- `tls.enabled`: Enable TLS support. Defaults to `false` +- `tls.certificatesSecret`: Name of an existing secret that contains the certificates. No defaults. +- `tls.certFilename`: Certificate filename. No defaults. +- `tls.certKeyFilename`: Certificate key filename. No defaults. + +For example: + +* First, create the secret with the cetificates files: + + ```console + kubectl create secret generic certificates-tls-secret --from-file=./cert.crt --from-file=./cert.key --from-file=./ca.crt + ``` + +* Then, use the following parameters: + + ```console + volumePermissions.enabled=true + tls.enabled=true + tls.certificatesSecret="certificates-tls-secret" + tls.certFilename="cert.crt" + tls.certKeyFilename="cert.key" + ``` + + > Note TLS and VolumePermissions: PostgreSQL requires certain permissions on sensitive files (such as certificate keys) to start up. Due to an on-going [issue](https://github.com/kubernetes/kubernetes/issues/57923) regarding kubernetes permissions and the use of `containerSecurityContext.runAsUser`, you must enable `volumePermissions` to ensure everything works as expected. + +### Sidecars + +If you need additional containers to run within the same pod as PostgreSQL (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +# For the PostgreSQL primary +primary: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +# For the PostgreSQL replicas +readReplicas: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +### Metrics + +The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9187) is not exposed and it is expected that the metrics are collected from inside the k8s cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). + +The exporter allows to create custom metrics from additional SQL queries. See the Chart's `values.yaml` for an example and consult the [exporters documentation](https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file) for more details. + +### Use of global variables + +In more complex scenarios, we may have the following tree of dependencies + +``` + +--------------+ + | | + +------------+ Chart 1 +-----------+ + | | | | + | --------+------+ | + | | | + | | | + | | | + | | | + v v v ++-------+------+ +--------+------+ +--------+------+ +| | | | | | +| PostgreSQL | | Sub-chart 1 | | Sub-chart 2 | +| | | | | | ++--------------+ +---------------+ +---------------+ +``` + +The three charts below depend on the parent chart Chart 1. However, subcharts 1 and 2 may need to connect to PostgreSQL as well. In order to do so, subcharts 1 and 2 need to know the PostgreSQL credentials, so one option for deploying could be deploy Chart 1 with the following parameters: + +``` +postgresql.postgresqlPassword=testtest +subchart1.postgresql.postgresqlPassword=testtest +subchart2.postgresql.postgresqlPassword=testtest +postgresql.postgresqlDatabase=db1 +subchart1.postgresql.postgresqlDatabase=db1 +subchart2.postgresql.postgresqlDatabase=db1 +``` + +If the number of dependent sub-charts increases, installing the chart with parameters can become increasingly difficult. An alternative would be to set the credentials using global variables as follows: + +``` +global.postgresql.postgresqlPassword=testtest +global.postgresql.postgresqlDatabase=db1 +``` + +This way, the credentials will be available in all of the subcharts. + +## Persistence + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image stores the PostgreSQL data and configurations at the `/bitnami/postgresql` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. +See the [Parameters](#parameters) section to configure the PVC or to disable persistence. + +If you already have data in it, you will fail to sync to standby nodes for all commits, details can refer to [code](https://github.com/bitnami/bitnami-docker-postgresql/blob/8725fe1d7d30ebe8d9a16e9175d05f7ad9260c93/9.6/debian-9/rootfs/libpostgresql.sh#L518-L556). If you need to use those data, please covert them to sql and import after `helm install` finished. + +## NetworkPolicy + +To enable network policy for PostgreSQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: + +```console +$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 5432. + +For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to PostgreSQL. +This label will be displayed in the output of a successful install. + +## Differences between Bitnami PostgreSQL image and [Docker Official](https://hub.docker.com/_/postgres) image + +- The Docker Official PostgreSQL image does not support replication. If you pass any replication environment variable, this would be ignored. The only environment variables supported by the Docker Official image are POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORD, POSTGRES_INITDB_ARGS, POSTGRES_INITDB_WALDIR and PGDATA. All the remaining environment variables are specific to the Bitnami PostgreSQL image. +- The Bitnami PostgreSQL image is non-root by default. This requires that you run the pod with `securityContext` and updates the permissions of the volume with an `initContainer`. A key benefit of this configuration is that the pod follows security best practices and is prepared to run on Kubernetes distributions with hard security constraints like OpenShift. +- For OpenShift, one may either define the runAsUser and fsGroup accordingly, or try this more dynamic option: volumePermissions.securityContext.runAsUser="auto",securityContext.enabled=false,containerSecurityContext.enabled=false,shmVolume.chmod.enabled=false + +### Deploy chart using Docker Official PostgreSQL Image + +From chart version 4.0.0, it is possible to use this chart with the Docker Official PostgreSQL image. +Besides specifying the new Docker repository and tag, it is important to modify the PostgreSQL data directory and volume mount point. Basically, the PostgreSQL data dir cannot be the mount point directly, it has to be a subdirectory. + +``` +image.repository=postgres +image.tag=10.6 +postgresqlDataDir=/data/pgdata +persistence.mountPath=/data/ +``` + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` paremeter(s). Find more infomation about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/master/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## Troubleshooting + +Find more information about how to deal with common errors related to Bitnami’s Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). + +## Upgrading + +It's necessary to specify the existing passwords while performing an upgrade to ensure the secrets are not updated with invalid randomly generated passwords. Remember to specify the existing values of the `postgresqlPassword` and `replication.password` parameters when upgrading the chart: + +```bash +$ helm upgrade my-release bitnami/postgresql \ + --set postgresqlPassword=[POSTGRESQL_PASSWORD] \ + --set replication.password=[REPLICATION_PASSWORD] +``` + +> Note: you need to substitute the placeholders _[POSTGRESQL_PASSWORD]_, and _[REPLICATION_PASSWORD]_ with the values obtained from instructions in the installation notes. + +### To 10.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Move dependency information from the *requirements.yaml* to the *Chart.yaml* +- After running `helm dependency update`, a *Chart.lock* file is generated containing the same structure used in the previous *requirements.lock* +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Chart. + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ + +#### Breaking changes + +- The term `master` has been replaced with `primary` and `slave` with `readReplicas` throughout the chart. Role names have changed from `master` and `slave` to `primary` and `read`. + +To upgrade to `10.0.0`, it should be done reusing the PVCs used to hold the PostgreSQL data on your previous release. To do so, follow the instructions below (the following example assumes that the release name is `postgresql`): + +> NOTE: Please, create a backup of your database before running any of those actions. + +Obtain the credentials and the names of the PVCs used to hold the PostgreSQL data on your current release: + +```console +$ export POSTGRESQL_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode) +$ export POSTGRESQL_PVC=$(kubectl get pvc -l app.kubernetes.io/instance=postgresql,role=master -o jsonpath="{.items[0].metadata.name}") +``` + +Delete the PostgreSQL statefulset. Notice the option `--cascade=false`: + +```console +$ kubectl delete statefulsets.apps postgresql-postgresql --cascade=false +``` + +Now the upgrade works: + +```console +$ helm upgrade postgresql bitnami/postgresql --set postgresqlPassword=$POSTGRESQL_PASSWORD --set persistence.existingClaim=$POSTGRESQL_PVC +``` + +You will have to delete the existing MariaDB pod and the new statefulset is going to create a new one + +```console +$ kubectl delete pod postgresql-postgresql-0 +``` + +Finally, you should see the lines below in MariaDB container logs: + +```console +$ kubectl logs $(kubectl get pods -l app.kubernetes.io/instance=postgresql,app.kubernetes.io/name=postgresql,role=primary -o jsonpath="{.items[0].metadata.name}") +... +postgresql 08:05:12.59 INFO ==> Deploying PostgreSQL with persisted data... +... +``` + +### To 9.0.0 + +In this version the chart was adapted to follow the Helm label best practices, see [PR 3021](https://github.com/bitnami/charts/pull/3021). That means the backward compatibility is not guarantee when upgrading the chart to this major version. + +As a workaround, you can delete the existing statefulset (using the `--cascade=false` flag pods are not deleted) before upgrade the chart. For example, this can be a valid workflow: + +- Deploy an old version (8.X.X) + +```console +$ helm install postgresql bitnami/postgresql --version 8.10.14 +``` + +- Old version is up and running + +```console +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 1 2020-08-04 13:39:54.783480286 +0000 UTC deployed postgresql-8.10.14 11.8.0 + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 76s +``` + +- The upgrade to the latest one (9.X.X) is going to fail + +```console +$ helm upgrade postgresql bitnami/postgresql +Error: UPGRADE FAILED: cannot patch "postgresql-postgresql" with kind StatefulSet: StatefulSet.apps "postgresql-postgresql" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden +``` + +- Delete the statefulset + +```console +$ kubectl delete statefulsets.apps --cascade=false postgresql-postgresql +statefulset.apps "postgresql-postgresql" deleted +``` + +- Now the upgrade works + +```console +$ helm upgrade postgresql bitnami/postgresql +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 3 2020-08-04 13:42:08.020385884 +0000 UTC deployed postgresql-9.1.2 11.8.0 +``` + +- We can kill the existing pod and the new statefulset is going to create a new one: + +```console +$ kubectl delete pod postgresql-postgresql-0 +pod "postgresql-postgresql-0" deleted + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 19s +``` + +Please, note that without the `--cascade=false` both objects (statefulset and pod) are going to be removed and both objects will be deployed again with the `helm upgrade` command + +### To 8.0.0 + +Prefixes the port names with their protocols to comply with Istio conventions. + +If you depend on the port names in your setup, make sure to update them to reflect this change. + +### To 7.1.0 + +Adds support for LDAP configuration. + +### To 7.0.0 + +Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. + +In https://github.com/helm/charts/pull/17281 the `apiVersion` of the statefulset resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. + +This major version bump signifies this change. + +### To 6.5.7 + +In this version, the chart will use PostgreSQL with the Postgis extension included. The version used with Postgresql version 10, 11 and 12 is Postgis 2.5. It has been compiled with the following dependencies: + +- protobuf +- protobuf-c +- json-c +- geos +- proj + +### To 5.0.0 + +In this version, the **chart is using PostgreSQL 11 instead of PostgreSQL 10**. You can find the main difference and notable changes in the following links: [https://www.postgresql.org/about/news/1894/](https://www.postgresql.org/about/news/1894/) and [https://www.postgresql.org/about/featurematrix/](https://www.postgresql.org/about/featurematrix/). + +For major releases of PostgreSQL, the internal data storage format is subject to change, thus complicating upgrades, you can see some errors like the following one in the logs: + +```console +Welcome to the Bitnami postgresql container +Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-postgresql +Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-postgresql/issues +Send us your feedback at containers@bitnami.com + +INFO ==> ** Starting PostgreSQL setup ** +NFO ==> Validating settings in POSTGRESQL_* env vars.. +INFO ==> Initializing PostgreSQL database... +INFO ==> postgresql.conf file not detected. Generating it... +INFO ==> pg_hba.conf file not detected. Generating it... +INFO ==> Deploying PostgreSQL with persisted data... +INFO ==> Configuring replication parameters +INFO ==> Loading custom scripts... +INFO ==> Enabling remote connections +INFO ==> Stopping PostgreSQL... +INFO ==> ** PostgreSQL setup finished! ** + +INFO ==> ** Starting PostgreSQL ** + [1] FATAL: database files are incompatible with server + [1] DETAIL: The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.3. +``` + +In this case, you should migrate the data from the old chart to the new one following an approach similar to that described in [this section](https://www.postgresql.org/docs/current/upgrading.html#UPGRADING-VIA-PGDUMPALL) from the official documentation. Basically, create a database dump in the old chart, move and restore it in the new one. + +### To 4.0.0 + +This chart will use by default the Bitnami PostgreSQL container starting from version `10.7.0-r68`. This version moves the initialization logic from node.js to bash. This new version of the chart requires setting the `POSTGRES_PASSWORD` in the slaves as well, in order to properly configure the `pg_hba.conf` file. Users from previous versions of the chart are advised to upgrade immediately. + +IMPORTANT: If you do not want to upgrade the chart version then make sure you use the `10.7.0-r68` version of the container. Otherwise, you will get this error + +``` +The POSTGRESQL_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development +``` + +### To 3.0.0 + +This releases make it possible to specify different nodeSelector, affinity and tolerations for master and slave pods. +It also fixes an issue with `postgresql.master.fullname` helper template not obeying fullnameOverride. + +#### Breaking changes + +- `affinty` has been renamed to `master.affinity` and `slave.affinity`. +- `tolerations` has been renamed to `master.tolerations` and `slave.tolerations`. +- `nodeSelector` has been renamed to `master.nodeSelector` and `slave.nodeSelector`. + +### To 2.0.0 + +In order to upgrade from the `0.X.X` branch to `1.X.X`, you should follow the below steps: + +- Obtain the service name (`SERVICE_NAME`) and password (`OLD_PASSWORD`) of the existing postgresql chart. You can find the instructions to obtain the password in the NOTES.txt, the service name can be obtained by running + +```console +$ kubectl get svc +``` + +- Install (not upgrade) the new version + +```console +$ helm repo update +$ helm install my-release bitnami/postgresql +``` + +- Connect to the new pod (you can obtain the name by running `kubectl get pods`): + +```console +$ kubectl exec -it NAME bash +``` + +- Once logged in, create a dump file from the previous database using `pg_dump`, for that we should connect to the previous postgresql chart: + +```console +$ pg_dump -h SERVICE_NAME -U postgres DATABASE_NAME > /tmp/backup.sql +``` + +After run above command you should be prompted for a password, this password is the previous chart password (`OLD_PASSWORD`). +This operation could take some time depending on the database size. + +- Once you have the backup file, you can restore it with a command like the one below: + +```console +$ psql -U postgres DATABASE_NAME < /tmp/backup.sql +``` + +In this case, you are accessing to the local postgresql, so the password should be the new one (you can find it in NOTES.txt). + +If you want to restore the database and the database schema does not exist, it is necessary to first follow the steps described below. + +```console +$ psql -U postgres +postgres=# drop database DATABASE_NAME; +postgres=# create database DATABASE_NAME; +postgres=# create user USER_NAME; +postgres=# alter role USER_NAME with password 'BITNAMI_USER_PASSWORD'; +postgres=# grant all privileges on database DATABASE_NAME to USER_NAME; +postgres=# alter database DATABASE_NAME owner to USER_NAME; +``` diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/.helmignore b/sample-cnfs/sample_secret_env/postgresql/charts/common/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/Chart.yaml b/sample-cnfs/sample_secret_env/postgresql/charts/common/Chart.yaml new file mode 100644 index 000000000..1bda8e2df --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 1.1.1 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://github.com/bitnami/charts/tree/master/bitnami/common +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- email: containers@bitnami.com + name: Bitnami +name: common +sources: +- https://github.com/bitnami/charts +- http://www.bitnami.com/ +type: library +version: 1.1.2 diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/README.md b/sample-cnfs/sample_secret_env/postgresql/charts/common/README.md new file mode 100644 index 000000000..a68895368 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/README.md @@ -0,0 +1,309 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 0.x.x + repository: https://charts.bitnami.com/bitnami +``` + +```bash +$ helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ + +## Parameters + +The following table lists the helpers available in the library which are scoped in different sections. + +### Affinities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.node.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.pod.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.pod.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | + +### Capabilities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.capabilities.deployment.apiVersion` | Return the appropriate apiVersion for deployment. | `.` Chart context | +| `common.capabilities.statefulset.apiVersion` | Return the appropriate apiVersion for statefulset. | `.` Chart context | +| `common.capabilities.ingress.apiVersion` | Return the appropriate apiVersion for ingress. | `.` Chart context | + +### Errors + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.errors.upgrade.passwords.empty` | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01) "context" $` | + +### Images + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.images.image` | Return the proper and full image name | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure. | +| `common.images.pullSecrets` | Return the proper Docker Image Registry Secret Names | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global` | + +### Labels + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.labels.standard` | Return Kubernetes standard labels | `.` Chart context | +| `common.labels.matchLabels` | Return the proper Docker Image Registry Secret Names | `.` Chart context | + +### Names + +| Helper identifier | Description | Expected Inpput | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.names.name` | Expand the name of the chart or use `.Values.nameOverride` | `.` Chart context | +| `common.names.fullname` | Create a default fully qualified app name. | `.` Chart context | +| `common.names.chart` | Chart name plus version | `.` Chart context | + +### Secrets + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.secrets.name` | Generate the name of the secret. | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.key` | Generate secret key. | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure. | + +### Storage + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. | + +### TplValues + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.tplvalues.render` | Renders a value that contains template | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frecuently is the chart context `$` or `.` | + +### Utils + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.utils.fieldToEnvVar` | Build environment variable name given a field. | `dict "field" "my-password"` | +| `common.utils.secret.getvalue` | Print instructions to get a secret value. | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` | +| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path | `dict "key" "path.to.key" "context" $` | + +### Validations + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.validations.values.single.empty` | Validate a value must not be empty. | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "context" $` secret and field are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) | +| `common.validations.values.multiple.empty` | Validate a multiple values must not be empty. It returns a shared error for all the values. | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue) | +| `common.validations.values.mariadb.passwords` | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values. | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mariadb chart and the helper. | +| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values. | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper. | +| `common.validations.values.redis.passwords` | This helper will ensure required password for Redis are not empty. It returns a shared error for all the values. | `dict "secret" "redis-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use redis chart and the helper. | +| `common.validations.values.cassandra.passwords` | This helper will ensure required password for Cassandra are not empty. It returns a shared error for all the values. | `dict "secret" "cassandra-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use cassandra chart and the helper. | +| `common.validations.values.mongodb.passwords` | This helper will ensure required password for MongoDB are not empty. It returns a shared error for all the values. | `dict "secret" "mongodb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mongodb chart and the helper. | + +### Warnings + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.warnings.rollingTag` | Warning about using rolling tag. | `ImageRoot` see [ImageRoot](#imageroot) for the structure. | + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets. + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possiblity of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +$ helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 --decode) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 --decode) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_affinities.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_affinities.tpl new file mode 100644 index 000000000..1ff26d585 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_affinities.tpl @@ -0,0 +1,94 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname + weight: 1 +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_capabilities.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_capabilities.tpl new file mode 100644 index 000000000..143bef2a4 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_capabilities.tpl @@ -0,0 +1,33 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_errors.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_errors.tpl new file mode 100644 index 000000000..d6d3ec65a --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_errors.tpl @@ -0,0 +1,20 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: you must provide your current passwords when upgrade the release%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_images.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_images.tpl new file mode 100644 index 000000000..aafde9f3b --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_images.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $tag := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_labels.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_labels.tpl new file mode 100644 index 000000000..252066c7e --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_labels.tpl @@ -0,0 +1,18 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Kubernetes standard labels +*/}} +{{- define "common.labels.standard" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector +*/}} +{{- define "common.labels.matchLabels" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_names.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_names.tpl new file mode 100644 index 000000000..adf2a74f4 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_names.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "common.names.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_secrets.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_secrets.tpl new file mode 100644 index 000000000..ebfb5d42d --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_secrets.tpl @@ -0,0 +1,57 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- $name = .name -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_storage.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_storage.tpl new file mode 100644 index 000000000..60e2a844f --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_storage.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} + +{{- $storageClass := .persistence.storageClass -}} +{{- if .global -}} + {{- if .global.storageClass -}} + {{- $storageClass = .global.storageClass -}} + {{- end -}} +{{- end -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_tplvalues.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_tplvalues.tpl new file mode 100644 index 000000000..2db166851 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,13 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "common.tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_utils.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_utils.tpl new file mode 100644 index 000000000..74774a3ca --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_utils.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_warnings.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_warnings.tpl new file mode 100644 index 000000000..ae10fa41e --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/_warnings.tpl @@ -0,0 +1,14 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ +{{- end }} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_cassandra.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 000000000..7a274a08c --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mariadb.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 000000000..3bf669dd8 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mongodb.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 000000000..7e0c1cbc3 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,108 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (not $existingSecret) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_postgresql.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 000000000..f25e0ffbf --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,131 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_redis.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_redis.tpl new file mode 100644 index 000000000..2ccc04d2d --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,72 @@ + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $existingSecret := include "common.redis.values.existingSecret" . -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $valueKeyRedisPassword := printf "%s%s" $valueKeyPrefix "password" -}} + {{- $valueKeyRedisUsePassword := printf "%s%s" $valueKeyPrefix "usePassword" -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $usePassword := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUsePassword "context" .context) -}} + {{- if eq $usePassword "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Redis Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.redis.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.redis.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_validations.tpl b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_validations.tpl new file mode 100644 index 000000000..d4cf32c77 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,44 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s=$%s' to the command.%s" .valueKey .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/charts/common/values.yaml b/sample-cnfs/sample_secret_env/postgresql/charts/common/values.yaml new file mode 100644 index 000000000..9ecdc93f5 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/charts/common/values.yaml @@ -0,0 +1,3 @@ +## bitnami/common +## It is required by CI/CD tools and processes. +exampleValue: common-chart diff --git a/sample-cnfs/sample_secret_env/postgresql/ci/commonAnnotations.yaml b/sample-cnfs/sample_secret_env/postgresql/ci/commonAnnotations.yaml new file mode 100644 index 000000000..97e18a4cc --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/ci/commonAnnotations.yaml @@ -0,0 +1,3 @@ +commonAnnotations: + helm.sh/hook: "\"pre-install, pre-upgrade\"" + helm.sh/hook-weight: "-1" diff --git a/sample-cnfs/sample_secret_env/postgresql/ci/default-values.yaml b/sample-cnfs/sample_secret_env/postgresql/ci/default-values.yaml new file mode 100644 index 000000000..fc2ba605a --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/ci/default-values.yaml @@ -0,0 +1 @@ +# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml. diff --git a/sample-cnfs/sample_secret_env/postgresql/ci/shmvolume-disabled-values.yaml b/sample-cnfs/sample_secret_env/postgresql/ci/shmvolume-disabled-values.yaml new file mode 100644 index 000000000..347d3b40a --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/ci/shmvolume-disabled-values.yaml @@ -0,0 +1,2 @@ +shmVolume: + enabled: false diff --git a/sample-cnfs/sample_secret_env/postgresql/files/README.md b/sample-cnfs/sample_secret_env/postgresql/files/README.md new file mode 100644 index 000000000..1813a2fea --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/files/README.md @@ -0,0 +1 @@ +Copy here your postgresql.conf and/or pg_hba.conf files to use it as a config map. diff --git a/sample-cnfs/sample_secret_env/postgresql/files/conf.d/README.md b/sample-cnfs/sample_secret_env/postgresql/files/conf.d/README.md new file mode 100644 index 000000000..184c1875d --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/files/conf.d/README.md @@ -0,0 +1,4 @@ +If you don't want to provide the whole configuration file and only specify certain parameters, you can copy here your extended `.conf` files. +These files will be injected as a config maps and add/overwrite the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +More info in the [bitnami-docker-postgresql README](https://github.com/bitnami/bitnami-docker-postgresql#configuration-file). diff --git a/sample-cnfs/sample_secret_env/postgresql/files/docker-entrypoint-initdb.d/README.md b/sample-cnfs/sample_secret_env/postgresql/files/docker-entrypoint-initdb.d/README.md new file mode 100644 index 000000000..cba38091e --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/files/docker-entrypoint-initdb.d/README.md @@ -0,0 +1,3 @@ +You can copy here your custom `.sh`, `.sql` or `.sql.gz` file so they are executed during the first boot of the image. + +More info in the [bitnami-docker-postgresql](https://github.com/bitnami/bitnami-docker-postgresql#initializing-a-new-instance) repository. \ No newline at end of file diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/NOTES.txt b/sample-cnfs/sample_secret_env/postgresql/templates/NOTES.txt new file mode 100644 index 000000000..4e98958c1 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/NOTES.txt @@ -0,0 +1,59 @@ +** Please be patient while the chart is being deployed ** + +PostgreSQL can be accessed via port {{ template "postgresql.port" . }} on the following DNS name from within your cluster: + + {{ template "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - Read/Write connection +{{- if .Values.replication.enabled }} + {{ template "common.names.fullname" . }}-read.{{ .Release.Namespace }}.svc.cluster.local - Read only connection +{{- end }} + +{{- if not (eq (include "postgresql.username" .) "postgres") }} + +To get the password for "postgres" run: + + export POSTGRES_ADMIN_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-postgres-password}" | base64 --decode) +{{- end }} + +To get the password for "{{ template "postgresql.username" . }}" run: + + export POSTGRES_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-password}" | base64 --decode) + +To connect to your database run the following command: + + kubectl run {{ template "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --namespace {{ .Release.Namespace }} --image {{ template "postgresql.image" . }} --env="PGPASSWORD=$POSTGRES_PASSWORD" {{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} + --labels="{{ template "common.names.fullname" . }}-client=true" {{- end }} --command -- psql --host {{ template "common.names.fullname" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to this PostgreSQL cluster. +{{- end }} + +To connect to your database from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $NODE_IP --port $NODE_PORT -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $SERVICE_IP --port {{ template "postgresql.port" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "common.names.fullname" . }} {{ template "postgresql.port" . }}:{{ template "postgresql.port" . }} & + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host 127.0.0.1 -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{- end }} + +{{- include "postgresql.validateValues" . -}} + +{{- include "common.warnings.rollingTag" .Values.image -}} + +{{- $passwordValidationErrors := include "common.validations.values.postgresql.passwords" (dict "secret" (include "common.names.fullname" .) "context" $) -}} + +{{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $passwordValidationErrors) "context" $) -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/_helpers.tpl b/sample-cnfs/sample_secret_env/postgresql/templates/_helpers.tpl new file mode 100644 index 000000000..7509941cf --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/_helpers.tpl @@ -0,0 +1,330 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "postgresql.primary.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- $fullname := default (printf "%s-%s" .Release.Name $name) .Values.fullnameOverride -}} +{{- if .Values.replication.enabled -}} +{{- printf "%s-%s" $fullname "primary" | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $fullname | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper PostgreSQL image name +*/}} +{{- define "postgresql.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper PostgreSQL metrics image name +*/}} +{{- define "postgresql.metrics.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "postgresql.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "postgresql.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Return PostgreSQL postgres user password +*/}} +{{- define "postgresql.postgres.password" -}} +{{- if .Values.global.postgresql.postgresqlPostgresPassword }} + {{- .Values.global.postgresql.postgresqlPostgresPassword -}} +{{- else if .Values.postgresqlPostgresPassword -}} + {{- .Values.postgresqlPostgresPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL password +*/}} +{{- define "postgresql.password" -}} +{{- if .Values.global.postgresql.postgresqlPassword }} + {{- .Values.global.postgresql.postgresqlPassword -}} +{{- else if .Values.postgresqlPassword -}} + {{- .Values.postgresqlPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication password +*/}} +{{- define "postgresql.replication.password" -}} +{{- if .Values.global.postgresql.replicationPassword }} + {{- .Values.global.postgresql.replicationPassword -}} +{{- else if .Values.replication.password -}} + {{- .Values.replication.password -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL username +*/}} +{{- define "postgresql.username" -}} +{{- if .Values.global.postgresql.postgresqlUsername }} + {{- .Values.global.postgresql.postgresqlUsername -}} +{{- else -}} + {{- .Values.postgresqlUsername -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication username +*/}} +{{- define "postgresql.replication.username" -}} +{{- if .Values.global.postgresql.replicationUser }} + {{- .Values.global.postgresql.replicationUser -}} +{{- else -}} + {{- .Values.replication.user -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL port +*/}} +{{- define "postgresql.port" -}} +{{- if .Values.global.postgresql.servicePort }} + {{- .Values.global.postgresql.servicePort -}} +{{- else -}} + {{- .Values.service.port -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL created database +*/}} +{{- define "postgresql.database" -}} +{{- if .Values.global.postgresql.postgresqlDatabase }} + {{- .Values.global.postgresql.postgresqlDatabase -}} +{{- else if .Values.postgresqlDatabase -}} + {{- .Values.postgresqlDatabase -}} +{{- end -}} +{{- end -}} + +{{/* +Get the password secret. +*/}} +{{- define "postgresql.secretName" -}} +{{- if .Values.global.postgresql.existingSecret }} + {{- printf "%s" (tpl .Values.global.postgresql.existingSecret $) -}} +{{- else if .Values.existingSecret -}} + {{- printf "%s" (tpl .Values.existingSecret $) -}} +{{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if we should use an existingSecret. +*/}} +{{- define "postgresql.useExistingSecret" -}} +{{- if or .Values.global.postgresql.existingSecret .Values.existingSecret -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created +*/}} +{{- define "postgresql.createSecret" -}} +{{- if not (include "postgresql.useExistingSecret" .) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the configuration ConfigMap name. +*/}} +{{- define "postgresql.configurationCM" -}} +{{- if .Values.configurationConfigMap -}} +{{- printf "%s" (tpl .Values.configurationConfigMap $) -}} +{{- else -}} +{{- printf "%s-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the extended configuration ConfigMap name. +*/}} +{{- define "postgresql.extendedConfigurationCM" -}} +{{- if .Values.extendedConfConfigMap -}} +{{- printf "%s" (tpl .Values.extendedConfConfigMap $) -}} +{{- else -}} +{{- printf "%s-extended-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap should be mounted with PostgreSQL configuration +*/}} +{{- define "postgresql.mountConfigurationCM" -}} +{{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "postgresql.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts Secret name. +*/}} +{{- define "postgresql.initdbScriptsSecret" -}} +{{- printf "%s" (tpl .Values.initdbScriptsSecret $) -}} +{{- end -}} + +{{/* +Get the metrics ConfigMap name. +*/}} +{{- define "postgresql.metricsCM" -}} +{{- printf "%s-metrics" (include "common.names.fullname" .) -}} +{{- end -}} + +{{/* +Get the readiness probe command +*/}} +{{- define "postgresql.readinessProbeCommand" -}} +- | +{{- if (include "postgresql.database" .) }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- else }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- end }} +{{- if contains "bitnami/" .Values.image.repository }} + [ -f /opt/bitnami/postgresql/tmp/.initialized ] || [ -f /bitnami/postgresql/.initialized ] +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "postgresql.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "postgresql.validateValues.ldapConfigurationMethod" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.psp" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If ldap.url is used then you don't need the other settings for ldap +*/}} +{{- define "postgresql.validateValues.ldapConfigurationMethod" -}} +{{- if and .Values.ldap.enabled (and (not (empty .Values.ldap.url)) (not (empty .Values.ldap.server))) }} +postgresql: ldap.url, ldap.server + You cannot set both `ldap.url` and `ldap.server` at the same time. + Please provide a unique way to configure LDAP. + More info at https://www.postgresql.org/docs/current/auth-ldap.html +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If PSP is enabled RBAC should be enabled too +*/}} +{{- define "postgresql.validateValues.psp" -}} +{{- if and .Values.psp.create (not .Values.rbac.create) }} +postgresql: psp.create, rbac.create + RBAC should be enabled if PSP is enabled in order for PSP to work. + More info at https://kubernetes.io/docs/concepts/policy/pod-security-policy/#authorizing-policies +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- if semverCompare "<1.10-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "postgresql.networkPolicy.apiVersion" -}} +{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"extensions/v1beta1" +{{- else if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"networking.k8s.io/v1" +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql TLS - When TLS is enabled, so must be VolumePermissions +*/}} +{{- define "postgresql.validateValues.tls" -}} +{{- if and .Values.tls.enabled (not .Values.volumePermissions.enabled) }} +postgresql: tls.enabled, volumePermissions.enabled + When TLS is enabled you must enable volumePermissions as well to ensure certificates files have + the right permissions. +{{- end -}} +{{- end -}} + +{{/* +Return the path to the cert file. +*/}} +{{- define "postgresql.tlsCert" -}} +{{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the cert key file. +*/}} +{{- define "postgresql.tlsCertKey" -}} +{{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the CA cert file. +*/}} +{{- define "postgresql.tlsCACert" -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.certCAFilename -}} +{{- end -}} + +{{/* +Return the path to the CRL file. +*/}} +{{- define "postgresql.tlsCRL" -}} +{{- if .Values.tls.crlFilename -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.crlFilename -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/configmap.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/configmap.yaml new file mode 100644 index 000000000..4508f95a4 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{ if and (or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration) (not .Values.configurationConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- if (.Files.Glob "files/postgresql.conf") }} +{{ (.Files.Glob "files/postgresql.conf").AsConfig | indent 2 }} +{{- else if .Values.postgresqlConfiguration }} + postgresql.conf: | +{{- range $key, $value := default dict .Values.postgresqlConfiguration }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- if (.Files.Glob "files/pg_hba.conf") }} +{{ (.Files.Glob "files/pg_hba.conf").AsConfig | indent 2 }} +{{- else if .Values.pgHbaConfiguration }} + pg_hba.conf: | +{{ .Values.pgHbaConfiguration | indent 4 }} +{{- end }} +{{ end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/extended-config-configmap.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/extended-config-configmap.yaml new file mode 100644 index 000000000..5ccdb08f8 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/extended-config-configmap.yaml @@ -0,0 +1,21 @@ +{{- if and (or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf) (not .Values.extendedConfConfigMap)}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-extended-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- with .Files.Glob "files/conf.d/*.conf" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{ with .Values.postgresqlExtendedConf }} + override.conf: | +{{- range $key, $value := . }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/extra-list.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/extra-list.yaml new file mode 100644 index 000000000..9ac65f9e1 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/initialization-configmap.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/initialization-configmap.yaml new file mode 100644 index 000000000..074ed5827 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/initialization-configmap.yaml @@ -0,0 +1,24 @@ +{{- if and (or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScripts) (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-init-scripts + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.sql.gz" }} +binaryData: +{{- range $path, $bytes := . }} + {{ base $path }}: {{ $.Files.Get $path | b64enc | quote }} +{{- end }} +{{- end }} +data: +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql}" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{- with .Values.initdbScripts }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/metrics-configmap.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/metrics-configmap.yaml new file mode 100644 index 000000000..6216eca84 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/metrics-configmap.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "postgresql.metricsCM" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + custom-metrics.yaml: {{ toYaml .Values.metrics.customMetrics | quote }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/metrics-svc.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/metrics-svc.yaml new file mode 100644 index 000000000..a8f7b3310 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/metrics-svc.yaml @@ -0,0 +1,25 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-metrics + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- toYaml .Values.metrics.service.annotations | nindent 4 }} +spec: + type: {{ .Values.metrics.service.type }} + {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }} + {{- end }} + ports: + - name: http-metrics + port: 9187 + targetPort: http-metrics + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/networkpolicy.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/networkpolicy.yaml new file mode 100644 index 000000000..ef48ba182 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/networkpolicy.yaml @@ -0,0 +1,38 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "postgresql.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + ingress: + # Allow inbound connections + - ports: + - port: {{ template "postgresql.port" . }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: +{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + role: read + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow prometheus scrapes + - ports: + - port: 9187 + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..a79ebf163 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/podsecuritypolicy.yaml @@ -0,0 +1,37 @@ +{{- if .Values.psp.create }} +apiVersion: {{ include "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + privileged: false + volumes: + - 'configMap' + - 'secret' + - 'persistentVolumeClaim' + - 'emptyDir' + - 'projected' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/prometheusrule.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/prometheusrule.yaml new file mode 100644 index 000000000..d0f408c78 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/prometheusrule.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "common.names.fullname" . }} +{{- with .Values.metrics.prometheusRule.namespace }} + namespace: {{ . }} +{{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- with .Values.metrics.prometheusRule.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: +{{- with .Values.metrics.prometheusRule.rules }} + groups: + - name: {{ template "postgresql.name" $ }} + rules: {{ tpl (toYaml .) $ | nindent 8 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/role.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/role.yaml new file mode 100644 index 000000000..5a6de3350 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/role.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + {{- if .Values.psp.create }} + - apiGroups: ["extensions"] + resources: ["podsecuritypolicies"] + verbs: ["use"] + resourceNames: + - {{ template "common.names.fullname" . }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/rolebinding.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/rolebinding.yaml new file mode 100644 index 000000000..2bdb1c5ea --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + kind: Role + name: {{ template "common.names.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/secrets.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/secrets.yaml new file mode 100644 index 000000000..8351cbe8b --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/secrets.yaml @@ -0,0 +1,21 @@ +{{- if (include "postgresql.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + postgresql-postgres-password: {{ include "postgresql.postgres.password" . | b64enc | quote }} + postgresql-password: {{ include "postgresql.password" . | b64enc | quote }} + {{- if .Values.replication.enabled }} + postgresql-replication-password: {{ include "postgresql.replication.password" . | b64enc | quote }} + {{- end }} + {{- if (and .Values.ldap.enabled .Values.ldap.bind_password)}} + postgresql-ldap-password: {{ .Values.ldap.bind_password | b64enc | quote }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/serviceaccount.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/serviceaccount.yaml new file mode 100644 index 000000000..8cba31e43 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if and (.Values.serviceAccount.enabled) (not .Values.serviceAccount.name) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "common.labels.standard" . | nindent 4 }} + name: {{ template "common.names.fullname" . }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/servicemonitor.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/servicemonitor.yaml new file mode 100644 index 000000000..587ce85b8 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} + {{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + +spec: + endpoints: + - port: http-metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/statefulset-readreplicas.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/statefulset-readreplicas.yaml new file mode 100644 index 000000000..1f5b97043 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/statefulset-readreplicas.yaml @@ -0,0 +1,410 @@ +{{- if .Values.replication.enabled }} +{{- $readReplicasResources := coalesce .Values.readReplicas.resources .Values.resources -}} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: "{{ template "common.names.fullname" . }}-read" + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: read +{{- with .Values.readReplicas.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.readReplicas.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: {{ .Values.replication.readReplicas }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: read + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: read + role: read +{{- with .Values.readReplicas.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.readReplicas.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.readReplicas.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAffinityPreset "component" "read" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAntiAffinityPreset "component" "read" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.readReplicas.nodeAffinityPreset.type "key" .Values.readReplicas.nodeAffinityPreset.key "values" .Values.readReplicas.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.readReplicas.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.readReplicas.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name}} + {{- end }} + {{- if or .Values.readReplicas.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{ if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.readReplicas.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.readReplicas.priorityClassName }} + priorityClassName: {{ .Values.readReplicas.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if $readReplicasResources }} + resources: {{- toYaml $readReplicasResources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + - name: POSTGRES_REPLICATION_MODE + value: "slave" + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + - name: POSTGRES_MASTER_HOST + value: {{ template "common.names.fullname" . }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ include "postgresql.port" . | quote }} + {{- if and (not (eq .Values.postgresqlUsername "postgres")) (or .Values.postgresqlPostgresPassword (include "postgresql.useExistingSecret" .)) }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{ end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.readReplicas.extraVolumeMounts }} + {{- toYaml .Values.readReplicas.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.readReplicas.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.sidecars "context" $ ) | nindent 8 }} +{{- end }} + volumes: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} + {{- if or (not .Values.persistence.enabled) (not .Values.readReplicas.persistence.enabled) }} + - name: data + emptyDir: {} + {{- end }} + {{- if .Values.readReplicas.extraVolumes }} + {{- toYaml .Values.readReplicas.extraVolumes | nindent 8 }} + {{- end }} + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} +{{- if and .Values.persistence.enabled .Values.readReplicas.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/statefulset.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/statefulset.yaml new file mode 100644 index 000000000..1c1d2dbac --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/statefulset.yaml @@ -0,0 +1,589 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "postgresql.primary.fullname" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- with .Values.primary.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.primary.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: 1 + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: primary + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + role: primary + app.kubernetes.io/component: primary + {{- with .Values.primary.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.primary.podAnnotations }} + annotations: {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.primary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.primary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAffinityPreset "component" "primary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "component" "primary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.primary.nodeAffinityPreset.type "key" .Values.primary.nodeAffinityPreset.key "values" .Values.primary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.primary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.primary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + {{- end }} + {{- if or .Values.primary.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.primary.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.primary.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + {{- if .Values.postgresqlInitdbArgs }} + - name: POSTGRES_INITDB_ARGS + value: {{ .Values.postgresqlInitdbArgs | quote }} + {{- end }} + {{- if .Values.postgresqlInitdbWalDir }} + - name: POSTGRES_INITDB_WALDIR + value: {{ .Values.postgresqlInitdbWalDir | quote }} + {{- end }} + {{- if .Values.initdbUser }} + - name: POSTGRESQL_INITSCRIPTS_USERNAME + value: {{ .Values.initdbUser }} + {{- end }} + {{- if .Values.initdbPassword }} + - name: POSTGRESQL_INITSCRIPTS_PASSWORD + value: {{ .Values.initdbPassword }} + {{- end }} + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + {{- if .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_MASTER_HOST + value: {{ .Values.primaryAsStandBy.primaryHost }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ .Values.primaryAsStandBy.primaryPort | quote }} + {{- end }} + {{- if or .Values.replication.enabled .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_REPLICATION_MODE + {{- if .Values.primaryAsStandBy.enabled }} + value: "slave" + {{- else }} + value: "master" + {{- end }} + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + {{- if not (eq .Values.replication.synchronousCommit "off")}} + - name: POSTGRES_SYNCHRONOUS_COMMIT_MODE + value: {{ .Values.replication.synchronousCommit | quote }} + - name: POSTGRES_NUM_SYNCHRONOUS_REPLICAS + value: {{ .Values.replication.numSynchronousReplicas | quote }} + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + {{- end }} + {{- if not (eq (include "postgresql.username" .) "postgres") }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + - name: POSTGRES_USER + value: {{ include "postgresql.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + {{- if (include "postgresql.database" .) }} + - name: POSTGRES_DB + value: {{ (include "postgresql.database" .) | quote }} + {{- end }} + {{- if .Values.extraEnv }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnv "context" $) | nindent 12 }} + {{- end }} + - name: POSTGRESQL_ENABLE_LDAP + value: {{ ternary "yes" "no" .Values.ldap.enabled | quote }} + {{- if .Values.ldap.enabled }} + - name: POSTGRESQL_LDAP_SERVER + value: {{ .Values.ldap.server }} + - name: POSTGRESQL_LDAP_PORT + value: {{ .Values.ldap.port | quote }} + - name: POSTGRESQL_LDAP_SCHEME + value: {{ .Values.ldap.scheme }} + {{- if .Values.ldap.tls }} + - name: POSTGRESQL_LDAP_TLS + value: "1" + {{- end }} + - name: POSTGRESQL_LDAP_PREFIX + value: {{ .Values.ldap.prefix | quote }} + - name: POSTGRESQL_LDAP_SUFFIX + value: {{ .Values.ldap.suffix | quote }} + - name: POSTGRESQL_LDAP_BASE_DN + value: {{ .Values.ldap.baseDN }} + - name: POSTGRESQL_LDAP_BIND_DN + value: {{ .Values.ldap.bindDN }} + {{- if (not (empty .Values.ldap.bind_password)) }} + - name: POSTGRESQL_LDAP_BIND_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-ldap-password + {{- end}} + - name: POSTGRESQL_LDAP_SEARCH_ATTR + value: {{ .Values.ldap.search_attr }} + - name: POSTGRESQL_LDAP_SEARCH_FILTER + value: {{ .Values.ldap.search_filter }} + - name: POSTGRESQL_LDAP_URL + value: {{ .Values.ldap.url }} + {{- end}} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + {{- if .Values.extraEnvVarsCM }} + envFrom: + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d/ + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + mountPath: /docker-entrypoint-initdb.d/secret + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.primary.extraVolumeMounts }} + {{- toYaml .Values.primary.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.primary.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.primary.sidecars "context" $ ) | nindent 8 }} +{{- end }} +{{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "postgresql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.securityContext.enabled }} + securityContext: {{- omit .Values.metrics.securityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- $database := required "In order to enable metrics you need to specify a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase)" (include "postgresql.database" .) }} + {{- $sslmode := ternary "require" "disable" .Values.tls.enabled }} + {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} + - name: DATA_SOURCE_NAME + value: {{ printf "host=127.0.0.1 port=%d user=%s sslmode=%s sslcert=%s sslkey=%s" (int (include "postgresql.port" .)) (include "postgresql.username" .) $sslmode (include "postgresql.tlsCert" .) (include "postgresql.tlsCertKey" .) }} + {{- else }} + - name: DATA_SOURCE_URI + value: {{ printf "127.0.0.1:%d/%s?sslmode=%s" (int (include "postgresql.port" .)) $database $sslmode }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: DATA_SOURCE_PASS_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: DATA_SOURCE_PASS + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: DATA_SOURCE_USER + value: {{ template "postgresql.username" . }} + {{- if .Values.metrics.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.metrics.customMetrics }} + - name: custom-metrics + mountPath: /conf + readOnly: true + args: ["--extend.query-path", "/conf/custom-metrics.yaml"] + {{- end }} + ports: + - name: http-metrics + containerPort: 9187 + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} +{{- end }} + volumes: + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "postgresql.initdbScriptsCM" . }} + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + secret: + secretName: {{ template "postgresql.initdbScriptsSecret" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.primary.extraVolumes }} + {{- toYaml .Values.primary.extraVolumes | nindent 8 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} + - name: custom-metrics + configMap: + name: {{ template "postgresql.metricsCM" . }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} +{{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: +{{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} +{{- end }} +{{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} +{{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/svc-headless.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/svc-headless.yaml new file mode 100644 index 000000000..6ad0dd5f2 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/svc-headless.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-headless + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + # Use this annotation in addition to the actual publishNotReadyAddresses + # field below because the annotation will stop being respected soon but the + # field is broken in some versions of Kubernetes: + # https://github.com/kubernetes/kubernetes/issues/58662 + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +spec: + type: ClusterIP + clusterIP: None + # We want all pods in the StatefulSet to have their addresses published for + # the sake of the other Postgresql pods even before they're ready, since they + # have to be able to talk to each other in order to become ready. + publishNotReadyAddresses: true + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/svc-read.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/svc-read.yaml new file mode 100644 index 000000000..8c9ea54e8 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/svc-read.yaml @@ -0,0 +1,42 @@ +{{- if .Values.replication.enabled }} +{{- $serviceAnnotations := coalesce .Values.readReplicas.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.readReplicas.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.readReplicas.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.readReplicas.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.readReplicas.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.readReplicas.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-read + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: read +{{- end }} diff --git a/sample-cnfs/sample_secret_env/postgresql/templates/svc.yaml b/sample-cnfs/sample_secret_env/postgresql/templates/svc.yaml new file mode 100644 index 000000000..5bc2b50ee --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/templates/svc.yaml @@ -0,0 +1,40 @@ +{{- $serviceAnnotations := coalesce .Values.primary.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.primary.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.primary.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.primary.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.primary.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.primary.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary diff --git a/sample-cnfs/sample_secret_env/postgresql/values-production.yaml b/sample-cnfs/sample_secret_env/postgresql/values-production.yaml new file mode 100644 index 000000000..4e1ee0416 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/values-production.yaml @@ -0,0 +1,791 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: true + user: repl_user + password: repl_password + readReplicas: 2 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + ## + synchronousCommit: "on" + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + ## + numSynchronousReplicas: 1 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +## existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +# usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: "" + server: "" + port: "" + prefix: "" + suffix: "" + baseDN: "" + bindDN: "" + bind_password: + search_attr: "" + search_filter: "" + scheme: "" + tls: {} + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read replica(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: "" + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Additional PostgreSQL Primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL Read Only Replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + ## Additional PostgreSQL Read Replica Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Read Replica Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Read Replicas + ## + service: {} + # type: + # nodePort: + # clusterIP: + ## Whether to enable PostgreSQL readReplicas replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for readReplicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: "" + # + # Certificate filename + certFilename: "" + # + # Certificate Key filename + certKeyFilename: "" + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: true + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9187" + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 diff --git a/sample-cnfs/sample_secret_env/postgresql/values.schema.json b/sample-cnfs/sample_secret_env/postgresql/values.schema.json new file mode 100644 index 000000000..66a2a9dd0 --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/values.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "postgresqlUsername": { + "type": "string", + "title": "Admin user", + "form": true + }, + "postgresqlPassword": { + "type": "string", + "title": "Password", + "form": true + }, + "persistence": { + "type": "object", + "properties": { + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi" + } + } + }, + "resources": { + "type": "object", + "title": "Required Resources", + "description": "Configure resource requests", + "form": true, + "properties": { + "requests": { + "type": "object", + "properties": { + "memory": { + "type": "string", + "form": true, + "render": "slider", + "title": "Memory Request", + "sliderMin": 10, + "sliderMax": 2048, + "sliderUnit": "Mi" + }, + "cpu": { + "type": "string", + "form": true, + "render": "slider", + "title": "CPU Request", + "sliderMin": 10, + "sliderMax": 2000, + "sliderUnit": "m" + } + } + } + } + }, + "replication": { + "type": "object", + "form": true, + "title": "Replication Details", + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable Replication", + "form": true + }, + "readReplicas": { + "type": "integer", + "title": "read Replicas", + "form": true, + "hidden": { + "value": false, + "path": "replication/enabled" + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable Init Containers", + "description": "Change the owner of the persist volume mountpoint to RunAsUser:fsGroup" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "title": "Configure metrics exporter", + "form": true + } + } + } + } +} diff --git a/sample-cnfs/sample_secret_env/postgresql/values.yaml b/sample-cnfs/sample_secret_env/postgresql/values.yaml new file mode 100644 index 000000000..4ef9ad1ba --- /dev/null +++ b/sample-cnfs/sample_secret_env/postgresql/values.yaml @@ -0,0 +1,813 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: false + user: repl_user + password: repl_password + readReplicas: 1 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + synchronousCommit: 'off' + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + numSynchronousReplicas: 0 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +# existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: '' + server: '' + port: '' + prefix: '' + suffix: '' + baseDN: '' + bindDN: '' + bind_password: + search_attr: '' + search_filter: '' + scheme: '' + tls: {} + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: '' + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL read only replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL read replicas Volume mounts + ## + extraVolumeMounts: [] + + ## Additional PostgreSQL read replicas Volumes + ## + extraVolumes: [] + + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for read + ## + service: {} + # type: + # nodePort: + # clusterIP: + + ## Whether to enable PostgreSQL read replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for read replicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: '' + # + # Certificate filename + certFilename: '' + # + # Certificate Key filename + certKeyFilename: '' + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: false + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '9187' + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: '' + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size_bytes FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + # + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Array with extra yaml to deploy with the chart. Evaluated as a template +## +extraDeploy: [] diff --git a/sample-cnfs/sample_secret_env_no_ref/README.md b/sample-cnfs/sample_secret_env_no_ref/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_secret_env_no_ref/cnf-conformance.yml b/sample-cnfs/sample_secret_env_no_ref/cnf-conformance.yml new file mode 100644 index 000000000..acc776928 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/cnf-conformance.yml @@ -0,0 +1,10 @@ +--- +helm_directory: postgresql +git_clone_url: +install_script: chart +release_name: postgresql +service_name: postgresql +container_names: + - name: postgresql + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/.helmignore b/sample-cnfs/sample_secret_env_no_ref/postgresql/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.lock b/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.lock new file mode 100644 index 000000000..00ef82278 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.1.2 +digest: sha256:5a5d1b6e8a55efef1c07768b6bb264c60c98e230792b9a63f85468b95cf58c45 +generated: "2020-12-11T12:22:28.510708+01:00" diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.yaml new file mode 100644 index 000000000..332cb9650 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/Chart.yaml @@ -0,0 +1,29 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 11.10.0 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.x.x +description: Chart for PostgreSQL, an object-relational database management system + (ORDBMS) with an emphasis on extensibility and on standards-compliance. +home: https://github.com/bitnami/charts/tree/master/bitnami/postgresql +icon: https://bitnami.com/assets/stacks/postgresql/img/postgresql-stack-110x117.png +keywords: +- postgresql +- postgres +- database +- sql +- replication +- cluster +maintainers: +- email: containers@bitnami.com + name: Bitnami +- email: cedric@desaintmartin.fr + name: desaintmartin +name: postgresql +sources: +- https://github.com/bitnami/bitnami-docker-postgresql +- https://www.postgresql.org/ +version: 10.2.0 diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/README.md b/sample-cnfs/sample_secret_env_no_ref/postgresql/README.md new file mode 100644 index 000000000..9cf7c4128 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/README.md @@ -0,0 +1,798 @@ +# PostgreSQL + +[PostgreSQL](https://www.postgresql.org/) is an object-relational database management system (ORDBMS) with an emphasis on extensibility and on standards-compliance. + +For HA, please see [this repo](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) + +## TL;DR + +```console +$ helm repo add bitnami https://charts.bitnami.com/bitnami +$ helm install my-release bitnami/postgresql +``` + +## Introduction + +This chart bootstraps a [PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart +To install the chart with the release name `my-release`: + +```console +$ helm install my-release bitnami/postgresql +``` + +The command deploys PostgreSQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components but PVC's associated with the chart and deletes the release. + +To delete the PVC's associated with `my-release`: + +```console +$ kubectl delete pvc -l release=my-release +``` + +> **Note**: Deleting the PVC's will delete postgresql data as well. Please be cautious before doing it. + +## Parameters + +The following tables lists the configurable parameters of the PostgreSQL chart and their default values. + +| Parameter | Description | Default | +|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| +| `global.imageRegistry` | Global Docker Image registry | `nil` | +| `global.postgresql.postgresqlDatabase` | PostgreSQL database (overrides `postgresqlDatabase`) | `nil` | +| `global.postgresql.postgresqlUsername` | PostgreSQL username (overrides `postgresqlUsername`) | `nil` | +| `global.postgresql.existingSecret` | Name of existing secret to use for PostgreSQL passwords (overrides `existingSecret`) | `nil` | +| `global.postgresql.postgresqlPassword` | PostgreSQL admin password (overrides `postgresqlPassword`) | `nil` | +| `global.postgresql.servicePort` | PostgreSQL port (overrides `service.port`) | `nil` | +| `global.postgresql.replicationPassword` | Replication user password (overrides `replication.password`) | `nil` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | +| `global.storageClass` | Global storage class for dynamic provisioning | `nil` | +| `image.registry` | PostgreSQL Image registry | `docker.io` | +| `image.repository` | PostgreSQL Image name | `bitnami/postgresql` | +| `image.tag` | PostgreSQL Image tag | `{TAG_NAME}` | +| `image.pullPolicy` | PostgreSQL Image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `image.debug` | Specify if debug values should be set | `false` | +| `nameOverride` | String to partially override common.names.fullname template with a string (will prepend the release name) | `nil` | +| `fullnameOverride` | String to fully override common.names.fullname template with a string | `nil` | +| `volumePermissions.enabled` | Enable init container that changes volume permissions in the data directory (for cases where the default k8s `runAsUser` and `fsUser` values do not work) | `false` | +| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | +| `volumePermissions.image.repository` | Init container volume-permissions image name | `bitnami/minideb` | +| `volumePermissions.image.tag` | Init container volume-permissions image tag | `buster` | +| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `Always` | +| `volumePermissions.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container (when facing issues in OpenShift or uid unknown, try value "auto") | `0` | +| `usePasswordFile` | Have the secrets mounted as a file instead of env vars | `false` | +| `ldap.enabled` | Enable LDAP support | `false` | +| `ldap.existingSecret` | Name of existing secret to use for LDAP passwords | `nil` | +| `ldap.url` | LDAP URL beginning in the form `ldap[s]://host[:port]/basedn[?[attribute][?[scope][?[filter]]]]` | `nil` | +| `ldap.server` | IP address or name of the LDAP server. | `nil` | +| `ldap.port` | Port number on the LDAP server to connect to | `nil` | +| `ldap.scheme` | Set to `ldaps` to use LDAPS. | `nil` | +| `ldap.tls` | Set to `1` to use TLS encryption | `nil` | +| `ldap.prefix` | String to prepend to the user name when forming the DN to bind | `nil` | +| `ldap.suffix` | String to append to the user name when forming the DN to bind | `nil` | +| `ldap.search_attr` | Attribute to match against the user name in the search | `nil` | +| `ldap.search_filter` | The search filter to use when doing search+bind authentication | `nil` | +| `ldap.baseDN` | Root DN to begin the search for the user in | `nil` | +| `ldap.bindDN` | DN of user to bind to LDAP | `nil` | +| `ldap.bind_password` | Password for the user to bind to LDAP | `nil` | +| `replication.enabled` | Enable replication | `false` | +| `replication.user` | Replication user | `repl_user` | +| `replication.password` | Replication user password | `repl_password` | +| `replication.readReplicas` | Number of read replicas replicas | `1` | +| `replication.synchronousCommit` | Set synchronous commit mode. Allowed values: `on`, `remote_apply`, `remote_write`, `local` and `off` | `off` | +| `replication.numSynchronousReplicas` | Number of replicas that will have synchronous replication. Note: Cannot be greater than `replication.readReplicas`. | `0` | +| `replication.applicationName` | Cluster application name. Useful for advanced replication settings | `my_application` | +| `existingSecret` | Name of existing secret to use for PostgreSQL passwords. The secret has to contain the keys `postgresql-password` which is the password for `postgresqlUsername` when it is different of `postgres`, `postgresql-postgres-password` which will override `postgresqlPassword`, `postgresql-replication-password` which will override `replication.password` and `postgresql-ldap-password` which will be sed to authenticate on LDAP. The value is evaluated as a template. | `nil` | +| `postgresqlPostgresPassword` | PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`, in which case`postgres` is the admin username). | _random 10 character alphanumeric string_ | +| `postgresqlUsername` | PostgreSQL user (creates a non-admin user when `postgresqlUsername` is not `postgres`) | `postgres` | +| `postgresqlPassword` | PostgreSQL user password | _random 10 character alphanumeric string_ | +| `postgresqlDatabase` | PostgreSQL database | `nil` | +| `postgresqlDataDir` | PostgreSQL data dir folder | `/bitnami/postgresql` (same value as persistence.mountPath) | +| `extraEnv` | Any extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `[]` | +| `extraEnvVarsCM` | Name of a Config Map containing extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `nil` | +| `postgresqlInitdbArgs` | PostgreSQL initdb extra arguments | `nil` | +| `postgresqlInitdbWalDir` | PostgreSQL location for transaction log | `nil` | +| `postgresqlConfiguration` | Runtime Config Parameters | `nil` | +| `postgresqlExtendedConf` | Extended Runtime Config Parameters (appended to main or default configuration) | `nil` | +| `pgHbaConfiguration` | Content of pg_hba.conf | `nil (do not create pg_hba.conf)` | +| `postgresqlSharedPreloadLibraries` | Shared preload libraries (comma-separated list) | `pgaudit` | +| `postgresqlMaxConnections` | Maximum total connections | `nil` | +| `postgresqlPostgresConnectionLimit` | Maximum total connections for the postgres user | `nil` | +| `postgresqlDbUserConnectionLimit` | Maximum total connections for the non-admin user | `nil` | +| `postgresqlTcpKeepalivesInterval` | TCP keepalives interval | `nil` | +| `postgresqlTcpKeepalivesIdle` | TCP keepalives idle | `nil` | +| `postgresqlTcpKeepalivesCount` | TCP keepalives count | `nil` | +| `postgresqlStatementTimeout` | Statement timeout | `nil` | +| `postgresqlPghbaRemoveFilters` | Comma-separated list of patterns to remove from the pg_hba.conf file | `nil` | +| `customLivenessProbe` | Override default liveness probe | `nil` | +| `customReadinessProbe` | Override default readiness probe | `nil` | +| `audit.logHostname` | Add client hostnames to the log file | `false` | +| `audit.logConnections` | Add client log-in operations to the log file | `false` | +| `audit.logDisconnections` | Add client log-outs operations to the log file | `false` | +| `audit.pgAuditLog` | Add operations to log using the pgAudit extension | `nil` | +| `audit.clientMinMessages` | Message log level to share with the user | `nil` | +| `audit.logLinePrefix` | Template string for the log line prefix | `nil` | +| `audit.logTimezone` | Timezone for the log timestamps | `nil` | +| `configurationConfigMap` | ConfigMap with the PostgreSQL configuration files (Note: Overrides `postgresqlConfiguration` and `pgHbaConfiguration`). The value is evaluated as a template. | `nil` | +| `extendedConfConfigMap` | ConfigMap with the extended PostgreSQL configuration files. The value is evaluated as a template. | `nil` | +| `initdbScripts` | Dictionary of initdb scripts | `nil` | +| `initdbUser` | PostgreSQL user to execute the .sql and sql.gz scripts | `nil` | +| `initdbPassword` | Password for the user specified in `initdbUser` | `nil` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`). The value is evaluated as a template. | `nil` | +| `initdbScriptsSecret` | Secret with initdb scripts that contain sensitive information (Note: can be used with `initdbScriptsConfigMap` or `initdbScripts`). The value is evaluated as a template. | `nil` | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.port` | PostgreSQL port | `5432` | +| `service.nodePort` | Kubernetes Service nodePort | `nil` | +| `service.annotations` | Annotations for PostgreSQL service | `{}` (evaluated as a template) | +| `service.loadBalancerIP` | loadBalancerIP if service type is `LoadBalancer` | `nil` | +| `service.loadBalancerSourceRanges` | Address that are allowed when svc is LoadBalancer | `[]` (evaluated as a template) | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `shmVolume.enabled` | Enable emptyDir volume for /dev/shm for primary and read replica(s) Pod(s) | `true` | +| `shmVolume.chmod.enabled` | Run at init chmod 777 of the /dev/shm (ignored if `volumePermissions.enabled` is `false`) | `true` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim`, the value is evaluated as a template. | `nil` | +| `persistence.mountPath` | Path to mount the volume at | `/bitnami/postgresql` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `persistence.storageClass` | PVC Storage Class for PostgreSQL volume | `nil` | +| `persistence.accessModes` | PVC Access Mode for PostgreSQL volume | `[ReadWriteOnce]` | +| `persistence.size` | PVC Storage Request for PostgreSQL volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume (this value is evaluated as a template) | `{}` | +| `commonAnnotations` | Annotations to be added to all deployed resources (rendered as a template) | `{}` | +| `primary.podAffinityPreset` | PostgreSQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | PostgreSQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | PostgreSQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | PostgreSQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | PostgreSQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.nodeSelector` | Node labels for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.tolerations` | Tolerations for PostgreSQL primary pods assignment | `[]` (evaluated as a template) | + +| `primary.anotations` | Map of annotations to add to the statefulset (postgresql primary) | `{}` | +| `primary.labels` | Map of labels to add to the statefulset (postgresql primary) | `{}` | +| `primary.podAnnotations` | Map of annotations to add to the pods (postgresql primary) | `{}` | +| `primary.podLabels` | Map of labels to add to the pods (postgresql primary) | `{}` | +| `primary.priorityClassName` | Priority Class to use for each pod (postgresql primary) | `nil` | +| `primary.extraInitContainers` | Additional init containers to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumes` | Additional volumes to add to the pods (postgresql primary) | `[]` | +| `primary.sidecars` | Add additional containers to the pod | `[]` | +| `primary.service.type` | Allows using a different service type for primary | `nil` | +| `primary.service.nodePort` | Allows using a different nodePort for primary | `nil` | +| `primary.service.clusterIP` | Allows using a different clusterIP for primary | `nil` | +| `primaryAsStandBy.enabled` | Whether to enable current cluster's primary as standby server of another cluster or not. | `false` | +| `primaryAsStandBy.primaryHost` | The Host of replication primary in the other cluster. | `nil` | +| `primaryAsStandBy.primaryPort ` | The Port of replication primary in the other cluster. | `nil` | +| `readReplicas.podAffinityPreset` | PostgreSQL read only pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.podAntiAffinityPreset` | PostgreSQL read only pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `readReplicas.nodeAffinityPreset.type` | PostgreSQL read only node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.nodeAffinityPreset.key` | PostgreSQL read only node label key to match Ignored if `primary.affinity` is set. | `""` | +| `readReplicas.nodeAffinityPreset.values` | PostgreSQL read only node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `readReplicas.affinity` | Affinity for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.nodeSelector` | Node labels for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.anotations` | Map of annotations to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.resources` | CPU/Memory resource requests/limits override for readReplicass. Will fallback to `values.resources` if not defined. | `{}` | +| `readReplicas.labels` | Map of labels to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.podAnnotations` | Map of annotations to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.podLabels` | Map of labels to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.priorityClassName` | Priority Class to use for each pod (postgresql readReplicas) | `nil` | +| `readReplicas.extraInitContainers` | Additional init containers to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumes` | Additional volumes to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.sidecars` | Add additional containers to the pod | `[]` | +| `readReplicas.service.type` | Allows using a different service type for readReplicas | `nil` | +| `readReplicas.service.nodePort` | Allows using a different nodePort for readReplicas | `nil` | +| `readReplicas.service.clusterIP` | Allows using a different clusterIP for readReplicas | `nil` | +| `readReplicas.persistence.enabled` | Whether to enable readReplicas replicas persistence | `true` | +| `terminationGracePeriodSeconds` | Seconds the pod needs to terminate gracefully | `nil` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | +| `securityContext.*` | Other pod security context to be included as-is in the pod spec | `{}` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the pod | `1001` | +| `containerSecurityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `containerSecurityContext.enabled` | Enable container security context | `true` | +| `containerSecurityContext.runAsUser` | User ID for the container | `1001` | +| `serviceAccount.enabled` | Enable service account (Note: Service Account will only be automatically created if `serviceAccount.name` is not set) | `false` | +| `serviceAccount.name` | Name of existing service account | `nil` | +| `livenessProbe.enabled` | Would you like a livenessProbe to be enabled | `true` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed | `{}` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `tls.enabled` | Enable TLS traffic support | `false` | +| `tls.preferServerCiphers` | Whether to use the server's TLS cipher preferences rather than the client's | `true` | +| `tls.certificatesSecret` | Name of an existing secret that contains the certificates | `nil` | +| `tls.certFilename` | Certificate filename | `""` | +| `tls.certKeyFilename` | Certificate key filename | `""` | +| `tls.certCAFilename` | CA Certificate filename. If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate. | `nil` | +| `tls.crlFilename` | File containing a Certificate Revocation List | `nil` | +| `metrics.enabled` | Start a prometheus exporter | `false` | +| `metrics.service.type` | Kubernetes Service type | `ClusterIP` | +| `service.clusterIP` | Static clusterIP or None for headless services | `nil` | +| `metrics.service.annotations` | Additional annotations for metrics exporter pod | `{ prometheus.io/scrape: "true", prometheus.io/port: "9187"}` | +| `metrics.service.loadBalancerIP` | loadBalancerIP if redis metrics service type is `LoadBalancer` | `nil` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.namespace` | Optional namespace in which to create ServiceMonitor | `nil` | +| `metrics.serviceMonitor.interval` | Scrape interval. If not set, the Prometheus default scrape interval is used | `nil` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout. If not set, the Prometheus default scrape timeout is used | `nil` | +| `metrics.prometheusRule.enabled` | Set this to true to create prometheusRules for Prometheus operator | `false` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so prometheusRules will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.namespace` | namespace where prometheusRules resource should be created | the same namespace as postgresql | +| `metrics.prometheusRule.rules` | [rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) to be created, check values for an example. | `[]` | +| `metrics.image.registry` | PostgreSQL Exporter Image registry | `docker.io` | +| `metrics.image.repository` | PostgreSQL Exporter Image name | `bitnami/postgres-exporter` | +| `metrics.image.tag` | PostgreSQL Exporter Image tag | `{TAG_NAME}` | +| `metrics.image.pullPolicy` | PostgreSQL Exporter Image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `metrics.customMetrics` | Additional custom metrics | `nil` | +| `metrics.extraEnvVars` | Extra environment variables to add to exporter | `{}` (evaluated as a template) | +| `metrics.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `metrics.securityContext.enabled` | Enable security context for metrics | `false` | +| `metrics.securityContext.runAsUser` | User ID for the container for metrics | `1001` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `metrics.livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `metrics.readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 5 | +| `metrics.readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `updateStrategy` | Update strategy policy | `{type: "RollingUpdate"}` | +| `psp.create` | Create Pod Security Policy | `false` | +| `rbac.create` | Create Role and RoleBinding (required for PSP to work) | `false` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template). | `nil` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install my-release \ + --set postgresqlPassword=secretpassword,postgresqlDatabase=my-database \ + bitnami/postgresql +``` + +The above command sets the PostgreSQL `postgres` account password to `secretpassword`. Additionally it creates a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +$ helm install my-release -f values.yaml bitnami/postgresql +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) + +It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. + +Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. + +### Production configuration and horizontal scaling + +This chart includes a `values-production.yaml` file where you can find some parameters oriented to production configuration in comparison to the regular `values.yaml`. You can use this file instead of the default one. + +- Enable replication: +```diff +- replication.enabled: false ++ replication.enabled: true +``` + +- Number of read replicas: +```diff +- replication.readReplicas: 1 ++ replication.readReplicas: 2 +``` + +- Set synchronous commit mode: +```diff +- replication.synchronousCommit: "off" ++ replication.synchronousCommit: "on" +``` + +- Number of replicas that will have synchronous replication: +```diff +- replication.numSynchronousReplicas: 0 ++ replication.numSynchronousReplicas: 1 +``` + +- Start a prometheus exporter: +```diff +- metrics.enabled: false ++ metrics.enabled: true +``` + +To horizontally scale this chart, you can use the `--replicas` flag to modify the number of nodes in your PostgreSQL deployment. Also you can use the `values-production.yaml` file or modify the parameters shown above. + +### Customizing primary and read replica services in a replicated configuration + +At the top level, there is a service object which defines the services for both primary and readReplicas. For deeper customization, there are service objects for both the primary and read types individually. This allows you to override the values in the top level service object so that the primary and read can be of different service types and with different clusterIPs / nodePorts. Also in the case you want the primary and read to be of type nodePort, you will need to set the nodePorts to different values to prevent a collision. The values that are deeper in the primary.service or readReplicas.service objects will take precedence over the top level service object. + +### Change PostgreSQL version + +To modify the PostgreSQL version used in this chart you can specify a [valid image tag](https://hub.docker.com/r/bitnami/postgresql/tags/) using the `image.tag` parameter. For example, `image.tag=X.Y.Z`. This approach is also applicable to other images like exporters. + +### postgresql.conf / pg_hba.conf files as configMap + +This helm chart also supports to customize the whole configuration file. + +Add your custom file to "files/postgresql.conf" in your working directory. This file will be mounted as configMap to the containers and it will be used for configuring the PostgreSQL server. + +Alternatively, you can specify PostgreSQL configuration parameters using the `postgresqlConfiguration` parameter as a dict, using camelCase, e.g. {"sharedBuffers": "500MB"}. + +In addition to these options, you can also set an external ConfigMap with all the configuration files. This is done by setting the `configurationConfigMap` parameter. Note that this will override the two previous options. + +### Allow settings to be loaded from files other than the default `postgresql.conf` + +If you don't want to provide the whole PostgreSQL configuration file and only specify certain parameters, you can add your extended `.conf` files to "files/conf.d/" in your working directory. +Those files will be mounted as configMap to the containers adding/overwriting the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +Alternatively, you can also set an external ConfigMap with all the extra configuration files. This is done by setting the `extendedConfConfigMap` parameter. Note that this will override the previous option. + +### Initialize a fresh instance + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image allows you to use your custom scripts to initialize a fresh instance. In order to execute the scripts, they must be located inside the chart folder `files/docker-entrypoint-initdb.d` so they can be consumed as a ConfigMap. + +Alternatively, you can specify custom scripts using the `initdbScripts` parameter as dict. + +In addition to these options, you can also set an external ConfigMap with all the initialization scripts. This is done by setting the `initdbScriptsConfigMap` parameter. Note that this will override the two previous options. If your initialization scripts contain sensitive information such as credentials or passwords, you can use the `initdbScriptsSecret` parameter. + +The allowed extensions are `.sh`, `.sql` and `.sql.gz`. + +### Securing traffic using TLS + +TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the chart: + +- `tls.enabled`: Enable TLS support. Defaults to `false` +- `tls.certificatesSecret`: Name of an existing secret that contains the certificates. No defaults. +- `tls.certFilename`: Certificate filename. No defaults. +- `tls.certKeyFilename`: Certificate key filename. No defaults. + +For example: + +* First, create the secret with the cetificates files: + + ```console + kubectl create secret generic certificates-tls-secret --from-file=./cert.crt --from-file=./cert.key --from-file=./ca.crt + ``` + +* Then, use the following parameters: + + ```console + volumePermissions.enabled=true + tls.enabled=true + tls.certificatesSecret="certificates-tls-secret" + tls.certFilename="cert.crt" + tls.certKeyFilename="cert.key" + ``` + + > Note TLS and VolumePermissions: PostgreSQL requires certain permissions on sensitive files (such as certificate keys) to start up. Due to an on-going [issue](https://github.com/kubernetes/kubernetes/issues/57923) regarding kubernetes permissions and the use of `containerSecurityContext.runAsUser`, you must enable `volumePermissions` to ensure everything works as expected. + +### Sidecars + +If you need additional containers to run within the same pod as PostgreSQL (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +# For the PostgreSQL primary +primary: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +# For the PostgreSQL replicas +readReplicas: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +### Metrics + +The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9187) is not exposed and it is expected that the metrics are collected from inside the k8s cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). + +The exporter allows to create custom metrics from additional SQL queries. See the Chart's `values.yaml` for an example and consult the [exporters documentation](https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file) for more details. + +### Use of global variables + +In more complex scenarios, we may have the following tree of dependencies + +``` + +--------------+ + | | + +------------+ Chart 1 +-----------+ + | | | | + | --------+------+ | + | | | + | | | + | | | + | | | + v v v ++-------+------+ +--------+------+ +--------+------+ +| | | | | | +| PostgreSQL | | Sub-chart 1 | | Sub-chart 2 | +| | | | | | ++--------------+ +---------------+ +---------------+ +``` + +The three charts below depend on the parent chart Chart 1. However, subcharts 1 and 2 may need to connect to PostgreSQL as well. In order to do so, subcharts 1 and 2 need to know the PostgreSQL credentials, so one option for deploying could be deploy Chart 1 with the following parameters: + +``` +postgresql.postgresqlPassword=testtest +subchart1.postgresql.postgresqlPassword=testtest +subchart2.postgresql.postgresqlPassword=testtest +postgresql.postgresqlDatabase=db1 +subchart1.postgresql.postgresqlDatabase=db1 +subchart2.postgresql.postgresqlDatabase=db1 +``` + +If the number of dependent sub-charts increases, installing the chart with parameters can become increasingly difficult. An alternative would be to set the credentials using global variables as follows: + +``` +global.postgresql.postgresqlPassword=testtest +global.postgresql.postgresqlDatabase=db1 +``` + +This way, the credentials will be available in all of the subcharts. + +## Persistence + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image stores the PostgreSQL data and configurations at the `/bitnami/postgresql` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. +See the [Parameters](#parameters) section to configure the PVC or to disable persistence. + +If you already have data in it, you will fail to sync to standby nodes for all commits, details can refer to [code](https://github.com/bitnami/bitnami-docker-postgresql/blob/8725fe1d7d30ebe8d9a16e9175d05f7ad9260c93/9.6/debian-9/rootfs/libpostgresql.sh#L518-L556). If you need to use those data, please covert them to sql and import after `helm install` finished. + +## NetworkPolicy + +To enable network policy for PostgreSQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: + +```console +$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 5432. + +For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to PostgreSQL. +This label will be displayed in the output of a successful install. + +## Differences between Bitnami PostgreSQL image and [Docker Official](https://hub.docker.com/_/postgres) image + +- The Docker Official PostgreSQL image does not support replication. If you pass any replication environment variable, this would be ignored. The only environment variables supported by the Docker Official image are POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORD, POSTGRES_INITDB_ARGS, POSTGRES_INITDB_WALDIR and PGDATA. All the remaining environment variables are specific to the Bitnami PostgreSQL image. +- The Bitnami PostgreSQL image is non-root by default. This requires that you run the pod with `securityContext` and updates the permissions of the volume with an `initContainer`. A key benefit of this configuration is that the pod follows security best practices and is prepared to run on Kubernetes distributions with hard security constraints like OpenShift. +- For OpenShift, one may either define the runAsUser and fsGroup accordingly, or try this more dynamic option: volumePermissions.securityContext.runAsUser="auto",securityContext.enabled=false,containerSecurityContext.enabled=false,shmVolume.chmod.enabled=false + +### Deploy chart using Docker Official PostgreSQL Image + +From chart version 4.0.0, it is possible to use this chart with the Docker Official PostgreSQL image. +Besides specifying the new Docker repository and tag, it is important to modify the PostgreSQL data directory and volume mount point. Basically, the PostgreSQL data dir cannot be the mount point directly, it has to be a subdirectory. + +``` +image.repository=postgres +image.tag=10.6 +postgresqlDataDir=/data/pgdata +persistence.mountPath=/data/ +``` + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` paremeter(s). Find more infomation about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/master/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## Troubleshooting + +Find more information about how to deal with common errors related to Bitnami’s Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). + +## Upgrading + +It's necessary to specify the existing passwords while performing an upgrade to ensure the secrets are not updated with invalid randomly generated passwords. Remember to specify the existing values of the `postgresqlPassword` and `replication.password` parameters when upgrading the chart: + +```bash +$ helm upgrade my-release bitnami/postgresql \ + --set postgresqlPassword=[POSTGRESQL_PASSWORD] \ + --set replication.password=[REPLICATION_PASSWORD] +``` + +> Note: you need to substitute the placeholders _[POSTGRESQL_PASSWORD]_, and _[REPLICATION_PASSWORD]_ with the values obtained from instructions in the installation notes. + +### To 10.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Move dependency information from the *requirements.yaml* to the *Chart.yaml* +- After running `helm dependency update`, a *Chart.lock* file is generated containing the same structure used in the previous *requirements.lock* +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Chart. + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ + +#### Breaking changes + +- The term `master` has been replaced with `primary` and `slave` with `readReplicas` throughout the chart. Role names have changed from `master` and `slave` to `primary` and `read`. + +To upgrade to `10.0.0`, it should be done reusing the PVCs used to hold the PostgreSQL data on your previous release. To do so, follow the instructions below (the following example assumes that the release name is `postgresql`): + +> NOTE: Please, create a backup of your database before running any of those actions. + +Obtain the credentials and the names of the PVCs used to hold the PostgreSQL data on your current release: + +```console +$ export POSTGRESQL_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode) +$ export POSTGRESQL_PVC=$(kubectl get pvc -l app.kubernetes.io/instance=postgresql,role=master -o jsonpath="{.items[0].metadata.name}") +``` + +Delete the PostgreSQL statefulset. Notice the option `--cascade=false`: + +```console +$ kubectl delete statefulsets.apps postgresql-postgresql --cascade=false +``` + +Now the upgrade works: + +```console +$ helm upgrade postgresql bitnami/postgresql --set postgresqlPassword=$POSTGRESQL_PASSWORD --set persistence.existingClaim=$POSTGRESQL_PVC +``` + +You will have to delete the existing MariaDB pod and the new statefulset is going to create a new one + +```console +$ kubectl delete pod postgresql-postgresql-0 +``` + +Finally, you should see the lines below in MariaDB container logs: + +```console +$ kubectl logs $(kubectl get pods -l app.kubernetes.io/instance=postgresql,app.kubernetes.io/name=postgresql,role=primary -o jsonpath="{.items[0].metadata.name}") +... +postgresql 08:05:12.59 INFO ==> Deploying PostgreSQL with persisted data... +... +``` + +### To 9.0.0 + +In this version the chart was adapted to follow the Helm label best practices, see [PR 3021](https://github.com/bitnami/charts/pull/3021). That means the backward compatibility is not guarantee when upgrading the chart to this major version. + +As a workaround, you can delete the existing statefulset (using the `--cascade=false` flag pods are not deleted) before upgrade the chart. For example, this can be a valid workflow: + +- Deploy an old version (8.X.X) + +```console +$ helm install postgresql bitnami/postgresql --version 8.10.14 +``` + +- Old version is up and running + +```console +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 1 2020-08-04 13:39:54.783480286 +0000 UTC deployed postgresql-8.10.14 11.8.0 + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 76s +``` + +- The upgrade to the latest one (9.X.X) is going to fail + +```console +$ helm upgrade postgresql bitnami/postgresql +Error: UPGRADE FAILED: cannot patch "postgresql-postgresql" with kind StatefulSet: StatefulSet.apps "postgresql-postgresql" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden +``` + +- Delete the statefulset + +```console +$ kubectl delete statefulsets.apps --cascade=false postgresql-postgresql +statefulset.apps "postgresql-postgresql" deleted +``` + +- Now the upgrade works + +```console +$ helm upgrade postgresql bitnami/postgresql +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 3 2020-08-04 13:42:08.020385884 +0000 UTC deployed postgresql-9.1.2 11.8.0 +``` + +- We can kill the existing pod and the new statefulset is going to create a new one: + +```console +$ kubectl delete pod postgresql-postgresql-0 +pod "postgresql-postgresql-0" deleted + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 19s +``` + +Please, note that without the `--cascade=false` both objects (statefulset and pod) are going to be removed and both objects will be deployed again with the `helm upgrade` command + +### To 8.0.0 + +Prefixes the port names with their protocols to comply with Istio conventions. + +If you depend on the port names in your setup, make sure to update them to reflect this change. + +### To 7.1.0 + +Adds support for LDAP configuration. + +### To 7.0.0 + +Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. + +In https://github.com/helm/charts/pull/17281 the `apiVersion` of the statefulset resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. + +This major version bump signifies this change. + +### To 6.5.7 + +In this version, the chart will use PostgreSQL with the Postgis extension included. The version used with Postgresql version 10, 11 and 12 is Postgis 2.5. It has been compiled with the following dependencies: + +- protobuf +- protobuf-c +- json-c +- geos +- proj + +### To 5.0.0 + +In this version, the **chart is using PostgreSQL 11 instead of PostgreSQL 10**. You can find the main difference and notable changes in the following links: [https://www.postgresql.org/about/news/1894/](https://www.postgresql.org/about/news/1894/) and [https://www.postgresql.org/about/featurematrix/](https://www.postgresql.org/about/featurematrix/). + +For major releases of PostgreSQL, the internal data storage format is subject to change, thus complicating upgrades, you can see some errors like the following one in the logs: + +```console +Welcome to the Bitnami postgresql container +Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-postgresql +Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-postgresql/issues +Send us your feedback at containers@bitnami.com + +INFO ==> ** Starting PostgreSQL setup ** +NFO ==> Validating settings in POSTGRESQL_* env vars.. +INFO ==> Initializing PostgreSQL database... +INFO ==> postgresql.conf file not detected. Generating it... +INFO ==> pg_hba.conf file not detected. Generating it... +INFO ==> Deploying PostgreSQL with persisted data... +INFO ==> Configuring replication parameters +INFO ==> Loading custom scripts... +INFO ==> Enabling remote connections +INFO ==> Stopping PostgreSQL... +INFO ==> ** PostgreSQL setup finished! ** + +INFO ==> ** Starting PostgreSQL ** + [1] FATAL: database files are incompatible with server + [1] DETAIL: The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.3. +``` + +In this case, you should migrate the data from the old chart to the new one following an approach similar to that described in [this section](https://www.postgresql.org/docs/current/upgrading.html#UPGRADING-VIA-PGDUMPALL) from the official documentation. Basically, create a database dump in the old chart, move and restore it in the new one. + +### To 4.0.0 + +This chart will use by default the Bitnami PostgreSQL container starting from version `10.7.0-r68`. This version moves the initialization logic from node.js to bash. This new version of the chart requires setting the `POSTGRES_PASSWORD` in the slaves as well, in order to properly configure the `pg_hba.conf` file. Users from previous versions of the chart are advised to upgrade immediately. + +IMPORTANT: If you do not want to upgrade the chart version then make sure you use the `10.7.0-r68` version of the container. Otherwise, you will get this error + +``` +The POSTGRESQL_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development +``` + +### To 3.0.0 + +This releases make it possible to specify different nodeSelector, affinity and tolerations for master and slave pods. +It also fixes an issue with `postgresql.master.fullname` helper template not obeying fullnameOverride. + +#### Breaking changes + +- `affinty` has been renamed to `master.affinity` and `slave.affinity`. +- `tolerations` has been renamed to `master.tolerations` and `slave.tolerations`. +- `nodeSelector` has been renamed to `master.nodeSelector` and `slave.nodeSelector`. + +### To 2.0.0 + +In order to upgrade from the `0.X.X` branch to `1.X.X`, you should follow the below steps: + +- Obtain the service name (`SERVICE_NAME`) and password (`OLD_PASSWORD`) of the existing postgresql chart. You can find the instructions to obtain the password in the NOTES.txt, the service name can be obtained by running + +```console +$ kubectl get svc +``` + +- Install (not upgrade) the new version + +```console +$ helm repo update +$ helm install my-release bitnami/postgresql +``` + +- Connect to the new pod (you can obtain the name by running `kubectl get pods`): + +```console +$ kubectl exec -it NAME bash +``` + +- Once logged in, create a dump file from the previous database using `pg_dump`, for that we should connect to the previous postgresql chart: + +```console +$ pg_dump -h SERVICE_NAME -U postgres DATABASE_NAME > /tmp/backup.sql +``` + +After run above command you should be prompted for a password, this password is the previous chart password (`OLD_PASSWORD`). +This operation could take some time depending on the database size. + +- Once you have the backup file, you can restore it with a command like the one below: + +```console +$ psql -U postgres DATABASE_NAME < /tmp/backup.sql +``` + +In this case, you are accessing to the local postgresql, so the password should be the new one (you can find it in NOTES.txt). + +If you want to restore the database and the database schema does not exist, it is necessary to first follow the steps described below. + +```console +$ psql -U postgres +postgres=# drop database DATABASE_NAME; +postgres=# create database DATABASE_NAME; +postgres=# create user USER_NAME; +postgres=# alter role USER_NAME with password 'BITNAMI_USER_PASSWORD'; +postgres=# grant all privileges on database DATABASE_NAME to USER_NAME; +postgres=# alter database DATABASE_NAME owner to USER_NAME; +``` diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/.helmignore b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/Chart.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/Chart.yaml new file mode 100644 index 000000000..1bda8e2df --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 1.1.1 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://github.com/bitnami/charts/tree/master/bitnami/common +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- email: containers@bitnami.com + name: Bitnami +name: common +sources: +- https://github.com/bitnami/charts +- http://www.bitnami.com/ +type: library +version: 1.1.2 diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/README.md b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/README.md new file mode 100644 index 000000000..a68895368 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/README.md @@ -0,0 +1,309 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 0.x.x + repository: https://charts.bitnami.com/bitnami +``` + +```bash +$ helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ + +## Parameters + +The following table lists the helpers available in the library which are scoped in different sections. + +### Affinities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.node.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.pod.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.pod.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | + +### Capabilities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.capabilities.deployment.apiVersion` | Return the appropriate apiVersion for deployment. | `.` Chart context | +| `common.capabilities.statefulset.apiVersion` | Return the appropriate apiVersion for statefulset. | `.` Chart context | +| `common.capabilities.ingress.apiVersion` | Return the appropriate apiVersion for ingress. | `.` Chart context | + +### Errors + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.errors.upgrade.passwords.empty` | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01) "context" $` | + +### Images + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.images.image` | Return the proper and full image name | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure. | +| `common.images.pullSecrets` | Return the proper Docker Image Registry Secret Names | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global` | + +### Labels + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.labels.standard` | Return Kubernetes standard labels | `.` Chart context | +| `common.labels.matchLabels` | Return the proper Docker Image Registry Secret Names | `.` Chart context | + +### Names + +| Helper identifier | Description | Expected Inpput | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.names.name` | Expand the name of the chart or use `.Values.nameOverride` | `.` Chart context | +| `common.names.fullname` | Create a default fully qualified app name. | `.` Chart context | +| `common.names.chart` | Chart name plus version | `.` Chart context | + +### Secrets + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.secrets.name` | Generate the name of the secret. | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.key` | Generate secret key. | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure. | + +### Storage + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. | + +### TplValues + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.tplvalues.render` | Renders a value that contains template | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frecuently is the chart context `$` or `.` | + +### Utils + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.utils.fieldToEnvVar` | Build environment variable name given a field. | `dict "field" "my-password"` | +| `common.utils.secret.getvalue` | Print instructions to get a secret value. | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` | +| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path | `dict "key" "path.to.key" "context" $` | + +### Validations + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.validations.values.single.empty` | Validate a value must not be empty. | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "context" $` secret and field are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) | +| `common.validations.values.multiple.empty` | Validate a multiple values must not be empty. It returns a shared error for all the values. | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue) | +| `common.validations.values.mariadb.passwords` | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values. | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mariadb chart and the helper. | +| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values. | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper. | +| `common.validations.values.redis.passwords` | This helper will ensure required password for Redis are not empty. It returns a shared error for all the values. | `dict "secret" "redis-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use redis chart and the helper. | +| `common.validations.values.cassandra.passwords` | This helper will ensure required password for Cassandra are not empty. It returns a shared error for all the values. | `dict "secret" "cassandra-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use cassandra chart and the helper. | +| `common.validations.values.mongodb.passwords` | This helper will ensure required password for MongoDB are not empty. It returns a shared error for all the values. | `dict "secret" "mongodb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mongodb chart and the helper. | + +### Warnings + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.warnings.rollingTag` | Warning about using rolling tag. | `ImageRoot` see [ImageRoot](#imageroot) for the structure. | + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets. + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possiblity of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +$ helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 --decode) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 --decode) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_affinities.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_affinities.tpl new file mode 100644 index 000000000..1ff26d585 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_affinities.tpl @@ -0,0 +1,94 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname + weight: 1 +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_capabilities.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_capabilities.tpl new file mode 100644 index 000000000..143bef2a4 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_capabilities.tpl @@ -0,0 +1,33 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_errors.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_errors.tpl new file mode 100644 index 000000000..d6d3ec65a --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_errors.tpl @@ -0,0 +1,20 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: you must provide your current passwords when upgrade the release%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_images.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_images.tpl new file mode 100644 index 000000000..aafde9f3b --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_images.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $tag := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_labels.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_labels.tpl new file mode 100644 index 000000000..252066c7e --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_labels.tpl @@ -0,0 +1,18 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Kubernetes standard labels +*/}} +{{- define "common.labels.standard" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector +*/}} +{{- define "common.labels.matchLabels" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_names.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_names.tpl new file mode 100644 index 000000000..adf2a74f4 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_names.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "common.names.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_secrets.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_secrets.tpl new file mode 100644 index 000000000..ebfb5d42d --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_secrets.tpl @@ -0,0 +1,57 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- $name = .name -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_storage.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_storage.tpl new file mode 100644 index 000000000..60e2a844f --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_storage.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} + +{{- $storageClass := .persistence.storageClass -}} +{{- if .global -}} + {{- if .global.storageClass -}} + {{- $storageClass = .global.storageClass -}} + {{- end -}} +{{- end -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_tplvalues.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_tplvalues.tpl new file mode 100644 index 000000000..2db166851 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,13 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "common.tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_utils.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_utils.tpl new file mode 100644 index 000000000..74774a3ca --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_utils.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_warnings.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_warnings.tpl new file mode 100644 index 000000000..ae10fa41e --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/_warnings.tpl @@ -0,0 +1,14 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ +{{- end }} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_cassandra.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 000000000..7a274a08c --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mariadb.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 000000000..3bf669dd8 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mongodb.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 000000000..7e0c1cbc3 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,108 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (not $existingSecret) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_postgresql.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 000000000..f25e0ffbf --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,131 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_redis.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_redis.tpl new file mode 100644 index 000000000..2ccc04d2d --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,72 @@ + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $existingSecret := include "common.redis.values.existingSecret" . -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $valueKeyRedisPassword := printf "%s%s" $valueKeyPrefix "password" -}} + {{- $valueKeyRedisUsePassword := printf "%s%s" $valueKeyPrefix "usePassword" -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $usePassword := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUsePassword "context" .context) -}} + {{- if eq $usePassword "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Redis Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.redis.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.redis.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_validations.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_validations.tpl new file mode 100644 index 000000000..d4cf32c77 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,44 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s=$%s' to the command.%s" .valueKey .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/values.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/values.yaml new file mode 100644 index 000000000..9ecdc93f5 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/charts/common/values.yaml @@ -0,0 +1,3 @@ +## bitnami/common +## It is required by CI/CD tools and processes. +exampleValue: common-chart diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/commonAnnotations.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/commonAnnotations.yaml new file mode 100644 index 000000000..97e18a4cc --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/commonAnnotations.yaml @@ -0,0 +1,3 @@ +commonAnnotations: + helm.sh/hook: "\"pre-install, pre-upgrade\"" + helm.sh/hook-weight: "-1" diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/default-values.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/default-values.yaml new file mode 100644 index 000000000..fc2ba605a --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/default-values.yaml @@ -0,0 +1 @@ +# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml. diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/shmvolume-disabled-values.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/shmvolume-disabled-values.yaml new file mode 100644 index 000000000..347d3b40a --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/ci/shmvolume-disabled-values.yaml @@ -0,0 +1,2 @@ +shmVolume: + enabled: false diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/files/README.md b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/README.md new file mode 100644 index 000000000..1813a2fea --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/README.md @@ -0,0 +1 @@ +Copy here your postgresql.conf and/or pg_hba.conf files to use it as a config map. diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/files/conf.d/README.md b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/conf.d/README.md new file mode 100644 index 000000000..184c1875d --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/conf.d/README.md @@ -0,0 +1,4 @@ +If you don't want to provide the whole configuration file and only specify certain parameters, you can copy here your extended `.conf` files. +These files will be injected as a config maps and add/overwrite the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +More info in the [bitnami-docker-postgresql README](https://github.com/bitnami/bitnami-docker-postgresql#configuration-file). diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/files/docker-entrypoint-initdb.d/README.md b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/docker-entrypoint-initdb.d/README.md new file mode 100644 index 000000000..cba38091e --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/files/docker-entrypoint-initdb.d/README.md @@ -0,0 +1,3 @@ +You can copy here your custom `.sh`, `.sql` or `.sql.gz` file so they are executed during the first boot of the image. + +More info in the [bitnami-docker-postgresql](https://github.com/bitnami/bitnami-docker-postgresql#initializing-a-new-instance) repository. \ No newline at end of file diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/NOTES.txt b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/NOTES.txt new file mode 100644 index 000000000..4e98958c1 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/NOTES.txt @@ -0,0 +1,59 @@ +** Please be patient while the chart is being deployed ** + +PostgreSQL can be accessed via port {{ template "postgresql.port" . }} on the following DNS name from within your cluster: + + {{ template "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - Read/Write connection +{{- if .Values.replication.enabled }} + {{ template "common.names.fullname" . }}-read.{{ .Release.Namespace }}.svc.cluster.local - Read only connection +{{- end }} + +{{- if not (eq (include "postgresql.username" .) "postgres") }} + +To get the password for "postgres" run: + + export POSTGRES_ADMIN_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-postgres-password}" | base64 --decode) +{{- end }} + +To get the password for "{{ template "postgresql.username" . }}" run: + + export POSTGRES_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-password}" | base64 --decode) + +To connect to your database run the following command: + + kubectl run {{ template "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --namespace {{ .Release.Namespace }} --image {{ template "postgresql.image" . }} --env="PGPASSWORD=$POSTGRES_PASSWORD" {{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} + --labels="{{ template "common.names.fullname" . }}-client=true" {{- end }} --command -- psql --host {{ template "common.names.fullname" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to this PostgreSQL cluster. +{{- end }} + +To connect to your database from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $NODE_IP --port $NODE_PORT -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $SERVICE_IP --port {{ template "postgresql.port" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "common.names.fullname" . }} {{ template "postgresql.port" . }}:{{ template "postgresql.port" . }} & + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host 127.0.0.1 -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{- end }} + +{{- include "postgresql.validateValues" . -}} + +{{- include "common.warnings.rollingTag" .Values.image -}} + +{{- $passwordValidationErrors := include "common.validations.values.postgresql.passwords" (dict "secret" (include "common.names.fullname" .) "context" $) -}} + +{{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $passwordValidationErrors) "context" $) -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/_helpers.tpl b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/_helpers.tpl new file mode 100644 index 000000000..7509941cf --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/_helpers.tpl @@ -0,0 +1,330 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "postgresql.primary.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- $fullname := default (printf "%s-%s" .Release.Name $name) .Values.fullnameOverride -}} +{{- if .Values.replication.enabled -}} +{{- printf "%s-%s" $fullname "primary" | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $fullname | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper PostgreSQL image name +*/}} +{{- define "postgresql.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper PostgreSQL metrics image name +*/}} +{{- define "postgresql.metrics.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "postgresql.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "postgresql.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Return PostgreSQL postgres user password +*/}} +{{- define "postgresql.postgres.password" -}} +{{- if .Values.global.postgresql.postgresqlPostgresPassword }} + {{- .Values.global.postgresql.postgresqlPostgresPassword -}} +{{- else if .Values.postgresqlPostgresPassword -}} + {{- .Values.postgresqlPostgresPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL password +*/}} +{{- define "postgresql.password" -}} +{{- if .Values.global.postgresql.postgresqlPassword }} + {{- .Values.global.postgresql.postgresqlPassword -}} +{{- else if .Values.postgresqlPassword -}} + {{- .Values.postgresqlPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication password +*/}} +{{- define "postgresql.replication.password" -}} +{{- if .Values.global.postgresql.replicationPassword }} + {{- .Values.global.postgresql.replicationPassword -}} +{{- else if .Values.replication.password -}} + {{- .Values.replication.password -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL username +*/}} +{{- define "postgresql.username" -}} +{{- if .Values.global.postgresql.postgresqlUsername }} + {{- .Values.global.postgresql.postgresqlUsername -}} +{{- else -}} + {{- .Values.postgresqlUsername -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication username +*/}} +{{- define "postgresql.replication.username" -}} +{{- if .Values.global.postgresql.replicationUser }} + {{- .Values.global.postgresql.replicationUser -}} +{{- else -}} + {{- .Values.replication.user -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL port +*/}} +{{- define "postgresql.port" -}} +{{- if .Values.global.postgresql.servicePort }} + {{- .Values.global.postgresql.servicePort -}} +{{- else -}} + {{- .Values.service.port -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL created database +*/}} +{{- define "postgresql.database" -}} +{{- if .Values.global.postgresql.postgresqlDatabase }} + {{- .Values.global.postgresql.postgresqlDatabase -}} +{{- else if .Values.postgresqlDatabase -}} + {{- .Values.postgresqlDatabase -}} +{{- end -}} +{{- end -}} + +{{/* +Get the password secret. +*/}} +{{- define "postgresql.secretName" -}} +{{- if .Values.global.postgresql.existingSecret }} + {{- printf "%s" (tpl .Values.global.postgresql.existingSecret $) -}} +{{- else if .Values.existingSecret -}} + {{- printf "%s" (tpl .Values.existingSecret $) -}} +{{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if we should use an existingSecret. +*/}} +{{- define "postgresql.useExistingSecret" -}} +{{- if or .Values.global.postgresql.existingSecret .Values.existingSecret -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created +*/}} +{{- define "postgresql.createSecret" -}} +{{- if not (include "postgresql.useExistingSecret" .) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the configuration ConfigMap name. +*/}} +{{- define "postgresql.configurationCM" -}} +{{- if .Values.configurationConfigMap -}} +{{- printf "%s" (tpl .Values.configurationConfigMap $) -}} +{{- else -}} +{{- printf "%s-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the extended configuration ConfigMap name. +*/}} +{{- define "postgresql.extendedConfigurationCM" -}} +{{- if .Values.extendedConfConfigMap -}} +{{- printf "%s" (tpl .Values.extendedConfConfigMap $) -}} +{{- else -}} +{{- printf "%s-extended-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap should be mounted with PostgreSQL configuration +*/}} +{{- define "postgresql.mountConfigurationCM" -}} +{{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "postgresql.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts Secret name. +*/}} +{{- define "postgresql.initdbScriptsSecret" -}} +{{- printf "%s" (tpl .Values.initdbScriptsSecret $) -}} +{{- end -}} + +{{/* +Get the metrics ConfigMap name. +*/}} +{{- define "postgresql.metricsCM" -}} +{{- printf "%s-metrics" (include "common.names.fullname" .) -}} +{{- end -}} + +{{/* +Get the readiness probe command +*/}} +{{- define "postgresql.readinessProbeCommand" -}} +- | +{{- if (include "postgresql.database" .) }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- else }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- end }} +{{- if contains "bitnami/" .Values.image.repository }} + [ -f /opt/bitnami/postgresql/tmp/.initialized ] || [ -f /bitnami/postgresql/.initialized ] +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "postgresql.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "postgresql.validateValues.ldapConfigurationMethod" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.psp" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If ldap.url is used then you don't need the other settings for ldap +*/}} +{{- define "postgresql.validateValues.ldapConfigurationMethod" -}} +{{- if and .Values.ldap.enabled (and (not (empty .Values.ldap.url)) (not (empty .Values.ldap.server))) }} +postgresql: ldap.url, ldap.server + You cannot set both `ldap.url` and `ldap.server` at the same time. + Please provide a unique way to configure LDAP. + More info at https://www.postgresql.org/docs/current/auth-ldap.html +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If PSP is enabled RBAC should be enabled too +*/}} +{{- define "postgresql.validateValues.psp" -}} +{{- if and .Values.psp.create (not .Values.rbac.create) }} +postgresql: psp.create, rbac.create + RBAC should be enabled if PSP is enabled in order for PSP to work. + More info at https://kubernetes.io/docs/concepts/policy/pod-security-policy/#authorizing-policies +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- if semverCompare "<1.10-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "postgresql.networkPolicy.apiVersion" -}} +{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"extensions/v1beta1" +{{- else if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"networking.k8s.io/v1" +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql TLS - When TLS is enabled, so must be VolumePermissions +*/}} +{{- define "postgresql.validateValues.tls" -}} +{{- if and .Values.tls.enabled (not .Values.volumePermissions.enabled) }} +postgresql: tls.enabled, volumePermissions.enabled + When TLS is enabled you must enable volumePermissions as well to ensure certificates files have + the right permissions. +{{- end -}} +{{- end -}} + +{{/* +Return the path to the cert file. +*/}} +{{- define "postgresql.tlsCert" -}} +{{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the cert key file. +*/}} +{{- define "postgresql.tlsCertKey" -}} +{{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the CA cert file. +*/}} +{{- define "postgresql.tlsCACert" -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.certCAFilename -}} +{{- end -}} + +{{/* +Return the path to the CRL file. +*/}} +{{- define "postgresql.tlsCRL" -}} +{{- if .Values.tls.crlFilename -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.crlFilename -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/configmap.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/configmap.yaml new file mode 100644 index 000000000..4508f95a4 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{ if and (or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration) (not .Values.configurationConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- if (.Files.Glob "files/postgresql.conf") }} +{{ (.Files.Glob "files/postgresql.conf").AsConfig | indent 2 }} +{{- else if .Values.postgresqlConfiguration }} + postgresql.conf: | +{{- range $key, $value := default dict .Values.postgresqlConfiguration }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- if (.Files.Glob "files/pg_hba.conf") }} +{{ (.Files.Glob "files/pg_hba.conf").AsConfig | indent 2 }} +{{- else if .Values.pgHbaConfiguration }} + pg_hba.conf: | +{{ .Values.pgHbaConfiguration | indent 4 }} +{{- end }} +{{ end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extended-config-configmap.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extended-config-configmap.yaml new file mode 100644 index 000000000..5ccdb08f8 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extended-config-configmap.yaml @@ -0,0 +1,21 @@ +{{- if and (or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf) (not .Values.extendedConfConfigMap)}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-extended-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- with .Files.Glob "files/conf.d/*.conf" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{ with .Values.postgresqlExtendedConf }} + override.conf: | +{{- range $key, $value := . }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extra-list.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extra-list.yaml new file mode 100644 index 000000000..9ac65f9e1 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/initialization-configmap.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/initialization-configmap.yaml new file mode 100644 index 000000000..074ed5827 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/initialization-configmap.yaml @@ -0,0 +1,24 @@ +{{- if and (or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScripts) (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-init-scripts + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.sql.gz" }} +binaryData: +{{- range $path, $bytes := . }} + {{ base $path }}: {{ $.Files.Get $path | b64enc | quote }} +{{- end }} +{{- end }} +data: +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql}" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{- with .Values.initdbScripts }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-configmap.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-configmap.yaml new file mode 100644 index 000000000..6216eca84 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-configmap.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "postgresql.metricsCM" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + custom-metrics.yaml: {{ toYaml .Values.metrics.customMetrics | quote }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-svc.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-svc.yaml new file mode 100644 index 000000000..a8f7b3310 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/metrics-svc.yaml @@ -0,0 +1,25 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-metrics + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- toYaml .Values.metrics.service.annotations | nindent 4 }} +spec: + type: {{ .Values.metrics.service.type }} + {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }} + {{- end }} + ports: + - name: http-metrics + port: 9187 + targetPort: http-metrics + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/networkpolicy.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/networkpolicy.yaml new file mode 100644 index 000000000..ef48ba182 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/networkpolicy.yaml @@ -0,0 +1,38 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "postgresql.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + ingress: + # Allow inbound connections + - ports: + - port: {{ template "postgresql.port" . }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: +{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + role: read + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow prometheus scrapes + - ports: + - port: 9187 + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..a79ebf163 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/podsecuritypolicy.yaml @@ -0,0 +1,37 @@ +{{- if .Values.psp.create }} +apiVersion: {{ include "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + privileged: false + volumes: + - 'configMap' + - 'secret' + - 'persistentVolumeClaim' + - 'emptyDir' + - 'projected' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/prometheusrule.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/prometheusrule.yaml new file mode 100644 index 000000000..d0f408c78 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/prometheusrule.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "common.names.fullname" . }} +{{- with .Values.metrics.prometheusRule.namespace }} + namespace: {{ . }} +{{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- with .Values.metrics.prometheusRule.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: +{{- with .Values.metrics.prometheusRule.rules }} + groups: + - name: {{ template "postgresql.name" $ }} + rules: {{ tpl (toYaml .) $ | nindent 8 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/role.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/role.yaml new file mode 100644 index 000000000..5a6de3350 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/role.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + {{- if .Values.psp.create }} + - apiGroups: ["extensions"] + resources: ["podsecuritypolicies"] + verbs: ["use"] + resourceNames: + - {{ template "common.names.fullname" . }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/rolebinding.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/rolebinding.yaml new file mode 100644 index 000000000..2bdb1c5ea --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + kind: Role + name: {{ template "common.names.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/secrets.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/secrets.yaml new file mode 100644 index 000000000..8351cbe8b --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/secrets.yaml @@ -0,0 +1,21 @@ +{{- if (include "postgresql.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + postgresql-postgres-password: {{ include "postgresql.postgres.password" . | b64enc | quote }} + postgresql-password: {{ include "postgresql.password" . | b64enc | quote }} + {{- if .Values.replication.enabled }} + postgresql-replication-password: {{ include "postgresql.replication.password" . | b64enc | quote }} + {{- end }} + {{- if (and .Values.ldap.enabled .Values.ldap.bind_password)}} + postgresql-ldap-password: {{ .Values.ldap.bind_password | b64enc | quote }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/serviceaccount.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/serviceaccount.yaml new file mode 100644 index 000000000..8cba31e43 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if and (.Values.serviceAccount.enabled) (not .Values.serviceAccount.name) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "common.labels.standard" . | nindent 4 }} + name: {{ template "common.names.fullname" . }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/servicemonitor.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/servicemonitor.yaml new file mode 100644 index 000000000..587ce85b8 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} + {{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + +spec: + endpoints: + - port: http-metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset-readreplicas.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset-readreplicas.yaml new file mode 100644 index 000000000..4d9d9b1ff --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset-readreplicas.yaml @@ -0,0 +1,392 @@ +{{- if .Values.replication.enabled }} +{{- $readReplicasResources := coalesce .Values.readReplicas.resources .Values.resources -}} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: "{{ template "common.names.fullname" . }}-read" + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: read +{{- with .Values.readReplicas.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.readReplicas.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: {{ .Values.replication.readReplicas }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: read + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: read + role: read +{{- with .Values.readReplicas.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.readReplicas.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.readReplicas.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAffinityPreset "component" "read" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAntiAffinityPreset "component" "read" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.readReplicas.nodeAffinityPreset.type "key" .Values.readReplicas.nodeAffinityPreset.key "values" .Values.readReplicas.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.readReplicas.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.readReplicas.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name}} + {{- end }} + {{- if or .Values.readReplicas.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{ if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.readReplicas.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.readReplicas.priorityClassName }} + priorityClassName: {{ .Values.readReplicas.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if $readReplicasResources }} + resources: {{- toYaml $readReplicasResources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + - name: POSTGRES_REPLICATION_MODE + value: "slave" + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + - name: POSTGRES_MASTER_HOST + value: {{ template "common.names.fullname" . }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ include "postgresql.port" . | quote }} + {{- if and (not (eq .Values.postgresqlUsername "postgres")) (or .Values.postgresqlPostgresPassword (include "postgresql.useExistingSecret" .)) }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- end }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- end }} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{ end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.readReplicas.extraVolumeMounts }} + {{- toYaml .Values.readReplicas.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.readReplicas.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.sidecars "context" $ ) | nindent 8 }} +{{- end }} + volumes: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} + {{- if or (not .Values.persistence.enabled) (not .Values.readReplicas.persistence.enabled) }} + - name: data + emptyDir: {} + {{- end }} + {{- if .Values.readReplicas.extraVolumes }} + {{- toYaml .Values.readReplicas.extraVolumes | nindent 8 }} + {{- end }} + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} +{{- if and .Values.persistence.enabled .Values.readReplicas.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset.yaml new file mode 100644 index 000000000..291b54cac --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/statefulset.yaml @@ -0,0 +1,558 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "postgresql.primary.fullname" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- with .Values.primary.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.primary.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: 1 + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: primary + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + role: primary + app.kubernetes.io/component: primary + {{- with .Values.primary.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.primary.podAnnotations }} + annotations: {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.primary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.primary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAffinityPreset "component" "primary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "component" "primary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.primary.nodeAffinityPreset.type "key" .Values.primary.nodeAffinityPreset.key "values" .Values.primary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.primary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.primary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + {{- end }} + {{- if or .Values.primary.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.primary.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.primary.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + {{- if .Values.postgresqlInitdbArgs }} + - name: POSTGRES_INITDB_ARGS + value: {{ .Values.postgresqlInitdbArgs | quote }} + {{- end }} + {{- if .Values.postgresqlInitdbWalDir }} + - name: POSTGRES_INITDB_WALDIR + value: {{ .Values.postgresqlInitdbWalDir | quote }} + {{- end }} + {{- if .Values.initdbUser }} + - name: POSTGRESQL_INITSCRIPTS_USERNAME + value: {{ .Values.initdbUser }} + {{- end }} + {{- if .Values.initdbPassword }} + - name: POSTGRESQL_INITSCRIPTS_PASSWORD + value: {{ .Values.initdbPassword }} + {{- end }} + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + {{- if .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_MASTER_HOST + value: {{ .Values.primaryAsStandBy.primaryHost }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ .Values.primaryAsStandBy.primaryPort | quote }} + {{- end }} + {{- if or .Values.replication.enabled .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_REPLICATION_MODE + {{- if .Values.primaryAsStandBy.enabled }} + value: "slave" + {{- else }} + value: "master" + {{- end }} + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- end }} + {{- if not (eq .Values.replication.synchronousCommit "off")}} + - name: POSTGRES_SYNCHRONOUS_COMMIT_MODE + value: {{ .Values.replication.synchronousCommit | quote }} + - name: POSTGRES_NUM_SYNCHRONOUS_REPLICAS + value: {{ .Values.replication.numSynchronousReplicas | quote }} + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + {{- end }} + {{- if not (eq (include "postgresql.username" .) "postgres") }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- end }} + {{- end }} + - name: POSTGRES_USER + value: {{ include "postgresql.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- end }} + {{- if (include "postgresql.database" .) }} + - name: POSTGRES_DB + value: {{ (include "postgresql.database" .) | quote }} + {{- end }} + {{- if .Values.extraEnv }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnv "context" $) | nindent 12 }} + {{- end }} + - name: POSTGRESQL_ENABLE_LDAP + value: {{ ternary "yes" "no" .Values.ldap.enabled | quote }} + {{- if .Values.ldap.enabled }} + - name: POSTGRESQL_LDAP_SERVER + value: {{ .Values.ldap.server }} + - name: POSTGRESQL_LDAP_PORT + value: {{ .Values.ldap.port | quote }} + - name: POSTGRESQL_LDAP_SCHEME + value: {{ .Values.ldap.scheme }} + {{- if .Values.ldap.tls }} + - name: POSTGRESQL_LDAP_TLS + value: "1" + {{- end }} + - name: POSTGRESQL_LDAP_PREFIX + value: {{ .Values.ldap.prefix | quote }} + - name: POSTGRESQL_LDAP_SUFFIX + value: {{ .Values.ldap.suffix | quote }} + - name: POSTGRESQL_LDAP_BASE_DN + value: {{ .Values.ldap.baseDN }} + - name: POSTGRESQL_LDAP_BIND_DN + value: {{ .Values.ldap.bindDN }} + - name: POSTGRESQL_LDAP_SEARCH_ATTR + value: {{ .Values.ldap.search_attr }} + - name: POSTGRESQL_LDAP_SEARCH_FILTER + value: {{ .Values.ldap.search_filter }} + - name: POSTGRESQL_LDAP_URL + value: {{ .Values.ldap.url }} + {{- end}} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + {{- if .Values.extraEnvVarsCM }} + envFrom: + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d/ + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + mountPath: /docker-entrypoint-initdb.d/secret + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.primary.extraVolumeMounts }} + {{- toYaml .Values.primary.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.primary.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.primary.sidecars "context" $ ) | nindent 8 }} +{{- end }} +{{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "postgresql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.securityContext.enabled }} + securityContext: {{- omit .Values.metrics.securityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- $database := required "In order to enable metrics you need to specify a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase)" (include "postgresql.database" .) }} + {{- $sslmode := ternary "require" "disable" .Values.tls.enabled }} + {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} + - name: DATA_SOURCE_NAME + value: {{ printf "host=127.0.0.1 port=%d user=%s sslmode=%s sslcert=%s sslkey=%s" (int (include "postgresql.port" .)) (include "postgresql.username" .) $sslmode (include "postgresql.tlsCert" .) (include "postgresql.tlsCertKey" .) }} + {{- else }} + - name: DATA_SOURCE_URI + value: {{ printf "127.0.0.1:%d/%s?sslmode=%s" (int (include "postgresql.port" .)) $database $sslmode }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: DATA_SOURCE_PASS_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- end }} + - name: DATA_SOURCE_USER + value: {{ template "postgresql.username" . }} + {{- if .Values.metrics.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.metrics.customMetrics }} + - name: custom-metrics + mountPath: /conf + readOnly: true + args: ["--extend.query-path", "/conf/custom-metrics.yaml"] + {{- end }} + ports: + - name: http-metrics + containerPort: 9187 + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} +{{- end }} + volumes: + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "postgresql.initdbScriptsCM" . }} + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + secret: + secretName: {{ template "postgresql.initdbScriptsSecret" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.primary.extraVolumes }} + {{- toYaml .Values.primary.extraVolumes | nindent 8 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} + - name: custom-metrics + configMap: + name: {{ template "postgresql.metricsCM" . }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} +{{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: +{{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} +{{- end }} +{{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} +{{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-headless.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-headless.yaml new file mode 100644 index 000000000..6ad0dd5f2 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-headless.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-headless + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + # Use this annotation in addition to the actual publishNotReadyAddresses + # field below because the annotation will stop being respected soon but the + # field is broken in some versions of Kubernetes: + # https://github.com/kubernetes/kubernetes/issues/58662 + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +spec: + type: ClusterIP + clusterIP: None + # We want all pods in the StatefulSet to have their addresses published for + # the sake of the other Postgresql pods even before they're ready, since they + # have to be able to talk to each other in order to become ready. + publishNotReadyAddresses: true + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-read.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-read.yaml new file mode 100644 index 000000000..8c9ea54e8 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc-read.yaml @@ -0,0 +1,42 @@ +{{- if .Values.replication.enabled }} +{{- $serviceAnnotations := coalesce .Values.readReplicas.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.readReplicas.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.readReplicas.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.readReplicas.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.readReplicas.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.readReplicas.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-read + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: read +{{- end }} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc.yaml new file mode 100644 index 000000000..5bc2b50ee --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/templates/svc.yaml @@ -0,0 +1,40 @@ +{{- $serviceAnnotations := coalesce .Values.primary.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.primary.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.primary.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.primary.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.primary.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.primary.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/values-production.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/values-production.yaml new file mode 100644 index 000000000..4e1ee0416 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/values-production.yaml @@ -0,0 +1,791 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: true + user: repl_user + password: repl_password + readReplicas: 2 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + ## + synchronousCommit: "on" + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + ## + numSynchronousReplicas: 1 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +## existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +# usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: "" + server: "" + port: "" + prefix: "" + suffix: "" + baseDN: "" + bindDN: "" + bind_password: + search_attr: "" + search_filter: "" + scheme: "" + tls: {} + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read replica(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: "" + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Additional PostgreSQL Primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL Read Only Replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + ## Additional PostgreSQL Read Replica Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Read Replica Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Read Replicas + ## + service: {} + # type: + # nodePort: + # clusterIP: + ## Whether to enable PostgreSQL readReplicas replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for readReplicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: "" + # + # Certificate filename + certFilename: "" + # + # Certificate Key filename + certKeyFilename: "" + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: true + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9187" + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/values.schema.json b/sample-cnfs/sample_secret_env_no_ref/postgresql/values.schema.json new file mode 100644 index 000000000..66a2a9dd0 --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/values.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "postgresqlUsername": { + "type": "string", + "title": "Admin user", + "form": true + }, + "postgresqlPassword": { + "type": "string", + "title": "Password", + "form": true + }, + "persistence": { + "type": "object", + "properties": { + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi" + } + } + }, + "resources": { + "type": "object", + "title": "Required Resources", + "description": "Configure resource requests", + "form": true, + "properties": { + "requests": { + "type": "object", + "properties": { + "memory": { + "type": "string", + "form": true, + "render": "slider", + "title": "Memory Request", + "sliderMin": 10, + "sliderMax": 2048, + "sliderUnit": "Mi" + }, + "cpu": { + "type": "string", + "form": true, + "render": "slider", + "title": "CPU Request", + "sliderMin": 10, + "sliderMax": 2000, + "sliderUnit": "m" + } + } + } + } + }, + "replication": { + "type": "object", + "form": true, + "title": "Replication Details", + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable Replication", + "form": true + }, + "readReplicas": { + "type": "integer", + "title": "read Replicas", + "form": true, + "hidden": { + "value": false, + "path": "replication/enabled" + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable Init Containers", + "description": "Change the owner of the persist volume mountpoint to RunAsUser:fsGroup" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "title": "Configure metrics exporter", + "form": true + } + } + } + } +} diff --git a/sample-cnfs/sample_secret_env_no_ref/postgresql/values.yaml b/sample-cnfs/sample_secret_env_no_ref/postgresql/values.yaml new file mode 100644 index 000000000..4ef9ad1ba --- /dev/null +++ b/sample-cnfs/sample_secret_env_no_ref/postgresql/values.yaml @@ -0,0 +1,813 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: false + user: repl_user + password: repl_password + readReplicas: 1 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + synchronousCommit: 'off' + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + numSynchronousReplicas: 0 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +# existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: '' + server: '' + port: '' + prefix: '' + suffix: '' + baseDN: '' + bindDN: '' + bind_password: + search_attr: '' + search_filter: '' + scheme: '' + tls: {} + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: '' + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL read only replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL read replicas Volume mounts + ## + extraVolumeMounts: [] + + ## Additional PostgreSQL read replicas Volumes + ## + extraVolumes: [] + + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for read + ## + service: {} + # type: + # nodePort: + # clusterIP: + + ## Whether to enable PostgreSQL read replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for read replicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: '' + # + # Certificate filename + certFilename: '' + # + # Certificate Key filename + certKeyFilename: '' + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: false + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '9187' + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: '' + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size_bytes FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + # + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Array with extra yaml to deploy with the chart. Evaluated as a template +## +extraDeploy: [] diff --git a/sample-cnfs/sample_secret_volume/README.md b/sample-cnfs/sample_secret_volume/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_secret_volume/cnf-conformance.yml b/sample-cnfs/sample_secret_volume/cnf-conformance.yml new file mode 100644 index 000000000..acc776928 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/cnf-conformance.yml @@ -0,0 +1,10 @@ +--- +helm_directory: postgresql +git_clone_url: +install_script: chart +release_name: postgresql +service_name: postgresql +container_names: + - name: postgresql + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_secret_volume/postgresql/.helmignore b/sample-cnfs/sample_secret_volume/postgresql/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/sample-cnfs/sample_secret_volume/postgresql/Chart.lock b/sample-cnfs/sample_secret_volume/postgresql/Chart.lock new file mode 100644 index 000000000..00ef82278 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.1.2 +digest: sha256:5a5d1b6e8a55efef1c07768b6bb264c60c98e230792b9a63f85468b95cf58c45 +generated: "2020-12-11T12:22:28.510708+01:00" diff --git a/sample-cnfs/sample_secret_volume/postgresql/Chart.yaml b/sample-cnfs/sample_secret_volume/postgresql/Chart.yaml new file mode 100644 index 000000000..332cb9650 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/Chart.yaml @@ -0,0 +1,29 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 11.10.0 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.x.x +description: Chart for PostgreSQL, an object-relational database management system + (ORDBMS) with an emphasis on extensibility and on standards-compliance. +home: https://github.com/bitnami/charts/tree/master/bitnami/postgresql +icon: https://bitnami.com/assets/stacks/postgresql/img/postgresql-stack-110x117.png +keywords: +- postgresql +- postgres +- database +- sql +- replication +- cluster +maintainers: +- email: containers@bitnami.com + name: Bitnami +- email: cedric@desaintmartin.fr + name: desaintmartin +name: postgresql +sources: +- https://github.com/bitnami/bitnami-docker-postgresql +- https://www.postgresql.org/ +version: 10.2.0 diff --git a/sample-cnfs/sample_secret_volume/postgresql/README.md b/sample-cnfs/sample_secret_volume/postgresql/README.md new file mode 100644 index 000000000..9cf7c4128 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/README.md @@ -0,0 +1,798 @@ +# PostgreSQL + +[PostgreSQL](https://www.postgresql.org/) is an object-relational database management system (ORDBMS) with an emphasis on extensibility and on standards-compliance. + +For HA, please see [this repo](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) + +## TL;DR + +```console +$ helm repo add bitnami https://charts.bitnami.com/bitnami +$ helm install my-release bitnami/postgresql +``` + +## Introduction + +This chart bootstraps a [PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart +To install the chart with the release name `my-release`: + +```console +$ helm install my-release bitnami/postgresql +``` + +The command deploys PostgreSQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components but PVC's associated with the chart and deletes the release. + +To delete the PVC's associated with `my-release`: + +```console +$ kubectl delete pvc -l release=my-release +``` + +> **Note**: Deleting the PVC's will delete postgresql data as well. Please be cautious before doing it. + +## Parameters + +The following tables lists the configurable parameters of the PostgreSQL chart and their default values. + +| Parameter | Description | Default | +|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| +| `global.imageRegistry` | Global Docker Image registry | `nil` | +| `global.postgresql.postgresqlDatabase` | PostgreSQL database (overrides `postgresqlDatabase`) | `nil` | +| `global.postgresql.postgresqlUsername` | PostgreSQL username (overrides `postgresqlUsername`) | `nil` | +| `global.postgresql.existingSecret` | Name of existing secret to use for PostgreSQL passwords (overrides `existingSecret`) | `nil` | +| `global.postgresql.postgresqlPassword` | PostgreSQL admin password (overrides `postgresqlPassword`) | `nil` | +| `global.postgresql.servicePort` | PostgreSQL port (overrides `service.port`) | `nil` | +| `global.postgresql.replicationPassword` | Replication user password (overrides `replication.password`) | `nil` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | +| `global.storageClass` | Global storage class for dynamic provisioning | `nil` | +| `image.registry` | PostgreSQL Image registry | `docker.io` | +| `image.repository` | PostgreSQL Image name | `bitnami/postgresql` | +| `image.tag` | PostgreSQL Image tag | `{TAG_NAME}` | +| `image.pullPolicy` | PostgreSQL Image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `image.debug` | Specify if debug values should be set | `false` | +| `nameOverride` | String to partially override common.names.fullname template with a string (will prepend the release name) | `nil` | +| `fullnameOverride` | String to fully override common.names.fullname template with a string | `nil` | +| `volumePermissions.enabled` | Enable init container that changes volume permissions in the data directory (for cases where the default k8s `runAsUser` and `fsUser` values do not work) | `false` | +| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | +| `volumePermissions.image.repository` | Init container volume-permissions image name | `bitnami/minideb` | +| `volumePermissions.image.tag` | Init container volume-permissions image tag | `buster` | +| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `Always` | +| `volumePermissions.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container (when facing issues in OpenShift or uid unknown, try value "auto") | `0` | +| `usePasswordFile` | Have the secrets mounted as a file instead of env vars | `false` | +| `ldap.enabled` | Enable LDAP support | `false` | +| `ldap.existingSecret` | Name of existing secret to use for LDAP passwords | `nil` | +| `ldap.url` | LDAP URL beginning in the form `ldap[s]://host[:port]/basedn[?[attribute][?[scope][?[filter]]]]` | `nil` | +| `ldap.server` | IP address or name of the LDAP server. | `nil` | +| `ldap.port` | Port number on the LDAP server to connect to | `nil` | +| `ldap.scheme` | Set to `ldaps` to use LDAPS. | `nil` | +| `ldap.tls` | Set to `1` to use TLS encryption | `nil` | +| `ldap.prefix` | String to prepend to the user name when forming the DN to bind | `nil` | +| `ldap.suffix` | String to append to the user name when forming the DN to bind | `nil` | +| `ldap.search_attr` | Attribute to match against the user name in the search | `nil` | +| `ldap.search_filter` | The search filter to use when doing search+bind authentication | `nil` | +| `ldap.baseDN` | Root DN to begin the search for the user in | `nil` | +| `ldap.bindDN` | DN of user to bind to LDAP | `nil` | +| `ldap.bind_password` | Password for the user to bind to LDAP | `nil` | +| `replication.enabled` | Enable replication | `false` | +| `replication.user` | Replication user | `repl_user` | +| `replication.password` | Replication user password | `repl_password` | +| `replication.readReplicas` | Number of read replicas replicas | `1` | +| `replication.synchronousCommit` | Set synchronous commit mode. Allowed values: `on`, `remote_apply`, `remote_write`, `local` and `off` | `off` | +| `replication.numSynchronousReplicas` | Number of replicas that will have synchronous replication. Note: Cannot be greater than `replication.readReplicas`. | `0` | +| `replication.applicationName` | Cluster application name. Useful for advanced replication settings | `my_application` | +| `existingSecret` | Name of existing secret to use for PostgreSQL passwords. The secret has to contain the keys `postgresql-password` which is the password for `postgresqlUsername` when it is different of `postgres`, `postgresql-postgres-password` which will override `postgresqlPassword`, `postgresql-replication-password` which will override `replication.password` and `postgresql-ldap-password` which will be sed to authenticate on LDAP. The value is evaluated as a template. | `nil` | +| `postgresqlPostgresPassword` | PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`, in which case`postgres` is the admin username). | _random 10 character alphanumeric string_ | +| `postgresqlUsername` | PostgreSQL user (creates a non-admin user when `postgresqlUsername` is not `postgres`) | `postgres` | +| `postgresqlPassword` | PostgreSQL user password | _random 10 character alphanumeric string_ | +| `postgresqlDatabase` | PostgreSQL database | `nil` | +| `postgresqlDataDir` | PostgreSQL data dir folder | `/bitnami/postgresql` (same value as persistence.mountPath) | +| `extraEnv` | Any extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `[]` | +| `extraEnvVarsCM` | Name of a Config Map containing extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `nil` | +| `postgresqlInitdbArgs` | PostgreSQL initdb extra arguments | `nil` | +| `postgresqlInitdbWalDir` | PostgreSQL location for transaction log | `nil` | +| `postgresqlConfiguration` | Runtime Config Parameters | `nil` | +| `postgresqlExtendedConf` | Extended Runtime Config Parameters (appended to main or default configuration) | `nil` | +| `pgHbaConfiguration` | Content of pg_hba.conf | `nil (do not create pg_hba.conf)` | +| `postgresqlSharedPreloadLibraries` | Shared preload libraries (comma-separated list) | `pgaudit` | +| `postgresqlMaxConnections` | Maximum total connections | `nil` | +| `postgresqlPostgresConnectionLimit` | Maximum total connections for the postgres user | `nil` | +| `postgresqlDbUserConnectionLimit` | Maximum total connections for the non-admin user | `nil` | +| `postgresqlTcpKeepalivesInterval` | TCP keepalives interval | `nil` | +| `postgresqlTcpKeepalivesIdle` | TCP keepalives idle | `nil` | +| `postgresqlTcpKeepalivesCount` | TCP keepalives count | `nil` | +| `postgresqlStatementTimeout` | Statement timeout | `nil` | +| `postgresqlPghbaRemoveFilters` | Comma-separated list of patterns to remove from the pg_hba.conf file | `nil` | +| `customLivenessProbe` | Override default liveness probe | `nil` | +| `customReadinessProbe` | Override default readiness probe | `nil` | +| `audit.logHostname` | Add client hostnames to the log file | `false` | +| `audit.logConnections` | Add client log-in operations to the log file | `false` | +| `audit.logDisconnections` | Add client log-outs operations to the log file | `false` | +| `audit.pgAuditLog` | Add operations to log using the pgAudit extension | `nil` | +| `audit.clientMinMessages` | Message log level to share with the user | `nil` | +| `audit.logLinePrefix` | Template string for the log line prefix | `nil` | +| `audit.logTimezone` | Timezone for the log timestamps | `nil` | +| `configurationConfigMap` | ConfigMap with the PostgreSQL configuration files (Note: Overrides `postgresqlConfiguration` and `pgHbaConfiguration`). The value is evaluated as a template. | `nil` | +| `extendedConfConfigMap` | ConfigMap with the extended PostgreSQL configuration files. The value is evaluated as a template. | `nil` | +| `initdbScripts` | Dictionary of initdb scripts | `nil` | +| `initdbUser` | PostgreSQL user to execute the .sql and sql.gz scripts | `nil` | +| `initdbPassword` | Password for the user specified in `initdbUser` | `nil` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`). The value is evaluated as a template. | `nil` | +| `initdbScriptsSecret` | Secret with initdb scripts that contain sensitive information (Note: can be used with `initdbScriptsConfigMap` or `initdbScripts`). The value is evaluated as a template. | `nil` | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.port` | PostgreSQL port | `5432` | +| `service.nodePort` | Kubernetes Service nodePort | `nil` | +| `service.annotations` | Annotations for PostgreSQL service | `{}` (evaluated as a template) | +| `service.loadBalancerIP` | loadBalancerIP if service type is `LoadBalancer` | `nil` | +| `service.loadBalancerSourceRanges` | Address that are allowed when svc is LoadBalancer | `[]` (evaluated as a template) | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `shmVolume.enabled` | Enable emptyDir volume for /dev/shm for primary and read replica(s) Pod(s) | `true` | +| `shmVolume.chmod.enabled` | Run at init chmod 777 of the /dev/shm (ignored if `volumePermissions.enabled` is `false`) | `true` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim`, the value is evaluated as a template. | `nil` | +| `persistence.mountPath` | Path to mount the volume at | `/bitnami/postgresql` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `persistence.storageClass` | PVC Storage Class for PostgreSQL volume | `nil` | +| `persistence.accessModes` | PVC Access Mode for PostgreSQL volume | `[ReadWriteOnce]` | +| `persistence.size` | PVC Storage Request for PostgreSQL volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume (this value is evaluated as a template) | `{}` | +| `commonAnnotations` | Annotations to be added to all deployed resources (rendered as a template) | `{}` | +| `primary.podAffinityPreset` | PostgreSQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | PostgreSQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | PostgreSQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | PostgreSQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | PostgreSQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.nodeSelector` | Node labels for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.tolerations` | Tolerations for PostgreSQL primary pods assignment | `[]` (evaluated as a template) | + +| `primary.anotations` | Map of annotations to add to the statefulset (postgresql primary) | `{}` | +| `primary.labels` | Map of labels to add to the statefulset (postgresql primary) | `{}` | +| `primary.podAnnotations` | Map of annotations to add to the pods (postgresql primary) | `{}` | +| `primary.podLabels` | Map of labels to add to the pods (postgresql primary) | `{}` | +| `primary.priorityClassName` | Priority Class to use for each pod (postgresql primary) | `nil` | +| `primary.extraInitContainers` | Additional init containers to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumes` | Additional volumes to add to the pods (postgresql primary) | `[]` | +| `primary.sidecars` | Add additional containers to the pod | `[]` | +| `primary.service.type` | Allows using a different service type for primary | `nil` | +| `primary.service.nodePort` | Allows using a different nodePort for primary | `nil` | +| `primary.service.clusterIP` | Allows using a different clusterIP for primary | `nil` | +| `primaryAsStandBy.enabled` | Whether to enable current cluster's primary as standby server of another cluster or not. | `false` | +| `primaryAsStandBy.primaryHost` | The Host of replication primary in the other cluster. | `nil` | +| `primaryAsStandBy.primaryPort ` | The Port of replication primary in the other cluster. | `nil` | +| `readReplicas.podAffinityPreset` | PostgreSQL read only pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.podAntiAffinityPreset` | PostgreSQL read only pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `readReplicas.nodeAffinityPreset.type` | PostgreSQL read only node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.nodeAffinityPreset.key` | PostgreSQL read only node label key to match Ignored if `primary.affinity` is set. | `""` | +| `readReplicas.nodeAffinityPreset.values` | PostgreSQL read only node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `readReplicas.affinity` | Affinity for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.nodeSelector` | Node labels for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.anotations` | Map of annotations to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.resources` | CPU/Memory resource requests/limits override for readReplicass. Will fallback to `values.resources` if not defined. | `{}` | +| `readReplicas.labels` | Map of labels to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.podAnnotations` | Map of annotations to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.podLabels` | Map of labels to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.priorityClassName` | Priority Class to use for each pod (postgresql readReplicas) | `nil` | +| `readReplicas.extraInitContainers` | Additional init containers to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumes` | Additional volumes to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.sidecars` | Add additional containers to the pod | `[]` | +| `readReplicas.service.type` | Allows using a different service type for readReplicas | `nil` | +| `readReplicas.service.nodePort` | Allows using a different nodePort for readReplicas | `nil` | +| `readReplicas.service.clusterIP` | Allows using a different clusterIP for readReplicas | `nil` | +| `readReplicas.persistence.enabled` | Whether to enable readReplicas replicas persistence | `true` | +| `terminationGracePeriodSeconds` | Seconds the pod needs to terminate gracefully | `nil` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | +| `securityContext.*` | Other pod security context to be included as-is in the pod spec | `{}` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the pod | `1001` | +| `containerSecurityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `containerSecurityContext.enabled` | Enable container security context | `true` | +| `containerSecurityContext.runAsUser` | User ID for the container | `1001` | +| `serviceAccount.enabled` | Enable service account (Note: Service Account will only be automatically created if `serviceAccount.name` is not set) | `false` | +| `serviceAccount.name` | Name of existing service account | `nil` | +| `livenessProbe.enabled` | Would you like a livenessProbe to be enabled | `true` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed | `{}` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `tls.enabled` | Enable TLS traffic support | `false` | +| `tls.preferServerCiphers` | Whether to use the server's TLS cipher preferences rather than the client's | `true` | +| `tls.certificatesSecret` | Name of an existing secret that contains the certificates | `nil` | +| `tls.certFilename` | Certificate filename | `""` | +| `tls.certKeyFilename` | Certificate key filename | `""` | +| `tls.certCAFilename` | CA Certificate filename. If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate. | `nil` | +| `tls.crlFilename` | File containing a Certificate Revocation List | `nil` | +| `metrics.enabled` | Start a prometheus exporter | `false` | +| `metrics.service.type` | Kubernetes Service type | `ClusterIP` | +| `service.clusterIP` | Static clusterIP or None for headless services | `nil` | +| `metrics.service.annotations` | Additional annotations for metrics exporter pod | `{ prometheus.io/scrape: "true", prometheus.io/port: "9187"}` | +| `metrics.service.loadBalancerIP` | loadBalancerIP if redis metrics service type is `LoadBalancer` | `nil` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.namespace` | Optional namespace in which to create ServiceMonitor | `nil` | +| `metrics.serviceMonitor.interval` | Scrape interval. If not set, the Prometheus default scrape interval is used | `nil` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout. If not set, the Prometheus default scrape timeout is used | `nil` | +| `metrics.prometheusRule.enabled` | Set this to true to create prometheusRules for Prometheus operator | `false` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so prometheusRules will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.namespace` | namespace where prometheusRules resource should be created | the same namespace as postgresql | +| `metrics.prometheusRule.rules` | [rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) to be created, check values for an example. | `[]` | +| `metrics.image.registry` | PostgreSQL Exporter Image registry | `docker.io` | +| `metrics.image.repository` | PostgreSQL Exporter Image name | `bitnami/postgres-exporter` | +| `metrics.image.tag` | PostgreSQL Exporter Image tag | `{TAG_NAME}` | +| `metrics.image.pullPolicy` | PostgreSQL Exporter Image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `metrics.customMetrics` | Additional custom metrics | `nil` | +| `metrics.extraEnvVars` | Extra environment variables to add to exporter | `{}` (evaluated as a template) | +| `metrics.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `metrics.securityContext.enabled` | Enable security context for metrics | `false` | +| `metrics.securityContext.runAsUser` | User ID for the container for metrics | `1001` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `metrics.livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `metrics.readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 5 | +| `metrics.readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `updateStrategy` | Update strategy policy | `{type: "RollingUpdate"}` | +| `psp.create` | Create Pod Security Policy | `false` | +| `rbac.create` | Create Role and RoleBinding (required for PSP to work) | `false` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template). | `nil` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install my-release \ + --set postgresqlPassword=secretpassword,postgresqlDatabase=my-database \ + bitnami/postgresql +``` + +The above command sets the PostgreSQL `postgres` account password to `secretpassword`. Additionally it creates a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +$ helm install my-release -f values.yaml bitnami/postgresql +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) + +It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. + +Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. + +### Production configuration and horizontal scaling + +This chart includes a `values-production.yaml` file where you can find some parameters oriented to production configuration in comparison to the regular `values.yaml`. You can use this file instead of the default one. + +- Enable replication: +```diff +- replication.enabled: false ++ replication.enabled: true +``` + +- Number of read replicas: +```diff +- replication.readReplicas: 1 ++ replication.readReplicas: 2 +``` + +- Set synchronous commit mode: +```diff +- replication.synchronousCommit: "off" ++ replication.synchronousCommit: "on" +``` + +- Number of replicas that will have synchronous replication: +```diff +- replication.numSynchronousReplicas: 0 ++ replication.numSynchronousReplicas: 1 +``` + +- Start a prometheus exporter: +```diff +- metrics.enabled: false ++ metrics.enabled: true +``` + +To horizontally scale this chart, you can use the `--replicas` flag to modify the number of nodes in your PostgreSQL deployment. Also you can use the `values-production.yaml` file or modify the parameters shown above. + +### Customizing primary and read replica services in a replicated configuration + +At the top level, there is a service object which defines the services for both primary and readReplicas. For deeper customization, there are service objects for both the primary and read types individually. This allows you to override the values in the top level service object so that the primary and read can be of different service types and with different clusterIPs / nodePorts. Also in the case you want the primary and read to be of type nodePort, you will need to set the nodePorts to different values to prevent a collision. The values that are deeper in the primary.service or readReplicas.service objects will take precedence over the top level service object. + +### Change PostgreSQL version + +To modify the PostgreSQL version used in this chart you can specify a [valid image tag](https://hub.docker.com/r/bitnami/postgresql/tags/) using the `image.tag` parameter. For example, `image.tag=X.Y.Z`. This approach is also applicable to other images like exporters. + +### postgresql.conf / pg_hba.conf files as configMap + +This helm chart also supports to customize the whole configuration file. + +Add your custom file to "files/postgresql.conf" in your working directory. This file will be mounted as configMap to the containers and it will be used for configuring the PostgreSQL server. + +Alternatively, you can specify PostgreSQL configuration parameters using the `postgresqlConfiguration` parameter as a dict, using camelCase, e.g. {"sharedBuffers": "500MB"}. + +In addition to these options, you can also set an external ConfigMap with all the configuration files. This is done by setting the `configurationConfigMap` parameter. Note that this will override the two previous options. + +### Allow settings to be loaded from files other than the default `postgresql.conf` + +If you don't want to provide the whole PostgreSQL configuration file and only specify certain parameters, you can add your extended `.conf` files to "files/conf.d/" in your working directory. +Those files will be mounted as configMap to the containers adding/overwriting the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +Alternatively, you can also set an external ConfigMap with all the extra configuration files. This is done by setting the `extendedConfConfigMap` parameter. Note that this will override the previous option. + +### Initialize a fresh instance + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image allows you to use your custom scripts to initialize a fresh instance. In order to execute the scripts, they must be located inside the chart folder `files/docker-entrypoint-initdb.d` so they can be consumed as a ConfigMap. + +Alternatively, you can specify custom scripts using the `initdbScripts` parameter as dict. + +In addition to these options, you can also set an external ConfigMap with all the initialization scripts. This is done by setting the `initdbScriptsConfigMap` parameter. Note that this will override the two previous options. If your initialization scripts contain sensitive information such as credentials or passwords, you can use the `initdbScriptsSecret` parameter. + +The allowed extensions are `.sh`, `.sql` and `.sql.gz`. + +### Securing traffic using TLS + +TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the chart: + +- `tls.enabled`: Enable TLS support. Defaults to `false` +- `tls.certificatesSecret`: Name of an existing secret that contains the certificates. No defaults. +- `tls.certFilename`: Certificate filename. No defaults. +- `tls.certKeyFilename`: Certificate key filename. No defaults. + +For example: + +* First, create the secret with the cetificates files: + + ```console + kubectl create secret generic certificates-tls-secret --from-file=./cert.crt --from-file=./cert.key --from-file=./ca.crt + ``` + +* Then, use the following parameters: + + ```console + volumePermissions.enabled=true + tls.enabled=true + tls.certificatesSecret="certificates-tls-secret" + tls.certFilename="cert.crt" + tls.certKeyFilename="cert.key" + ``` + + > Note TLS and VolumePermissions: PostgreSQL requires certain permissions on sensitive files (such as certificate keys) to start up. Due to an on-going [issue](https://github.com/kubernetes/kubernetes/issues/57923) regarding kubernetes permissions and the use of `containerSecurityContext.runAsUser`, you must enable `volumePermissions` to ensure everything works as expected. + +### Sidecars + +If you need additional containers to run within the same pod as PostgreSQL (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +# For the PostgreSQL primary +primary: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +# For the PostgreSQL replicas +readReplicas: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +### Metrics + +The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9187) is not exposed and it is expected that the metrics are collected from inside the k8s cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). + +The exporter allows to create custom metrics from additional SQL queries. See the Chart's `values.yaml` for an example and consult the [exporters documentation](https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file) for more details. + +### Use of global variables + +In more complex scenarios, we may have the following tree of dependencies + +``` + +--------------+ + | | + +------------+ Chart 1 +-----------+ + | | | | + | --------+------+ | + | | | + | | | + | | | + | | | + v v v ++-------+------+ +--------+------+ +--------+------+ +| | | | | | +| PostgreSQL | | Sub-chart 1 | | Sub-chart 2 | +| | | | | | ++--------------+ +---------------+ +---------------+ +``` + +The three charts below depend on the parent chart Chart 1. However, subcharts 1 and 2 may need to connect to PostgreSQL as well. In order to do so, subcharts 1 and 2 need to know the PostgreSQL credentials, so one option for deploying could be deploy Chart 1 with the following parameters: + +``` +postgresql.postgresqlPassword=testtest +subchart1.postgresql.postgresqlPassword=testtest +subchart2.postgresql.postgresqlPassword=testtest +postgresql.postgresqlDatabase=db1 +subchart1.postgresql.postgresqlDatabase=db1 +subchart2.postgresql.postgresqlDatabase=db1 +``` + +If the number of dependent sub-charts increases, installing the chart with parameters can become increasingly difficult. An alternative would be to set the credentials using global variables as follows: + +``` +global.postgresql.postgresqlPassword=testtest +global.postgresql.postgresqlDatabase=db1 +``` + +This way, the credentials will be available in all of the subcharts. + +## Persistence + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image stores the PostgreSQL data and configurations at the `/bitnami/postgresql` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. +See the [Parameters](#parameters) section to configure the PVC or to disable persistence. + +If you already have data in it, you will fail to sync to standby nodes for all commits, details can refer to [code](https://github.com/bitnami/bitnami-docker-postgresql/blob/8725fe1d7d30ebe8d9a16e9175d05f7ad9260c93/9.6/debian-9/rootfs/libpostgresql.sh#L518-L556). If you need to use those data, please covert them to sql and import after `helm install` finished. + +## NetworkPolicy + +To enable network policy for PostgreSQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: + +```console +$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 5432. + +For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to PostgreSQL. +This label will be displayed in the output of a successful install. + +## Differences between Bitnami PostgreSQL image and [Docker Official](https://hub.docker.com/_/postgres) image + +- The Docker Official PostgreSQL image does not support replication. If you pass any replication environment variable, this would be ignored. The only environment variables supported by the Docker Official image are POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORD, POSTGRES_INITDB_ARGS, POSTGRES_INITDB_WALDIR and PGDATA. All the remaining environment variables are specific to the Bitnami PostgreSQL image. +- The Bitnami PostgreSQL image is non-root by default. This requires that you run the pod with `securityContext` and updates the permissions of the volume with an `initContainer`. A key benefit of this configuration is that the pod follows security best practices and is prepared to run on Kubernetes distributions with hard security constraints like OpenShift. +- For OpenShift, one may either define the runAsUser and fsGroup accordingly, or try this more dynamic option: volumePermissions.securityContext.runAsUser="auto",securityContext.enabled=false,containerSecurityContext.enabled=false,shmVolume.chmod.enabled=false + +### Deploy chart using Docker Official PostgreSQL Image + +From chart version 4.0.0, it is possible to use this chart with the Docker Official PostgreSQL image. +Besides specifying the new Docker repository and tag, it is important to modify the PostgreSQL data directory and volume mount point. Basically, the PostgreSQL data dir cannot be the mount point directly, it has to be a subdirectory. + +``` +image.repository=postgres +image.tag=10.6 +postgresqlDataDir=/data/pgdata +persistence.mountPath=/data/ +``` + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` paremeter(s). Find more infomation about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/master/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## Troubleshooting + +Find more information about how to deal with common errors related to Bitnami’s Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). + +## Upgrading + +It's necessary to specify the existing passwords while performing an upgrade to ensure the secrets are not updated with invalid randomly generated passwords. Remember to specify the existing values of the `postgresqlPassword` and `replication.password` parameters when upgrading the chart: + +```bash +$ helm upgrade my-release bitnami/postgresql \ + --set postgresqlPassword=[POSTGRESQL_PASSWORD] \ + --set replication.password=[REPLICATION_PASSWORD] +``` + +> Note: you need to substitute the placeholders _[POSTGRESQL_PASSWORD]_, and _[REPLICATION_PASSWORD]_ with the values obtained from instructions in the installation notes. + +### To 10.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Move dependency information from the *requirements.yaml* to the *Chart.yaml* +- After running `helm dependency update`, a *Chart.lock* file is generated containing the same structure used in the previous *requirements.lock* +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Chart. + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ + +#### Breaking changes + +- The term `master` has been replaced with `primary` and `slave` with `readReplicas` throughout the chart. Role names have changed from `master` and `slave` to `primary` and `read`. + +To upgrade to `10.0.0`, it should be done reusing the PVCs used to hold the PostgreSQL data on your previous release. To do so, follow the instructions below (the following example assumes that the release name is `postgresql`): + +> NOTE: Please, create a backup of your database before running any of those actions. + +Obtain the credentials and the names of the PVCs used to hold the PostgreSQL data on your current release: + +```console +$ export POSTGRESQL_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode) +$ export POSTGRESQL_PVC=$(kubectl get pvc -l app.kubernetes.io/instance=postgresql,role=master -o jsonpath="{.items[0].metadata.name}") +``` + +Delete the PostgreSQL statefulset. Notice the option `--cascade=false`: + +```console +$ kubectl delete statefulsets.apps postgresql-postgresql --cascade=false +``` + +Now the upgrade works: + +```console +$ helm upgrade postgresql bitnami/postgresql --set postgresqlPassword=$POSTGRESQL_PASSWORD --set persistence.existingClaim=$POSTGRESQL_PVC +``` + +You will have to delete the existing MariaDB pod and the new statefulset is going to create a new one + +```console +$ kubectl delete pod postgresql-postgresql-0 +``` + +Finally, you should see the lines below in MariaDB container logs: + +```console +$ kubectl logs $(kubectl get pods -l app.kubernetes.io/instance=postgresql,app.kubernetes.io/name=postgresql,role=primary -o jsonpath="{.items[0].metadata.name}") +... +postgresql 08:05:12.59 INFO ==> Deploying PostgreSQL with persisted data... +... +``` + +### To 9.0.0 + +In this version the chart was adapted to follow the Helm label best practices, see [PR 3021](https://github.com/bitnami/charts/pull/3021). That means the backward compatibility is not guarantee when upgrading the chart to this major version. + +As a workaround, you can delete the existing statefulset (using the `--cascade=false` flag pods are not deleted) before upgrade the chart. For example, this can be a valid workflow: + +- Deploy an old version (8.X.X) + +```console +$ helm install postgresql bitnami/postgresql --version 8.10.14 +``` + +- Old version is up and running + +```console +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 1 2020-08-04 13:39:54.783480286 +0000 UTC deployed postgresql-8.10.14 11.8.0 + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 76s +``` + +- The upgrade to the latest one (9.X.X) is going to fail + +```console +$ helm upgrade postgresql bitnami/postgresql +Error: UPGRADE FAILED: cannot patch "postgresql-postgresql" with kind StatefulSet: StatefulSet.apps "postgresql-postgresql" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden +``` + +- Delete the statefulset + +```console +$ kubectl delete statefulsets.apps --cascade=false postgresql-postgresql +statefulset.apps "postgresql-postgresql" deleted +``` + +- Now the upgrade works + +```console +$ helm upgrade postgresql bitnami/postgresql +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 3 2020-08-04 13:42:08.020385884 +0000 UTC deployed postgresql-9.1.2 11.8.0 +``` + +- We can kill the existing pod and the new statefulset is going to create a new one: + +```console +$ kubectl delete pod postgresql-postgresql-0 +pod "postgresql-postgresql-0" deleted + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 19s +``` + +Please, note that without the `--cascade=false` both objects (statefulset and pod) are going to be removed and both objects will be deployed again with the `helm upgrade` command + +### To 8.0.0 + +Prefixes the port names with their protocols to comply with Istio conventions. + +If you depend on the port names in your setup, make sure to update them to reflect this change. + +### To 7.1.0 + +Adds support for LDAP configuration. + +### To 7.0.0 + +Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. + +In https://github.com/helm/charts/pull/17281 the `apiVersion` of the statefulset resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. + +This major version bump signifies this change. + +### To 6.5.7 + +In this version, the chart will use PostgreSQL with the Postgis extension included. The version used with Postgresql version 10, 11 and 12 is Postgis 2.5. It has been compiled with the following dependencies: + +- protobuf +- protobuf-c +- json-c +- geos +- proj + +### To 5.0.0 + +In this version, the **chart is using PostgreSQL 11 instead of PostgreSQL 10**. You can find the main difference and notable changes in the following links: [https://www.postgresql.org/about/news/1894/](https://www.postgresql.org/about/news/1894/) and [https://www.postgresql.org/about/featurematrix/](https://www.postgresql.org/about/featurematrix/). + +For major releases of PostgreSQL, the internal data storage format is subject to change, thus complicating upgrades, you can see some errors like the following one in the logs: + +```console +Welcome to the Bitnami postgresql container +Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-postgresql +Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-postgresql/issues +Send us your feedback at containers@bitnami.com + +INFO ==> ** Starting PostgreSQL setup ** +NFO ==> Validating settings in POSTGRESQL_* env vars.. +INFO ==> Initializing PostgreSQL database... +INFO ==> postgresql.conf file not detected. Generating it... +INFO ==> pg_hba.conf file not detected. Generating it... +INFO ==> Deploying PostgreSQL with persisted data... +INFO ==> Configuring replication parameters +INFO ==> Loading custom scripts... +INFO ==> Enabling remote connections +INFO ==> Stopping PostgreSQL... +INFO ==> ** PostgreSQL setup finished! ** + +INFO ==> ** Starting PostgreSQL ** + [1] FATAL: database files are incompatible with server + [1] DETAIL: The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.3. +``` + +In this case, you should migrate the data from the old chart to the new one following an approach similar to that described in [this section](https://www.postgresql.org/docs/current/upgrading.html#UPGRADING-VIA-PGDUMPALL) from the official documentation. Basically, create a database dump in the old chart, move and restore it in the new one. + +### To 4.0.0 + +This chart will use by default the Bitnami PostgreSQL container starting from version `10.7.0-r68`. This version moves the initialization logic from node.js to bash. This new version of the chart requires setting the `POSTGRES_PASSWORD` in the slaves as well, in order to properly configure the `pg_hba.conf` file. Users from previous versions of the chart are advised to upgrade immediately. + +IMPORTANT: If you do not want to upgrade the chart version then make sure you use the `10.7.0-r68` version of the container. Otherwise, you will get this error + +``` +The POSTGRESQL_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development +``` + +### To 3.0.0 + +This releases make it possible to specify different nodeSelector, affinity and tolerations for master and slave pods. +It also fixes an issue with `postgresql.master.fullname` helper template not obeying fullnameOverride. + +#### Breaking changes + +- `affinty` has been renamed to `master.affinity` and `slave.affinity`. +- `tolerations` has been renamed to `master.tolerations` and `slave.tolerations`. +- `nodeSelector` has been renamed to `master.nodeSelector` and `slave.nodeSelector`. + +### To 2.0.0 + +In order to upgrade from the `0.X.X` branch to `1.X.X`, you should follow the below steps: + +- Obtain the service name (`SERVICE_NAME`) and password (`OLD_PASSWORD`) of the existing postgresql chart. You can find the instructions to obtain the password in the NOTES.txt, the service name can be obtained by running + +```console +$ kubectl get svc +``` + +- Install (not upgrade) the new version + +```console +$ helm repo update +$ helm install my-release bitnami/postgresql +``` + +- Connect to the new pod (you can obtain the name by running `kubectl get pods`): + +```console +$ kubectl exec -it NAME bash +``` + +- Once logged in, create a dump file from the previous database using `pg_dump`, for that we should connect to the previous postgresql chart: + +```console +$ pg_dump -h SERVICE_NAME -U postgres DATABASE_NAME > /tmp/backup.sql +``` + +After run above command you should be prompted for a password, this password is the previous chart password (`OLD_PASSWORD`). +This operation could take some time depending on the database size. + +- Once you have the backup file, you can restore it with a command like the one below: + +```console +$ psql -U postgres DATABASE_NAME < /tmp/backup.sql +``` + +In this case, you are accessing to the local postgresql, so the password should be the new one (you can find it in NOTES.txt). + +If you want to restore the database and the database schema does not exist, it is necessary to first follow the steps described below. + +```console +$ psql -U postgres +postgres=# drop database DATABASE_NAME; +postgres=# create database DATABASE_NAME; +postgres=# create user USER_NAME; +postgres=# alter role USER_NAME with password 'BITNAMI_USER_PASSWORD'; +postgres=# grant all privileges on database DATABASE_NAME to USER_NAME; +postgres=# alter database DATABASE_NAME owner to USER_NAME; +``` diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/.helmignore b/sample-cnfs/sample_secret_volume/postgresql/charts/common/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/Chart.yaml b/sample-cnfs/sample_secret_volume/postgresql/charts/common/Chart.yaml new file mode 100644 index 000000000..1bda8e2df --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 1.1.1 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://github.com/bitnami/charts/tree/master/bitnami/common +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- email: containers@bitnami.com + name: Bitnami +name: common +sources: +- https://github.com/bitnami/charts +- http://www.bitnami.com/ +type: library +version: 1.1.2 diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/README.md b/sample-cnfs/sample_secret_volume/postgresql/charts/common/README.md new file mode 100644 index 000000000..a68895368 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/README.md @@ -0,0 +1,309 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 0.x.x + repository: https://charts.bitnami.com/bitnami +``` + +```bash +$ helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ + +## Parameters + +The following table lists the helpers available in the library which are scoped in different sections. + +### Affinities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.node.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.pod.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.pod.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | + +### Capabilities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.capabilities.deployment.apiVersion` | Return the appropriate apiVersion for deployment. | `.` Chart context | +| `common.capabilities.statefulset.apiVersion` | Return the appropriate apiVersion for statefulset. | `.` Chart context | +| `common.capabilities.ingress.apiVersion` | Return the appropriate apiVersion for ingress. | `.` Chart context | + +### Errors + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.errors.upgrade.passwords.empty` | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01) "context" $` | + +### Images + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.images.image` | Return the proper and full image name | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure. | +| `common.images.pullSecrets` | Return the proper Docker Image Registry Secret Names | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global` | + +### Labels + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.labels.standard` | Return Kubernetes standard labels | `.` Chart context | +| `common.labels.matchLabels` | Return the proper Docker Image Registry Secret Names | `.` Chart context | + +### Names + +| Helper identifier | Description | Expected Inpput | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.names.name` | Expand the name of the chart or use `.Values.nameOverride` | `.` Chart context | +| `common.names.fullname` | Create a default fully qualified app name. | `.` Chart context | +| `common.names.chart` | Chart name plus version | `.` Chart context | + +### Secrets + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.secrets.name` | Generate the name of the secret. | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.key` | Generate secret key. | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure. | + +### Storage + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. | + +### TplValues + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.tplvalues.render` | Renders a value that contains template | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frecuently is the chart context `$` or `.` | + +### Utils + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.utils.fieldToEnvVar` | Build environment variable name given a field. | `dict "field" "my-password"` | +| `common.utils.secret.getvalue` | Print instructions to get a secret value. | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` | +| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path | `dict "key" "path.to.key" "context" $` | + +### Validations + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.validations.values.single.empty` | Validate a value must not be empty. | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "context" $` secret and field are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) | +| `common.validations.values.multiple.empty` | Validate a multiple values must not be empty. It returns a shared error for all the values. | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue) | +| `common.validations.values.mariadb.passwords` | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values. | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mariadb chart and the helper. | +| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values. | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper. | +| `common.validations.values.redis.passwords` | This helper will ensure required password for Redis are not empty. It returns a shared error for all the values. | `dict "secret" "redis-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use redis chart and the helper. | +| `common.validations.values.cassandra.passwords` | This helper will ensure required password for Cassandra are not empty. It returns a shared error for all the values. | `dict "secret" "cassandra-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use cassandra chart and the helper. | +| `common.validations.values.mongodb.passwords` | This helper will ensure required password for MongoDB are not empty. It returns a shared error for all the values. | `dict "secret" "mongodb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mongodb chart and the helper. | + +### Warnings + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.warnings.rollingTag` | Warning about using rolling tag. | `ImageRoot` see [ImageRoot](#imageroot) for the structure. | + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets. + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possiblity of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +$ helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 --decode) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 --decode) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_affinities.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_affinities.tpl new file mode 100644 index 000000000..1ff26d585 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_affinities.tpl @@ -0,0 +1,94 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname + weight: 1 +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_capabilities.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_capabilities.tpl new file mode 100644 index 000000000..143bef2a4 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_capabilities.tpl @@ -0,0 +1,33 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_errors.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_errors.tpl new file mode 100644 index 000000000..d6d3ec65a --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_errors.tpl @@ -0,0 +1,20 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: you must provide your current passwords when upgrade the release%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_images.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_images.tpl new file mode 100644 index 000000000..aafde9f3b --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_images.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $tag := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_labels.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_labels.tpl new file mode 100644 index 000000000..252066c7e --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_labels.tpl @@ -0,0 +1,18 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Kubernetes standard labels +*/}} +{{- define "common.labels.standard" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector +*/}} +{{- define "common.labels.matchLabels" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_names.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_names.tpl new file mode 100644 index 000000000..adf2a74f4 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_names.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "common.names.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_secrets.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_secrets.tpl new file mode 100644 index 000000000..ebfb5d42d --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_secrets.tpl @@ -0,0 +1,57 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- $name = .name -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_storage.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_storage.tpl new file mode 100644 index 000000000..60e2a844f --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_storage.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} + +{{- $storageClass := .persistence.storageClass -}} +{{- if .global -}} + {{- if .global.storageClass -}} + {{- $storageClass = .global.storageClass -}} + {{- end -}} +{{- end -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl new file mode 100644 index 000000000..2db166851 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,13 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "common.tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_utils.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_utils.tpl new file mode 100644 index 000000000..74774a3ca --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_utils.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_warnings.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_warnings.tpl new file mode 100644 index 000000000..ae10fa41e --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/_warnings.tpl @@ -0,0 +1,14 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ +{{- end }} + +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 000000000..7a274a08c --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 000000000..3bf669dd8 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 000000000..7e0c1cbc3 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,108 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (not $existingSecret) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 000000000..f25e0ffbf --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,131 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl new file mode 100644 index 000000000..2ccc04d2d --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,72 @@ + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $existingSecret := include "common.redis.values.existingSecret" . -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $valueKeyRedisPassword := printf "%s%s" $valueKeyPrefix "password" -}} + {{- $valueKeyRedisUsePassword := printf "%s%s" $valueKeyPrefix "usePassword" -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $usePassword := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUsePassword "context" .context) -}} + {{- if eq $usePassword "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Redis Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.redis.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.redis.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl new file mode 100644 index 000000000..d4cf32c77 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,44 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s=$%s' to the command.%s" .valueKey .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/charts/common/values.yaml b/sample-cnfs/sample_secret_volume/postgresql/charts/common/values.yaml new file mode 100644 index 000000000..9ecdc93f5 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/charts/common/values.yaml @@ -0,0 +1,3 @@ +## bitnami/common +## It is required by CI/CD tools and processes. +exampleValue: common-chart diff --git a/sample-cnfs/sample_secret_volume/postgresql/ci/commonAnnotations.yaml b/sample-cnfs/sample_secret_volume/postgresql/ci/commonAnnotations.yaml new file mode 100644 index 000000000..97e18a4cc --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/ci/commonAnnotations.yaml @@ -0,0 +1,3 @@ +commonAnnotations: + helm.sh/hook: "\"pre-install, pre-upgrade\"" + helm.sh/hook-weight: "-1" diff --git a/sample-cnfs/sample_secret_volume/postgresql/ci/default-values.yaml b/sample-cnfs/sample_secret_volume/postgresql/ci/default-values.yaml new file mode 100644 index 000000000..fc2ba605a --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/ci/default-values.yaml @@ -0,0 +1 @@ +# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml. diff --git a/sample-cnfs/sample_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml b/sample-cnfs/sample_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml new file mode 100644 index 000000000..347d3b40a --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml @@ -0,0 +1,2 @@ +shmVolume: + enabled: false diff --git a/sample-cnfs/sample_secret_volume/postgresql/files/README.md b/sample-cnfs/sample_secret_volume/postgresql/files/README.md new file mode 100644 index 000000000..1813a2fea --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/files/README.md @@ -0,0 +1 @@ +Copy here your postgresql.conf and/or pg_hba.conf files to use it as a config map. diff --git a/sample-cnfs/sample_secret_volume/postgresql/files/conf.d/README.md b/sample-cnfs/sample_secret_volume/postgresql/files/conf.d/README.md new file mode 100644 index 000000000..184c1875d --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/files/conf.d/README.md @@ -0,0 +1,4 @@ +If you don't want to provide the whole configuration file and only specify certain parameters, you can copy here your extended `.conf` files. +These files will be injected as a config maps and add/overwrite the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +More info in the [bitnami-docker-postgresql README](https://github.com/bitnami/bitnami-docker-postgresql#configuration-file). diff --git a/sample-cnfs/sample_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md b/sample-cnfs/sample_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md new file mode 100644 index 000000000..cba38091e --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md @@ -0,0 +1,3 @@ +You can copy here your custom `.sh`, `.sql` or `.sql.gz` file so they are executed during the first boot of the image. + +More info in the [bitnami-docker-postgresql](https://github.com/bitnami/bitnami-docker-postgresql#initializing-a-new-instance) repository. \ No newline at end of file diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/NOTES.txt b/sample-cnfs/sample_secret_volume/postgresql/templates/NOTES.txt new file mode 100644 index 000000000..4e98958c1 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/NOTES.txt @@ -0,0 +1,59 @@ +** Please be patient while the chart is being deployed ** + +PostgreSQL can be accessed via port {{ template "postgresql.port" . }} on the following DNS name from within your cluster: + + {{ template "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - Read/Write connection +{{- if .Values.replication.enabled }} + {{ template "common.names.fullname" . }}-read.{{ .Release.Namespace }}.svc.cluster.local - Read only connection +{{- end }} + +{{- if not (eq (include "postgresql.username" .) "postgres") }} + +To get the password for "postgres" run: + + export POSTGRES_ADMIN_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-postgres-password}" | base64 --decode) +{{- end }} + +To get the password for "{{ template "postgresql.username" . }}" run: + + export POSTGRES_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-password}" | base64 --decode) + +To connect to your database run the following command: + + kubectl run {{ template "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --namespace {{ .Release.Namespace }} --image {{ template "postgresql.image" . }} --env="PGPASSWORD=$POSTGRES_PASSWORD" {{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} + --labels="{{ template "common.names.fullname" . }}-client=true" {{- end }} --command -- psql --host {{ template "common.names.fullname" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to this PostgreSQL cluster. +{{- end }} + +To connect to your database from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $NODE_IP --port $NODE_PORT -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $SERVICE_IP --port {{ template "postgresql.port" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "common.names.fullname" . }} {{ template "postgresql.port" . }}:{{ template "postgresql.port" . }} & + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host 127.0.0.1 -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{- end }} + +{{- include "postgresql.validateValues" . -}} + +{{- include "common.warnings.rollingTag" .Values.image -}} + +{{- $passwordValidationErrors := include "common.validations.values.postgresql.passwords" (dict "secret" (include "common.names.fullname" .) "context" $) -}} + +{{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $passwordValidationErrors) "context" $) -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/_helpers.tpl b/sample-cnfs/sample_secret_volume/postgresql/templates/_helpers.tpl new file mode 100644 index 000000000..7509941cf --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/_helpers.tpl @@ -0,0 +1,330 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "postgresql.primary.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- $fullname := default (printf "%s-%s" .Release.Name $name) .Values.fullnameOverride -}} +{{- if .Values.replication.enabled -}} +{{- printf "%s-%s" $fullname "primary" | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $fullname | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper PostgreSQL image name +*/}} +{{- define "postgresql.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper PostgreSQL metrics image name +*/}} +{{- define "postgresql.metrics.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "postgresql.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "postgresql.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Return PostgreSQL postgres user password +*/}} +{{- define "postgresql.postgres.password" -}} +{{- if .Values.global.postgresql.postgresqlPostgresPassword }} + {{- .Values.global.postgresql.postgresqlPostgresPassword -}} +{{- else if .Values.postgresqlPostgresPassword -}} + {{- .Values.postgresqlPostgresPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL password +*/}} +{{- define "postgresql.password" -}} +{{- if .Values.global.postgresql.postgresqlPassword }} + {{- .Values.global.postgresql.postgresqlPassword -}} +{{- else if .Values.postgresqlPassword -}} + {{- .Values.postgresqlPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication password +*/}} +{{- define "postgresql.replication.password" -}} +{{- if .Values.global.postgresql.replicationPassword }} + {{- .Values.global.postgresql.replicationPassword -}} +{{- else if .Values.replication.password -}} + {{- .Values.replication.password -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL username +*/}} +{{- define "postgresql.username" -}} +{{- if .Values.global.postgresql.postgresqlUsername }} + {{- .Values.global.postgresql.postgresqlUsername -}} +{{- else -}} + {{- .Values.postgresqlUsername -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication username +*/}} +{{- define "postgresql.replication.username" -}} +{{- if .Values.global.postgresql.replicationUser }} + {{- .Values.global.postgresql.replicationUser -}} +{{- else -}} + {{- .Values.replication.user -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL port +*/}} +{{- define "postgresql.port" -}} +{{- if .Values.global.postgresql.servicePort }} + {{- .Values.global.postgresql.servicePort -}} +{{- else -}} + {{- .Values.service.port -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL created database +*/}} +{{- define "postgresql.database" -}} +{{- if .Values.global.postgresql.postgresqlDatabase }} + {{- .Values.global.postgresql.postgresqlDatabase -}} +{{- else if .Values.postgresqlDatabase -}} + {{- .Values.postgresqlDatabase -}} +{{- end -}} +{{- end -}} + +{{/* +Get the password secret. +*/}} +{{- define "postgresql.secretName" -}} +{{- if .Values.global.postgresql.existingSecret }} + {{- printf "%s" (tpl .Values.global.postgresql.existingSecret $) -}} +{{- else if .Values.existingSecret -}} + {{- printf "%s" (tpl .Values.existingSecret $) -}} +{{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if we should use an existingSecret. +*/}} +{{- define "postgresql.useExistingSecret" -}} +{{- if or .Values.global.postgresql.existingSecret .Values.existingSecret -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created +*/}} +{{- define "postgresql.createSecret" -}} +{{- if not (include "postgresql.useExistingSecret" .) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the configuration ConfigMap name. +*/}} +{{- define "postgresql.configurationCM" -}} +{{- if .Values.configurationConfigMap -}} +{{- printf "%s" (tpl .Values.configurationConfigMap $) -}} +{{- else -}} +{{- printf "%s-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the extended configuration ConfigMap name. +*/}} +{{- define "postgresql.extendedConfigurationCM" -}} +{{- if .Values.extendedConfConfigMap -}} +{{- printf "%s" (tpl .Values.extendedConfConfigMap $) -}} +{{- else -}} +{{- printf "%s-extended-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap should be mounted with PostgreSQL configuration +*/}} +{{- define "postgresql.mountConfigurationCM" -}} +{{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "postgresql.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts Secret name. +*/}} +{{- define "postgresql.initdbScriptsSecret" -}} +{{- printf "%s" (tpl .Values.initdbScriptsSecret $) -}} +{{- end -}} + +{{/* +Get the metrics ConfigMap name. +*/}} +{{- define "postgresql.metricsCM" -}} +{{- printf "%s-metrics" (include "common.names.fullname" .) -}} +{{- end -}} + +{{/* +Get the readiness probe command +*/}} +{{- define "postgresql.readinessProbeCommand" -}} +- | +{{- if (include "postgresql.database" .) }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- else }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- end }} +{{- if contains "bitnami/" .Values.image.repository }} + [ -f /opt/bitnami/postgresql/tmp/.initialized ] || [ -f /bitnami/postgresql/.initialized ] +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "postgresql.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "postgresql.validateValues.ldapConfigurationMethod" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.psp" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If ldap.url is used then you don't need the other settings for ldap +*/}} +{{- define "postgresql.validateValues.ldapConfigurationMethod" -}} +{{- if and .Values.ldap.enabled (and (not (empty .Values.ldap.url)) (not (empty .Values.ldap.server))) }} +postgresql: ldap.url, ldap.server + You cannot set both `ldap.url` and `ldap.server` at the same time. + Please provide a unique way to configure LDAP. + More info at https://www.postgresql.org/docs/current/auth-ldap.html +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If PSP is enabled RBAC should be enabled too +*/}} +{{- define "postgresql.validateValues.psp" -}} +{{- if and .Values.psp.create (not .Values.rbac.create) }} +postgresql: psp.create, rbac.create + RBAC should be enabled if PSP is enabled in order for PSP to work. + More info at https://kubernetes.io/docs/concepts/policy/pod-security-policy/#authorizing-policies +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- if semverCompare "<1.10-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "postgresql.networkPolicy.apiVersion" -}} +{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"extensions/v1beta1" +{{- else if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"networking.k8s.io/v1" +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql TLS - When TLS is enabled, so must be VolumePermissions +*/}} +{{- define "postgresql.validateValues.tls" -}} +{{- if and .Values.tls.enabled (not .Values.volumePermissions.enabled) }} +postgresql: tls.enabled, volumePermissions.enabled + When TLS is enabled you must enable volumePermissions as well to ensure certificates files have + the right permissions. +{{- end -}} +{{- end -}} + +{{/* +Return the path to the cert file. +*/}} +{{- define "postgresql.tlsCert" -}} +{{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the cert key file. +*/}} +{{- define "postgresql.tlsCertKey" -}} +{{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the CA cert file. +*/}} +{{- define "postgresql.tlsCACert" -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.certCAFilename -}} +{{- end -}} + +{{/* +Return the path to the CRL file. +*/}} +{{- define "postgresql.tlsCRL" -}} +{{- if .Values.tls.crlFilename -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.crlFilename -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/configmap.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/configmap.yaml new file mode 100644 index 000000000..4508f95a4 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{ if and (or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration) (not .Values.configurationConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- if (.Files.Glob "files/postgresql.conf") }} +{{ (.Files.Glob "files/postgresql.conf").AsConfig | indent 2 }} +{{- else if .Values.postgresqlConfiguration }} + postgresql.conf: | +{{- range $key, $value := default dict .Values.postgresqlConfiguration }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- if (.Files.Glob "files/pg_hba.conf") }} +{{ (.Files.Glob "files/pg_hba.conf").AsConfig | indent 2 }} +{{- else if .Values.pgHbaConfiguration }} + pg_hba.conf: | +{{ .Values.pgHbaConfiguration | indent 4 }} +{{- end }} +{{ end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/extended-config-configmap.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/extended-config-configmap.yaml new file mode 100644 index 000000000..5ccdb08f8 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/extended-config-configmap.yaml @@ -0,0 +1,21 @@ +{{- if and (or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf) (not .Values.extendedConfConfigMap)}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-extended-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- with .Files.Glob "files/conf.d/*.conf" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{ with .Values.postgresqlExtendedConf }} + override.conf: | +{{- range $key, $value := . }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/extra-list.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/extra-list.yaml new file mode 100644 index 000000000..9ac65f9e1 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/initialization-configmap.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/initialization-configmap.yaml new file mode 100644 index 000000000..074ed5827 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/initialization-configmap.yaml @@ -0,0 +1,24 @@ +{{- if and (or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScripts) (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-init-scripts + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.sql.gz" }} +binaryData: +{{- range $path, $bytes := . }} + {{ base $path }}: {{ $.Files.Get $path | b64enc | quote }} +{{- end }} +{{- end }} +data: +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql}" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{- with .Values.initdbScripts }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-configmap.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-configmap.yaml new file mode 100644 index 000000000..6216eca84 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-configmap.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "postgresql.metricsCM" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + custom-metrics.yaml: {{ toYaml .Values.metrics.customMetrics | quote }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-svc.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-svc.yaml new file mode 100644 index 000000000..a8f7b3310 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/metrics-svc.yaml @@ -0,0 +1,25 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-metrics + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- toYaml .Values.metrics.service.annotations | nindent 4 }} +spec: + type: {{ .Values.metrics.service.type }} + {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }} + {{- end }} + ports: + - name: http-metrics + port: 9187 + targetPort: http-metrics + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/networkpolicy.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/networkpolicy.yaml new file mode 100644 index 000000000..ef48ba182 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/networkpolicy.yaml @@ -0,0 +1,38 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "postgresql.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + ingress: + # Allow inbound connections + - ports: + - port: {{ template "postgresql.port" . }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: +{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + role: read + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow prometheus scrapes + - ports: + - port: 9187 + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..a79ebf163 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/podsecuritypolicy.yaml @@ -0,0 +1,37 @@ +{{- if .Values.psp.create }} +apiVersion: {{ include "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + privileged: false + volumes: + - 'configMap' + - 'secret' + - 'persistentVolumeClaim' + - 'emptyDir' + - 'projected' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/prometheusrule.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/prometheusrule.yaml new file mode 100644 index 000000000..d0f408c78 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/prometheusrule.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "common.names.fullname" . }} +{{- with .Values.metrics.prometheusRule.namespace }} + namespace: {{ . }} +{{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- with .Values.metrics.prometheusRule.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: +{{- with .Values.metrics.prometheusRule.rules }} + groups: + - name: {{ template "postgresql.name" $ }} + rules: {{ tpl (toYaml .) $ | nindent 8 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/role.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/role.yaml new file mode 100644 index 000000000..5a6de3350 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/role.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + {{- if .Values.psp.create }} + - apiGroups: ["extensions"] + resources: ["podsecuritypolicies"] + verbs: ["use"] + resourceNames: + - {{ template "common.names.fullname" . }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/rolebinding.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/rolebinding.yaml new file mode 100644 index 000000000..2bdb1c5ea --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + kind: Role + name: {{ template "common.names.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/secrets.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/secrets.yaml new file mode 100644 index 000000000..8351cbe8b --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/secrets.yaml @@ -0,0 +1,21 @@ +{{- if (include "postgresql.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + postgresql-postgres-password: {{ include "postgresql.postgres.password" . | b64enc | quote }} + postgresql-password: {{ include "postgresql.password" . | b64enc | quote }} + {{- if .Values.replication.enabled }} + postgresql-replication-password: {{ include "postgresql.replication.password" . | b64enc | quote }} + {{- end }} + {{- if (and .Values.ldap.enabled .Values.ldap.bind_password)}} + postgresql-ldap-password: {{ .Values.ldap.bind_password | b64enc | quote }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/serviceaccount.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/serviceaccount.yaml new file mode 100644 index 000000000..8cba31e43 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if and (.Values.serviceAccount.enabled) (not .Values.serviceAccount.name) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "common.labels.standard" . | nindent 4 }} + name: {{ template "common.names.fullname" . }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/servicemonitor.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/servicemonitor.yaml new file mode 100644 index 000000000..587ce85b8 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} + {{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + +spec: + endpoints: + - port: http-metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset-readreplicas.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset-readreplicas.yaml new file mode 100644 index 000000000..1f5b97043 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset-readreplicas.yaml @@ -0,0 +1,410 @@ +{{- if .Values.replication.enabled }} +{{- $readReplicasResources := coalesce .Values.readReplicas.resources .Values.resources -}} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: "{{ template "common.names.fullname" . }}-read" + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: read +{{- with .Values.readReplicas.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.readReplicas.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: {{ .Values.replication.readReplicas }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: read + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: read + role: read +{{- with .Values.readReplicas.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.readReplicas.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.readReplicas.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAffinityPreset "component" "read" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAntiAffinityPreset "component" "read" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.readReplicas.nodeAffinityPreset.type "key" .Values.readReplicas.nodeAffinityPreset.key "values" .Values.readReplicas.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.readReplicas.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.readReplicas.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name}} + {{- end }} + {{- if or .Values.readReplicas.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{ if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.readReplicas.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.readReplicas.priorityClassName }} + priorityClassName: {{ .Values.readReplicas.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if $readReplicasResources }} + resources: {{- toYaml $readReplicasResources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + - name: POSTGRES_REPLICATION_MODE + value: "slave" + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + - name: POSTGRES_MASTER_HOST + value: {{ template "common.names.fullname" . }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ include "postgresql.port" . | quote }} + {{- if and (not (eq .Values.postgresqlUsername "postgres")) (or .Values.postgresqlPostgresPassword (include "postgresql.useExistingSecret" .)) }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{ end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.readReplicas.extraVolumeMounts }} + {{- toYaml .Values.readReplicas.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.readReplicas.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.sidecars "context" $ ) | nindent 8 }} +{{- end }} + volumes: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} + {{- if or (not .Values.persistence.enabled) (not .Values.readReplicas.persistence.enabled) }} + - name: data + emptyDir: {} + {{- end }} + {{- if .Values.readReplicas.extraVolumes }} + {{- toYaml .Values.readReplicas.extraVolumes | nindent 8 }} + {{- end }} + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} +{{- if and .Values.persistence.enabled .Values.readReplicas.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset.yaml new file mode 100644 index 000000000..1c1d2dbac --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/statefulset.yaml @@ -0,0 +1,589 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "postgresql.primary.fullname" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- with .Values.primary.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.primary.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: 1 + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: primary + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + role: primary + app.kubernetes.io/component: primary + {{- with .Values.primary.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.primary.podAnnotations }} + annotations: {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.primary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.primary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAffinityPreset "component" "primary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "component" "primary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.primary.nodeAffinityPreset.type "key" .Values.primary.nodeAffinityPreset.key "values" .Values.primary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.primary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.primary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + {{- end }} + {{- if or .Values.primary.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.primary.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.primary.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + {{- if .Values.postgresqlInitdbArgs }} + - name: POSTGRES_INITDB_ARGS + value: {{ .Values.postgresqlInitdbArgs | quote }} + {{- end }} + {{- if .Values.postgresqlInitdbWalDir }} + - name: POSTGRES_INITDB_WALDIR + value: {{ .Values.postgresqlInitdbWalDir | quote }} + {{- end }} + {{- if .Values.initdbUser }} + - name: POSTGRESQL_INITSCRIPTS_USERNAME + value: {{ .Values.initdbUser }} + {{- end }} + {{- if .Values.initdbPassword }} + - name: POSTGRESQL_INITSCRIPTS_PASSWORD + value: {{ .Values.initdbPassword }} + {{- end }} + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + {{- if .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_MASTER_HOST + value: {{ .Values.primaryAsStandBy.primaryHost }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ .Values.primaryAsStandBy.primaryPort | quote }} + {{- end }} + {{- if or .Values.replication.enabled .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_REPLICATION_MODE + {{- if .Values.primaryAsStandBy.enabled }} + value: "slave" + {{- else }} + value: "master" + {{- end }} + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + {{- if not (eq .Values.replication.synchronousCommit "off")}} + - name: POSTGRES_SYNCHRONOUS_COMMIT_MODE + value: {{ .Values.replication.synchronousCommit | quote }} + - name: POSTGRES_NUM_SYNCHRONOUS_REPLICAS + value: {{ .Values.replication.numSynchronousReplicas | quote }} + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + {{- end }} + {{- if not (eq (include "postgresql.username" .) "postgres") }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + - name: POSTGRES_USER + value: {{ include "postgresql.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + {{- if (include "postgresql.database" .) }} + - name: POSTGRES_DB + value: {{ (include "postgresql.database" .) | quote }} + {{- end }} + {{- if .Values.extraEnv }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnv "context" $) | nindent 12 }} + {{- end }} + - name: POSTGRESQL_ENABLE_LDAP + value: {{ ternary "yes" "no" .Values.ldap.enabled | quote }} + {{- if .Values.ldap.enabled }} + - name: POSTGRESQL_LDAP_SERVER + value: {{ .Values.ldap.server }} + - name: POSTGRESQL_LDAP_PORT + value: {{ .Values.ldap.port | quote }} + - name: POSTGRESQL_LDAP_SCHEME + value: {{ .Values.ldap.scheme }} + {{- if .Values.ldap.tls }} + - name: POSTGRESQL_LDAP_TLS + value: "1" + {{- end }} + - name: POSTGRESQL_LDAP_PREFIX + value: {{ .Values.ldap.prefix | quote }} + - name: POSTGRESQL_LDAP_SUFFIX + value: {{ .Values.ldap.suffix | quote }} + - name: POSTGRESQL_LDAP_BASE_DN + value: {{ .Values.ldap.baseDN }} + - name: POSTGRESQL_LDAP_BIND_DN + value: {{ .Values.ldap.bindDN }} + {{- if (not (empty .Values.ldap.bind_password)) }} + - name: POSTGRESQL_LDAP_BIND_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-ldap-password + {{- end}} + - name: POSTGRESQL_LDAP_SEARCH_ATTR + value: {{ .Values.ldap.search_attr }} + - name: POSTGRESQL_LDAP_SEARCH_FILTER + value: {{ .Values.ldap.search_filter }} + - name: POSTGRESQL_LDAP_URL + value: {{ .Values.ldap.url }} + {{- end}} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + {{- if .Values.extraEnvVarsCM }} + envFrom: + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d/ + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + mountPath: /docker-entrypoint-initdb.d/secret + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.primary.extraVolumeMounts }} + {{- toYaml .Values.primary.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.primary.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.primary.sidecars "context" $ ) | nindent 8 }} +{{- end }} +{{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "postgresql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.securityContext.enabled }} + securityContext: {{- omit .Values.metrics.securityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- $database := required "In order to enable metrics you need to specify a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase)" (include "postgresql.database" .) }} + {{- $sslmode := ternary "require" "disable" .Values.tls.enabled }} + {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} + - name: DATA_SOURCE_NAME + value: {{ printf "host=127.0.0.1 port=%d user=%s sslmode=%s sslcert=%s sslkey=%s" (int (include "postgresql.port" .)) (include "postgresql.username" .) $sslmode (include "postgresql.tlsCert" .) (include "postgresql.tlsCertKey" .) }} + {{- else }} + - name: DATA_SOURCE_URI + value: {{ printf "127.0.0.1:%d/%s?sslmode=%s" (int (include "postgresql.port" .)) $database $sslmode }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: DATA_SOURCE_PASS_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: DATA_SOURCE_PASS + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: DATA_SOURCE_USER + value: {{ template "postgresql.username" . }} + {{- if .Values.metrics.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.metrics.customMetrics }} + - name: custom-metrics + mountPath: /conf + readOnly: true + args: ["--extend.query-path", "/conf/custom-metrics.yaml"] + {{- end }} + ports: + - name: http-metrics + containerPort: 9187 + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} +{{- end }} + volumes: + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "postgresql.initdbScriptsCM" . }} + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + secret: + secretName: {{ template "postgresql.initdbScriptsSecret" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.primary.extraVolumes }} + {{- toYaml .Values.primary.extraVolumes | nindent 8 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} + - name: custom-metrics + configMap: + name: {{ template "postgresql.metricsCM" . }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} +{{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: +{{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} +{{- end }} +{{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} +{{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/svc-headless.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/svc-headless.yaml new file mode 100644 index 000000000..6ad0dd5f2 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/svc-headless.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-headless + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + # Use this annotation in addition to the actual publishNotReadyAddresses + # field below because the annotation will stop being respected soon but the + # field is broken in some versions of Kubernetes: + # https://github.com/kubernetes/kubernetes/issues/58662 + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +spec: + type: ClusterIP + clusterIP: None + # We want all pods in the StatefulSet to have their addresses published for + # the sake of the other Postgresql pods even before they're ready, since they + # have to be able to talk to each other in order to become ready. + publishNotReadyAddresses: true + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/svc-read.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/svc-read.yaml new file mode 100644 index 000000000..8c9ea54e8 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/svc-read.yaml @@ -0,0 +1,42 @@ +{{- if .Values.replication.enabled }} +{{- $serviceAnnotations := coalesce .Values.readReplicas.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.readReplicas.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.readReplicas.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.readReplicas.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.readReplicas.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.readReplicas.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-read + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: read +{{- end }} diff --git a/sample-cnfs/sample_secret_volume/postgresql/templates/svc.yaml b/sample-cnfs/sample_secret_volume/postgresql/templates/svc.yaml new file mode 100644 index 000000000..5bc2b50ee --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/templates/svc.yaml @@ -0,0 +1,40 @@ +{{- $serviceAnnotations := coalesce .Values.primary.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.primary.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.primary.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.primary.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.primary.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.primary.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary diff --git a/sample-cnfs/sample_secret_volume/postgresql/values-production.yaml b/sample-cnfs/sample_secret_volume/postgresql/values-production.yaml new file mode 100644 index 000000000..4e1ee0416 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/values-production.yaml @@ -0,0 +1,791 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: true + user: repl_user + password: repl_password + readReplicas: 2 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + ## + synchronousCommit: "on" + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + ## + numSynchronousReplicas: 1 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +## existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +# usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: "" + server: "" + port: "" + prefix: "" + suffix: "" + baseDN: "" + bindDN: "" + bind_password: + search_attr: "" + search_filter: "" + scheme: "" + tls: {} + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read replica(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: "" + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Additional PostgreSQL Primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL Read Only Replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + ## Additional PostgreSQL Read Replica Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Read Replica Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Read Replicas + ## + service: {} + # type: + # nodePort: + # clusterIP: + ## Whether to enable PostgreSQL readReplicas replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for readReplicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: "" + # + # Certificate filename + certFilename: "" + # + # Certificate Key filename + certKeyFilename: "" + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: true + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9187" + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 diff --git a/sample-cnfs/sample_secret_volume/postgresql/values.schema.json b/sample-cnfs/sample_secret_volume/postgresql/values.schema.json new file mode 100644 index 000000000..66a2a9dd0 --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/values.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "postgresqlUsername": { + "type": "string", + "title": "Admin user", + "form": true + }, + "postgresqlPassword": { + "type": "string", + "title": "Password", + "form": true + }, + "persistence": { + "type": "object", + "properties": { + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi" + } + } + }, + "resources": { + "type": "object", + "title": "Required Resources", + "description": "Configure resource requests", + "form": true, + "properties": { + "requests": { + "type": "object", + "properties": { + "memory": { + "type": "string", + "form": true, + "render": "slider", + "title": "Memory Request", + "sliderMin": 10, + "sliderMax": 2048, + "sliderUnit": "Mi" + }, + "cpu": { + "type": "string", + "form": true, + "render": "slider", + "title": "CPU Request", + "sliderMin": 10, + "sliderMax": 2000, + "sliderUnit": "m" + } + } + } + } + }, + "replication": { + "type": "object", + "form": true, + "title": "Replication Details", + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable Replication", + "form": true + }, + "readReplicas": { + "type": "integer", + "title": "read Replicas", + "form": true, + "hidden": { + "value": false, + "path": "replication/enabled" + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable Init Containers", + "description": "Change the owner of the persist volume mountpoint to RunAsUser:fsGroup" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "title": "Configure metrics exporter", + "form": true + } + } + } + } +} diff --git a/sample-cnfs/sample_secret_volume/postgresql/values.yaml b/sample-cnfs/sample_secret_volume/postgresql/values.yaml new file mode 100644 index 000000000..e2884371c --- /dev/null +++ b/sample-cnfs/sample_secret_volume/postgresql/values.yaml @@ -0,0 +1,813 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: false + user: repl_user + password: repl_password + readReplicas: 1 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + synchronousCommit: 'off' + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + numSynchronousReplicas: 0 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +# existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +usePasswordFile: true + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: '' + server: '' + port: '' + prefix: '' + suffix: '' + baseDN: '' + bindDN: '' + bind_password: + search_attr: '' + search_filter: '' + scheme: '' + tls: {} + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: '' + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL read only replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL read replicas Volume mounts + ## + extraVolumeMounts: [] + + ## Additional PostgreSQL read replicas Volumes + ## + extraVolumes: [] + + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for read + ## + service: {} + # type: + # nodePort: + # clusterIP: + + ## Whether to enable PostgreSQL read replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for read replicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: '' + # + # Certificate filename + certFilename: '' + # + # Certificate Key filename + certKeyFilename: '' + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: false + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '9187' + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: '' + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size_bytes FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + # + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Array with extra yaml to deploy with the chart. Evaluated as a template +## +extraDeploy: [] diff --git a/sample-cnfs/sample_unmounted_secret_volume/README.md b/sample-cnfs/sample_unmounted_secret_volume/README.md new file mode 100644 index 000000000..12981cc93 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/README.md @@ -0,0 +1,39 @@ +# Set up Sample CoreDNS CNF +./sample-cnfs/sample-coredns-cnf/readme.md +# Prerequistes +### Install helm +``` +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +### Optional: Use a helm version manager +https://github.com/yuya-takeyama/helmenv +Check out helmenv into any path (here is ${HOME}/.helmenv) +``` +${HOME}/.helmenv) +$ git clone https://github.com/yuya-takeyama/helmenv.git ~/.helmenv +``` +Add ~/.helmenv/bin to your $PATH any way you like +``` +$ echo 'export PATH="$HOME/.helmenv/bin:$PATH"' >> ~/.bash_profile +``` +``` +helmenv versions +helmenv install +``` + +### core-dns installation +``` +helm install coredns stable/coredns +``` +### Pull down the helm chart code, untar it, and put it in the cnfs/coredns directory +``` +helm pull stable/coredns +``` +### Example cnf-conformance config file for sample-core-dns-cnf +In ./cnfs/sample-core-dns-cnf/cnf-conformance.yml +``` +--- +container_names: [coredns-coredns] +``` diff --git a/sample-cnfs/sample_unmounted_secret_volume/cnf-conformance.yml b/sample-cnfs/sample_unmounted_secret_volume/cnf-conformance.yml new file mode 100644 index 000000000..acc776928 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/cnf-conformance.yml @@ -0,0 +1,10 @@ +--- +helm_directory: postgresql +git_clone_url: +install_script: chart +release_name: postgresql +service_name: postgresql +container_names: + - name: postgresql + rolling_update_test_tag: "1.8.0" +allowlist_helm_chart_container_names: [] diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/.helmignore b/sample-cnfs/sample_unmounted_secret_volume/postgresql/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.lock b/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.lock new file mode 100644 index 000000000..00ef82278 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.1.2 +digest: sha256:5a5d1b6e8a55efef1c07768b6bb264c60c98e230792b9a63f85468b95cf58c45 +generated: "2020-12-11T12:22:28.510708+01:00" diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.yaml new file mode 100644 index 000000000..332cb9650 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/Chart.yaml @@ -0,0 +1,29 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 11.10.0 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 1.x.x +description: Chart for PostgreSQL, an object-relational database management system + (ORDBMS) with an emphasis on extensibility and on standards-compliance. +home: https://github.com/bitnami/charts/tree/master/bitnami/postgresql +icon: https://bitnami.com/assets/stacks/postgresql/img/postgresql-stack-110x117.png +keywords: +- postgresql +- postgres +- database +- sql +- replication +- cluster +maintainers: +- email: containers@bitnami.com + name: Bitnami +- email: cedric@desaintmartin.fr + name: desaintmartin +name: postgresql +sources: +- https://github.com/bitnami/bitnami-docker-postgresql +- https://www.postgresql.org/ +version: 10.2.0 diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/README.md b/sample-cnfs/sample_unmounted_secret_volume/postgresql/README.md new file mode 100644 index 000000000..9cf7c4128 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/README.md @@ -0,0 +1,798 @@ +# PostgreSQL + +[PostgreSQL](https://www.postgresql.org/) is an object-relational database management system (ORDBMS) with an emphasis on extensibility and on standards-compliance. + +For HA, please see [this repo](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) + +## TL;DR + +```console +$ helm repo add bitnami https://charts.bitnami.com/bitnami +$ helm install my-release bitnami/postgresql +``` + +## Introduction + +This chart bootstraps a [PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart +To install the chart with the release name `my-release`: + +```console +$ helm install my-release bitnami/postgresql +``` + +The command deploys PostgreSQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components but PVC's associated with the chart and deletes the release. + +To delete the PVC's associated with `my-release`: + +```console +$ kubectl delete pvc -l release=my-release +``` + +> **Note**: Deleting the PVC's will delete postgresql data as well. Please be cautious before doing it. + +## Parameters + +The following tables lists the configurable parameters of the PostgreSQL chart and their default values. + +| Parameter | Description | Default | +|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| +| `global.imageRegistry` | Global Docker Image registry | `nil` | +| `global.postgresql.postgresqlDatabase` | PostgreSQL database (overrides `postgresqlDatabase`) | `nil` | +| `global.postgresql.postgresqlUsername` | PostgreSQL username (overrides `postgresqlUsername`) | `nil` | +| `global.postgresql.existingSecret` | Name of existing secret to use for PostgreSQL passwords (overrides `existingSecret`) | `nil` | +| `global.postgresql.postgresqlPassword` | PostgreSQL admin password (overrides `postgresqlPassword`) | `nil` | +| `global.postgresql.servicePort` | PostgreSQL port (overrides `service.port`) | `nil` | +| `global.postgresql.replicationPassword` | Replication user password (overrides `replication.password`) | `nil` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | +| `global.storageClass` | Global storage class for dynamic provisioning | `nil` | +| `image.registry` | PostgreSQL Image registry | `docker.io` | +| `image.repository` | PostgreSQL Image name | `bitnami/postgresql` | +| `image.tag` | PostgreSQL Image tag | `{TAG_NAME}` | +| `image.pullPolicy` | PostgreSQL Image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `image.debug` | Specify if debug values should be set | `false` | +| `nameOverride` | String to partially override common.names.fullname template with a string (will prepend the release name) | `nil` | +| `fullnameOverride` | String to fully override common.names.fullname template with a string | `nil` | +| `volumePermissions.enabled` | Enable init container that changes volume permissions in the data directory (for cases where the default k8s `runAsUser` and `fsUser` values do not work) | `false` | +| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | +| `volumePermissions.image.repository` | Init container volume-permissions image name | `bitnami/minideb` | +| `volumePermissions.image.tag` | Init container volume-permissions image tag | `buster` | +| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `Always` | +| `volumePermissions.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container (when facing issues in OpenShift or uid unknown, try value "auto") | `0` | +| `usePasswordFile` | Have the secrets mounted as a file instead of env vars | `false` | +| `ldap.enabled` | Enable LDAP support | `false` | +| `ldap.existingSecret` | Name of existing secret to use for LDAP passwords | `nil` | +| `ldap.url` | LDAP URL beginning in the form `ldap[s]://host[:port]/basedn[?[attribute][?[scope][?[filter]]]]` | `nil` | +| `ldap.server` | IP address or name of the LDAP server. | `nil` | +| `ldap.port` | Port number on the LDAP server to connect to | `nil` | +| `ldap.scheme` | Set to `ldaps` to use LDAPS. | `nil` | +| `ldap.tls` | Set to `1` to use TLS encryption | `nil` | +| `ldap.prefix` | String to prepend to the user name when forming the DN to bind | `nil` | +| `ldap.suffix` | String to append to the user name when forming the DN to bind | `nil` | +| `ldap.search_attr` | Attribute to match against the user name in the search | `nil` | +| `ldap.search_filter` | The search filter to use when doing search+bind authentication | `nil` | +| `ldap.baseDN` | Root DN to begin the search for the user in | `nil` | +| `ldap.bindDN` | DN of user to bind to LDAP | `nil` | +| `ldap.bind_password` | Password for the user to bind to LDAP | `nil` | +| `replication.enabled` | Enable replication | `false` | +| `replication.user` | Replication user | `repl_user` | +| `replication.password` | Replication user password | `repl_password` | +| `replication.readReplicas` | Number of read replicas replicas | `1` | +| `replication.synchronousCommit` | Set synchronous commit mode. Allowed values: `on`, `remote_apply`, `remote_write`, `local` and `off` | `off` | +| `replication.numSynchronousReplicas` | Number of replicas that will have synchronous replication. Note: Cannot be greater than `replication.readReplicas`. | `0` | +| `replication.applicationName` | Cluster application name. Useful for advanced replication settings | `my_application` | +| `existingSecret` | Name of existing secret to use for PostgreSQL passwords. The secret has to contain the keys `postgresql-password` which is the password for `postgresqlUsername` when it is different of `postgres`, `postgresql-postgres-password` which will override `postgresqlPassword`, `postgresql-replication-password` which will override `replication.password` and `postgresql-ldap-password` which will be sed to authenticate on LDAP. The value is evaluated as a template. | `nil` | +| `postgresqlPostgresPassword` | PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`, in which case`postgres` is the admin username). | _random 10 character alphanumeric string_ | +| `postgresqlUsername` | PostgreSQL user (creates a non-admin user when `postgresqlUsername` is not `postgres`) | `postgres` | +| `postgresqlPassword` | PostgreSQL user password | _random 10 character alphanumeric string_ | +| `postgresqlDatabase` | PostgreSQL database | `nil` | +| `postgresqlDataDir` | PostgreSQL data dir folder | `/bitnami/postgresql` (same value as persistence.mountPath) | +| `extraEnv` | Any extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `[]` | +| `extraEnvVarsCM` | Name of a Config Map containing extra environment variables you would like to pass on to the pod. The value is evaluated as a template. | `nil` | +| `postgresqlInitdbArgs` | PostgreSQL initdb extra arguments | `nil` | +| `postgresqlInitdbWalDir` | PostgreSQL location for transaction log | `nil` | +| `postgresqlConfiguration` | Runtime Config Parameters | `nil` | +| `postgresqlExtendedConf` | Extended Runtime Config Parameters (appended to main or default configuration) | `nil` | +| `pgHbaConfiguration` | Content of pg_hba.conf | `nil (do not create pg_hba.conf)` | +| `postgresqlSharedPreloadLibraries` | Shared preload libraries (comma-separated list) | `pgaudit` | +| `postgresqlMaxConnections` | Maximum total connections | `nil` | +| `postgresqlPostgresConnectionLimit` | Maximum total connections for the postgres user | `nil` | +| `postgresqlDbUserConnectionLimit` | Maximum total connections for the non-admin user | `nil` | +| `postgresqlTcpKeepalivesInterval` | TCP keepalives interval | `nil` | +| `postgresqlTcpKeepalivesIdle` | TCP keepalives idle | `nil` | +| `postgresqlTcpKeepalivesCount` | TCP keepalives count | `nil` | +| `postgresqlStatementTimeout` | Statement timeout | `nil` | +| `postgresqlPghbaRemoveFilters` | Comma-separated list of patterns to remove from the pg_hba.conf file | `nil` | +| `customLivenessProbe` | Override default liveness probe | `nil` | +| `customReadinessProbe` | Override default readiness probe | `nil` | +| `audit.logHostname` | Add client hostnames to the log file | `false` | +| `audit.logConnections` | Add client log-in operations to the log file | `false` | +| `audit.logDisconnections` | Add client log-outs operations to the log file | `false` | +| `audit.pgAuditLog` | Add operations to log using the pgAudit extension | `nil` | +| `audit.clientMinMessages` | Message log level to share with the user | `nil` | +| `audit.logLinePrefix` | Template string for the log line prefix | `nil` | +| `audit.logTimezone` | Timezone for the log timestamps | `nil` | +| `configurationConfigMap` | ConfigMap with the PostgreSQL configuration files (Note: Overrides `postgresqlConfiguration` and `pgHbaConfiguration`). The value is evaluated as a template. | `nil` | +| `extendedConfConfigMap` | ConfigMap with the extended PostgreSQL configuration files. The value is evaluated as a template. | `nil` | +| `initdbScripts` | Dictionary of initdb scripts | `nil` | +| `initdbUser` | PostgreSQL user to execute the .sql and sql.gz scripts | `nil` | +| `initdbPassword` | Password for the user specified in `initdbUser` | `nil` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`). The value is evaluated as a template. | `nil` | +| `initdbScriptsSecret` | Secret with initdb scripts that contain sensitive information (Note: can be used with `initdbScriptsConfigMap` or `initdbScripts`). The value is evaluated as a template. | `nil` | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.port` | PostgreSQL port | `5432` | +| `service.nodePort` | Kubernetes Service nodePort | `nil` | +| `service.annotations` | Annotations for PostgreSQL service | `{}` (evaluated as a template) | +| `service.loadBalancerIP` | loadBalancerIP if service type is `LoadBalancer` | `nil` | +| `service.loadBalancerSourceRanges` | Address that are allowed when svc is LoadBalancer | `[]` (evaluated as a template) | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `shmVolume.enabled` | Enable emptyDir volume for /dev/shm for primary and read replica(s) Pod(s) | `true` | +| `shmVolume.chmod.enabled` | Run at init chmod 777 of the /dev/shm (ignored if `volumePermissions.enabled` is `false`) | `true` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim`, the value is evaluated as a template. | `nil` | +| `persistence.mountPath` | Path to mount the volume at | `/bitnami/postgresql` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `persistence.storageClass` | PVC Storage Class for PostgreSQL volume | `nil` | +| `persistence.accessModes` | PVC Access Mode for PostgreSQL volume | `[ReadWriteOnce]` | +| `persistence.size` | PVC Storage Request for PostgreSQL volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume (this value is evaluated as a template) | `{}` | +| `commonAnnotations` | Annotations to be added to all deployed resources (rendered as a template) | `{}` | +| `primary.podAffinityPreset` | PostgreSQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | PostgreSQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | PostgreSQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | PostgreSQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | PostgreSQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.nodeSelector` | Node labels for PostgreSQL primary pods assignment | `{}` (evaluated as a template) | +| `primary.tolerations` | Tolerations for PostgreSQL primary pods assignment | `[]` (evaluated as a template) | + +| `primary.anotations` | Map of annotations to add to the statefulset (postgresql primary) | `{}` | +| `primary.labels` | Map of labels to add to the statefulset (postgresql primary) | `{}` | +| `primary.podAnnotations` | Map of annotations to add to the pods (postgresql primary) | `{}` | +| `primary.podLabels` | Map of labels to add to the pods (postgresql primary) | `{}` | +| `primary.priorityClassName` | Priority Class to use for each pod (postgresql primary) | `nil` | +| `primary.extraInitContainers` | Additional init containers to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql primary) | `[]` | +| `primary.extraVolumes` | Additional volumes to add to the pods (postgresql primary) | `[]` | +| `primary.sidecars` | Add additional containers to the pod | `[]` | +| `primary.service.type` | Allows using a different service type for primary | `nil` | +| `primary.service.nodePort` | Allows using a different nodePort for primary | `nil` | +| `primary.service.clusterIP` | Allows using a different clusterIP for primary | `nil` | +| `primaryAsStandBy.enabled` | Whether to enable current cluster's primary as standby server of another cluster or not. | `false` | +| `primaryAsStandBy.primaryHost` | The Host of replication primary in the other cluster. | `nil` | +| `primaryAsStandBy.primaryPort ` | The Port of replication primary in the other cluster. | `nil` | +| `readReplicas.podAffinityPreset` | PostgreSQL read only pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.podAntiAffinityPreset` | PostgreSQL read only pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `readReplicas.nodeAffinityPreset.type` | PostgreSQL read only node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `readReplicas.nodeAffinityPreset.key` | PostgreSQL read only node label key to match Ignored if `primary.affinity` is set. | `""` | +| `readReplicas.nodeAffinityPreset.values` | PostgreSQL read only node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `readReplicas.affinity` | Affinity for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.nodeSelector` | Node labels for PostgreSQL read only pods assignment | `{}` (evaluated as a template) | +| `readReplicas.anotations` | Map of annotations to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.resources` | CPU/Memory resource requests/limits override for readReplicass. Will fallback to `values.resources` if not defined. | `{}` | +| `readReplicas.labels` | Map of labels to add to the statefulsets (postgresql readReplicas) | `{}` | +| `readReplicas.podAnnotations` | Map of annotations to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.podLabels` | Map of labels to add to the pods (postgresql readReplicas) | `{}` | +| `readReplicas.priorityClassName` | Priority Class to use for each pod (postgresql readReplicas) | `nil` | +| `readReplicas.extraInitContainers` | Additional init containers to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumeMounts` | Additional volume mounts to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.extraVolumes` | Additional volumes to add to the pods (postgresql readReplicas) | `[]` | +| `readReplicas.sidecars` | Add additional containers to the pod | `[]` | +| `readReplicas.service.type` | Allows using a different service type for readReplicas | `nil` | +| `readReplicas.service.nodePort` | Allows using a different nodePort for readReplicas | `nil` | +| `readReplicas.service.clusterIP` | Allows using a different clusterIP for readReplicas | `nil` | +| `readReplicas.persistence.enabled` | Whether to enable readReplicas replicas persistence | `true` | +| `terminationGracePeriodSeconds` | Seconds the pod needs to terminate gracefully | `nil` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | +| `securityContext.*` | Other pod security context to be included as-is in the pod spec | `{}` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the pod | `1001` | +| `containerSecurityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `containerSecurityContext.enabled` | Enable container security context | `true` | +| `containerSecurityContext.runAsUser` | User ID for the container | `1001` | +| `serviceAccount.enabled` | Enable service account (Note: Service Account will only be automatically created if `serviceAccount.name` is not set) | `false` | +| `serviceAccount.name` | Name of existing service account | `nil` | +| `livenessProbe.enabled` | Would you like a livenessProbe to be enabled | `true` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed | `{}` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `tls.enabled` | Enable TLS traffic support | `false` | +| `tls.preferServerCiphers` | Whether to use the server's TLS cipher preferences rather than the client's | `true` | +| `tls.certificatesSecret` | Name of an existing secret that contains the certificates | `nil` | +| `tls.certFilename` | Certificate filename | `""` | +| `tls.certKeyFilename` | Certificate key filename | `""` | +| `tls.certCAFilename` | CA Certificate filename. If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate. | `nil` | +| `tls.crlFilename` | File containing a Certificate Revocation List | `nil` | +| `metrics.enabled` | Start a prometheus exporter | `false` | +| `metrics.service.type` | Kubernetes Service type | `ClusterIP` | +| `service.clusterIP` | Static clusterIP or None for headless services | `nil` | +| `metrics.service.annotations` | Additional annotations for metrics exporter pod | `{ prometheus.io/scrape: "true", prometheus.io/port: "9187"}` | +| `metrics.service.loadBalancerIP` | loadBalancerIP if redis metrics service type is `LoadBalancer` | `nil` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.namespace` | Optional namespace in which to create ServiceMonitor | `nil` | +| `metrics.serviceMonitor.interval` | Scrape interval. If not set, the Prometheus default scrape interval is used | `nil` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout. If not set, the Prometheus default scrape timeout is used | `nil` | +| `metrics.prometheusRule.enabled` | Set this to true to create prometheusRules for Prometheus operator | `false` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so prometheusRules will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.namespace` | namespace where prometheusRules resource should be created | the same namespace as postgresql | +| `metrics.prometheusRule.rules` | [rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) to be created, check values for an example. | `[]` | +| `metrics.image.registry` | PostgreSQL Exporter Image registry | `docker.io` | +| `metrics.image.repository` | PostgreSQL Exporter Image name | `bitnami/postgres-exporter` | +| `metrics.image.tag` | PostgreSQL Exporter Image tag | `{TAG_NAME}` | +| `metrics.image.pullPolicy` | PostgreSQL Exporter Image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify Image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `metrics.customMetrics` | Additional custom metrics | `nil` | +| `metrics.extraEnvVars` | Extra environment variables to add to exporter | `{}` (evaluated as a template) | +| `metrics.securityContext.*` | Other container security context to be included as-is in the container spec | `{}` | +| `metrics.securityContext.enabled` | Enable security context for metrics | `false` | +| `metrics.securityContext.runAsUser` | User ID for the container for metrics | `1001` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `metrics.livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `metrics.readinessProbe.enabled` | would you like a readinessProbe to be enabled | `true` | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 5 | +| `metrics.readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | +| `metrics.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | +| `updateStrategy` | Update strategy policy | `{type: "RollingUpdate"}` | +| `psp.create` | Create Pod Security Policy | `false` | +| `rbac.create` | Create Role and RoleBinding (required for PSP to work) | `false` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template). | `nil` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install my-release \ + --set postgresqlPassword=secretpassword,postgresqlDatabase=my-database \ + bitnami/postgresql +``` + +The above command sets the PostgreSQL `postgres` account password to `secretpassword`. Additionally it creates a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +$ helm install my-release -f values.yaml bitnami/postgresql +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) + +It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. + +Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. + +### Production configuration and horizontal scaling + +This chart includes a `values-production.yaml` file where you can find some parameters oriented to production configuration in comparison to the regular `values.yaml`. You can use this file instead of the default one. + +- Enable replication: +```diff +- replication.enabled: false ++ replication.enabled: true +``` + +- Number of read replicas: +```diff +- replication.readReplicas: 1 ++ replication.readReplicas: 2 +``` + +- Set synchronous commit mode: +```diff +- replication.synchronousCommit: "off" ++ replication.synchronousCommit: "on" +``` + +- Number of replicas that will have synchronous replication: +```diff +- replication.numSynchronousReplicas: 0 ++ replication.numSynchronousReplicas: 1 +``` + +- Start a prometheus exporter: +```diff +- metrics.enabled: false ++ metrics.enabled: true +``` + +To horizontally scale this chart, you can use the `--replicas` flag to modify the number of nodes in your PostgreSQL deployment. Also you can use the `values-production.yaml` file or modify the parameters shown above. + +### Customizing primary and read replica services in a replicated configuration + +At the top level, there is a service object which defines the services for both primary and readReplicas. For deeper customization, there are service objects for both the primary and read types individually. This allows you to override the values in the top level service object so that the primary and read can be of different service types and with different clusterIPs / nodePorts. Also in the case you want the primary and read to be of type nodePort, you will need to set the nodePorts to different values to prevent a collision. The values that are deeper in the primary.service or readReplicas.service objects will take precedence over the top level service object. + +### Change PostgreSQL version + +To modify the PostgreSQL version used in this chart you can specify a [valid image tag](https://hub.docker.com/r/bitnami/postgresql/tags/) using the `image.tag` parameter. For example, `image.tag=X.Y.Z`. This approach is also applicable to other images like exporters. + +### postgresql.conf / pg_hba.conf files as configMap + +This helm chart also supports to customize the whole configuration file. + +Add your custom file to "files/postgresql.conf" in your working directory. This file will be mounted as configMap to the containers and it will be used for configuring the PostgreSQL server. + +Alternatively, you can specify PostgreSQL configuration parameters using the `postgresqlConfiguration` parameter as a dict, using camelCase, e.g. {"sharedBuffers": "500MB"}. + +In addition to these options, you can also set an external ConfigMap with all the configuration files. This is done by setting the `configurationConfigMap` parameter. Note that this will override the two previous options. + +### Allow settings to be loaded from files other than the default `postgresql.conf` + +If you don't want to provide the whole PostgreSQL configuration file and only specify certain parameters, you can add your extended `.conf` files to "files/conf.d/" in your working directory. +Those files will be mounted as configMap to the containers adding/overwriting the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +Alternatively, you can also set an external ConfigMap with all the extra configuration files. This is done by setting the `extendedConfConfigMap` parameter. Note that this will override the previous option. + +### Initialize a fresh instance + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image allows you to use your custom scripts to initialize a fresh instance. In order to execute the scripts, they must be located inside the chart folder `files/docker-entrypoint-initdb.d` so they can be consumed as a ConfigMap. + +Alternatively, you can specify custom scripts using the `initdbScripts` parameter as dict. + +In addition to these options, you can also set an external ConfigMap with all the initialization scripts. This is done by setting the `initdbScriptsConfigMap` parameter. Note that this will override the two previous options. If your initialization scripts contain sensitive information such as credentials or passwords, you can use the `initdbScriptsSecret` parameter. + +The allowed extensions are `.sh`, `.sql` and `.sql.gz`. + +### Securing traffic using TLS + +TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the chart: + +- `tls.enabled`: Enable TLS support. Defaults to `false` +- `tls.certificatesSecret`: Name of an existing secret that contains the certificates. No defaults. +- `tls.certFilename`: Certificate filename. No defaults. +- `tls.certKeyFilename`: Certificate key filename. No defaults. + +For example: + +* First, create the secret with the cetificates files: + + ```console + kubectl create secret generic certificates-tls-secret --from-file=./cert.crt --from-file=./cert.key --from-file=./ca.crt + ``` + +* Then, use the following parameters: + + ```console + volumePermissions.enabled=true + tls.enabled=true + tls.certificatesSecret="certificates-tls-secret" + tls.certFilename="cert.crt" + tls.certKeyFilename="cert.key" + ``` + + > Note TLS and VolumePermissions: PostgreSQL requires certain permissions on sensitive files (such as certificate keys) to start up. Due to an on-going [issue](https://github.com/kubernetes/kubernetes/issues/57923) regarding kubernetes permissions and the use of `containerSecurityContext.runAsUser`, you must enable `volumePermissions` to ensure everything works as expected. + +### Sidecars + +If you need additional containers to run within the same pod as PostgreSQL (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +# For the PostgreSQL primary +primary: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +# For the PostgreSQL replicas +readReplicas: + sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +### Metrics + +The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9187) is not exposed and it is expected that the metrics are collected from inside the k8s cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). + +The exporter allows to create custom metrics from additional SQL queries. See the Chart's `values.yaml` for an example and consult the [exporters documentation](https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file) for more details. + +### Use of global variables + +In more complex scenarios, we may have the following tree of dependencies + +``` + +--------------+ + | | + +------------+ Chart 1 +-----------+ + | | | | + | --------+------+ | + | | | + | | | + | | | + | | | + v v v ++-------+------+ +--------+------+ +--------+------+ +| | | | | | +| PostgreSQL | | Sub-chart 1 | | Sub-chart 2 | +| | | | | | ++--------------+ +---------------+ +---------------+ +``` + +The three charts below depend on the parent chart Chart 1. However, subcharts 1 and 2 may need to connect to PostgreSQL as well. In order to do so, subcharts 1 and 2 need to know the PostgreSQL credentials, so one option for deploying could be deploy Chart 1 with the following parameters: + +``` +postgresql.postgresqlPassword=testtest +subchart1.postgresql.postgresqlPassword=testtest +subchart2.postgresql.postgresqlPassword=testtest +postgresql.postgresqlDatabase=db1 +subchart1.postgresql.postgresqlDatabase=db1 +subchart2.postgresql.postgresqlDatabase=db1 +``` + +If the number of dependent sub-charts increases, installing the chart with parameters can become increasingly difficult. An alternative would be to set the credentials using global variables as follows: + +``` +global.postgresql.postgresqlPassword=testtest +global.postgresql.postgresqlDatabase=db1 +``` + +This way, the credentials will be available in all of the subcharts. + +## Persistence + +The [Bitnami PostgreSQL](https://github.com/bitnami/bitnami-docker-postgresql) image stores the PostgreSQL data and configurations at the `/bitnami/postgresql` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. +See the [Parameters](#parameters) section to configure the PVC or to disable persistence. + +If you already have data in it, you will fail to sync to standby nodes for all commits, details can refer to [code](https://github.com/bitnami/bitnami-docker-postgresql/blob/8725fe1d7d30ebe8d9a16e9175d05f7ad9260c93/9.6/debian-9/rootfs/libpostgresql.sh#L518-L556). If you need to use those data, please covert them to sql and import after `helm install` finished. + +## NetworkPolicy + +To enable network policy for PostgreSQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: + +```console +$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 5432. + +For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to PostgreSQL. +This label will be displayed in the output of a successful install. + +## Differences between Bitnami PostgreSQL image and [Docker Official](https://hub.docker.com/_/postgres) image + +- The Docker Official PostgreSQL image does not support replication. If you pass any replication environment variable, this would be ignored. The only environment variables supported by the Docker Official image are POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORD, POSTGRES_INITDB_ARGS, POSTGRES_INITDB_WALDIR and PGDATA. All the remaining environment variables are specific to the Bitnami PostgreSQL image. +- The Bitnami PostgreSQL image is non-root by default. This requires that you run the pod with `securityContext` and updates the permissions of the volume with an `initContainer`. A key benefit of this configuration is that the pod follows security best practices and is prepared to run on Kubernetes distributions with hard security constraints like OpenShift. +- For OpenShift, one may either define the runAsUser and fsGroup accordingly, or try this more dynamic option: volumePermissions.securityContext.runAsUser="auto",securityContext.enabled=false,containerSecurityContext.enabled=false,shmVolume.chmod.enabled=false + +### Deploy chart using Docker Official PostgreSQL Image + +From chart version 4.0.0, it is possible to use this chart with the Docker Official PostgreSQL image. +Besides specifying the new Docker repository and tag, it is important to modify the PostgreSQL data directory and volume mount point. Basically, the PostgreSQL data dir cannot be the mount point directly, it has to be a subdirectory. + +``` +image.repository=postgres +image.tag=10.6 +postgresqlDataDir=/data/pgdata +persistence.mountPath=/data/ +``` + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` paremeter(s). Find more infomation about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/master/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## Troubleshooting + +Find more information about how to deal with common errors related to Bitnami’s Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). + +## Upgrading + +It's necessary to specify the existing passwords while performing an upgrade to ensure the secrets are not updated with invalid randomly generated passwords. Remember to specify the existing values of the `postgresqlPassword` and `replication.password` parameters when upgrading the chart: + +```bash +$ helm upgrade my-release bitnami/postgresql \ + --set postgresqlPassword=[POSTGRESQL_PASSWORD] \ + --set replication.password=[REPLICATION_PASSWORD] +``` + +> Note: you need to substitute the placeholders _[POSTGRESQL_PASSWORD]_, and _[REPLICATION_PASSWORD]_ with the values obtained from instructions in the installation notes. + +### To 10.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Move dependency information from the *requirements.yaml* to the *Chart.yaml* +- After running `helm dependency update`, a *Chart.lock* file is generated containing the same structure used in the previous *requirements.lock* +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Chart. + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ + +#### Breaking changes + +- The term `master` has been replaced with `primary` and `slave` with `readReplicas` throughout the chart. Role names have changed from `master` and `slave` to `primary` and `read`. + +To upgrade to `10.0.0`, it should be done reusing the PVCs used to hold the PostgreSQL data on your previous release. To do so, follow the instructions below (the following example assumes that the release name is `postgresql`): + +> NOTE: Please, create a backup of your database before running any of those actions. + +Obtain the credentials and the names of the PVCs used to hold the PostgreSQL data on your current release: + +```console +$ export POSTGRESQL_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode) +$ export POSTGRESQL_PVC=$(kubectl get pvc -l app.kubernetes.io/instance=postgresql,role=master -o jsonpath="{.items[0].metadata.name}") +``` + +Delete the PostgreSQL statefulset. Notice the option `--cascade=false`: + +```console +$ kubectl delete statefulsets.apps postgresql-postgresql --cascade=false +``` + +Now the upgrade works: + +```console +$ helm upgrade postgresql bitnami/postgresql --set postgresqlPassword=$POSTGRESQL_PASSWORD --set persistence.existingClaim=$POSTGRESQL_PVC +``` + +You will have to delete the existing MariaDB pod and the new statefulset is going to create a new one + +```console +$ kubectl delete pod postgresql-postgresql-0 +``` + +Finally, you should see the lines below in MariaDB container logs: + +```console +$ kubectl logs $(kubectl get pods -l app.kubernetes.io/instance=postgresql,app.kubernetes.io/name=postgresql,role=primary -o jsonpath="{.items[0].metadata.name}") +... +postgresql 08:05:12.59 INFO ==> Deploying PostgreSQL with persisted data... +... +``` + +### To 9.0.0 + +In this version the chart was adapted to follow the Helm label best practices, see [PR 3021](https://github.com/bitnami/charts/pull/3021). That means the backward compatibility is not guarantee when upgrading the chart to this major version. + +As a workaround, you can delete the existing statefulset (using the `--cascade=false` flag pods are not deleted) before upgrade the chart. For example, this can be a valid workflow: + +- Deploy an old version (8.X.X) + +```console +$ helm install postgresql bitnami/postgresql --version 8.10.14 +``` + +- Old version is up and running + +```console +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 1 2020-08-04 13:39:54.783480286 +0000 UTC deployed postgresql-8.10.14 11.8.0 + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 76s +``` + +- The upgrade to the latest one (9.X.X) is going to fail + +```console +$ helm upgrade postgresql bitnami/postgresql +Error: UPGRADE FAILED: cannot patch "postgresql-postgresql" with kind StatefulSet: StatefulSet.apps "postgresql-postgresql" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden +``` + +- Delete the statefulset + +```console +$ kubectl delete statefulsets.apps --cascade=false postgresql-postgresql +statefulset.apps "postgresql-postgresql" deleted +``` + +- Now the upgrade works + +```console +$ helm upgrade postgresql bitnami/postgresql +$ helm ls +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +postgresql default 3 2020-08-04 13:42:08.020385884 +0000 UTC deployed postgresql-9.1.2 11.8.0 +``` + +- We can kill the existing pod and the new statefulset is going to create a new one: + +```console +$ kubectl delete pod postgresql-postgresql-0 +pod "postgresql-postgresql-0" deleted + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +postgresql-postgresql-0 1/1 Running 0 19s +``` + +Please, note that without the `--cascade=false` both objects (statefulset and pod) are going to be removed and both objects will be deployed again with the `helm upgrade` command + +### To 8.0.0 + +Prefixes the port names with their protocols to comply with Istio conventions. + +If you depend on the port names in your setup, make sure to update them to reflect this change. + +### To 7.1.0 + +Adds support for LDAP configuration. + +### To 7.0.0 + +Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. + +In https://github.com/helm/charts/pull/17281 the `apiVersion` of the statefulset resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. + +This major version bump signifies this change. + +### To 6.5.7 + +In this version, the chart will use PostgreSQL with the Postgis extension included. The version used with Postgresql version 10, 11 and 12 is Postgis 2.5. It has been compiled with the following dependencies: + +- protobuf +- protobuf-c +- json-c +- geos +- proj + +### To 5.0.0 + +In this version, the **chart is using PostgreSQL 11 instead of PostgreSQL 10**. You can find the main difference and notable changes in the following links: [https://www.postgresql.org/about/news/1894/](https://www.postgresql.org/about/news/1894/) and [https://www.postgresql.org/about/featurematrix/](https://www.postgresql.org/about/featurematrix/). + +For major releases of PostgreSQL, the internal data storage format is subject to change, thus complicating upgrades, you can see some errors like the following one in the logs: + +```console +Welcome to the Bitnami postgresql container +Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-postgresql +Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-postgresql/issues +Send us your feedback at containers@bitnami.com + +INFO ==> ** Starting PostgreSQL setup ** +NFO ==> Validating settings in POSTGRESQL_* env vars.. +INFO ==> Initializing PostgreSQL database... +INFO ==> postgresql.conf file not detected. Generating it... +INFO ==> pg_hba.conf file not detected. Generating it... +INFO ==> Deploying PostgreSQL with persisted data... +INFO ==> Configuring replication parameters +INFO ==> Loading custom scripts... +INFO ==> Enabling remote connections +INFO ==> Stopping PostgreSQL... +INFO ==> ** PostgreSQL setup finished! ** + +INFO ==> ** Starting PostgreSQL ** + [1] FATAL: database files are incompatible with server + [1] DETAIL: The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.3. +``` + +In this case, you should migrate the data from the old chart to the new one following an approach similar to that described in [this section](https://www.postgresql.org/docs/current/upgrading.html#UPGRADING-VIA-PGDUMPALL) from the official documentation. Basically, create a database dump in the old chart, move and restore it in the new one. + +### To 4.0.0 + +This chart will use by default the Bitnami PostgreSQL container starting from version `10.7.0-r68`. This version moves the initialization logic from node.js to bash. This new version of the chart requires setting the `POSTGRES_PASSWORD` in the slaves as well, in order to properly configure the `pg_hba.conf` file. Users from previous versions of the chart are advised to upgrade immediately. + +IMPORTANT: If you do not want to upgrade the chart version then make sure you use the `10.7.0-r68` version of the container. Otherwise, you will get this error + +``` +The POSTGRESQL_PASSWORD environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development +``` + +### To 3.0.0 + +This releases make it possible to specify different nodeSelector, affinity and tolerations for master and slave pods. +It also fixes an issue with `postgresql.master.fullname` helper template not obeying fullnameOverride. + +#### Breaking changes + +- `affinty` has been renamed to `master.affinity` and `slave.affinity`. +- `tolerations` has been renamed to `master.tolerations` and `slave.tolerations`. +- `nodeSelector` has been renamed to `master.nodeSelector` and `slave.nodeSelector`. + +### To 2.0.0 + +In order to upgrade from the `0.X.X` branch to `1.X.X`, you should follow the below steps: + +- Obtain the service name (`SERVICE_NAME`) and password (`OLD_PASSWORD`) of the existing postgresql chart. You can find the instructions to obtain the password in the NOTES.txt, the service name can be obtained by running + +```console +$ kubectl get svc +``` + +- Install (not upgrade) the new version + +```console +$ helm repo update +$ helm install my-release bitnami/postgresql +``` + +- Connect to the new pod (you can obtain the name by running `kubectl get pods`): + +```console +$ kubectl exec -it NAME bash +``` + +- Once logged in, create a dump file from the previous database using `pg_dump`, for that we should connect to the previous postgresql chart: + +```console +$ pg_dump -h SERVICE_NAME -U postgres DATABASE_NAME > /tmp/backup.sql +``` + +After run above command you should be prompted for a password, this password is the previous chart password (`OLD_PASSWORD`). +This operation could take some time depending on the database size. + +- Once you have the backup file, you can restore it with a command like the one below: + +```console +$ psql -U postgres DATABASE_NAME < /tmp/backup.sql +``` + +In this case, you are accessing to the local postgresql, so the password should be the new one (you can find it in NOTES.txt). + +If you want to restore the database and the database schema does not exist, it is necessary to first follow the steps described below. + +```console +$ psql -U postgres +postgres=# drop database DATABASE_NAME; +postgres=# create database DATABASE_NAME; +postgres=# create user USER_NAME; +postgres=# alter role USER_NAME with password 'BITNAMI_USER_PASSWORD'; +postgres=# grant all privileges on database DATABASE_NAME to USER_NAME; +postgres=# alter database DATABASE_NAME owner to USER_NAME; +``` diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/.helmignore b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/Chart.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/Chart.yaml new file mode 100644 index 000000000..1bda8e2df --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 1.1.1 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://github.com/bitnami/charts/tree/master/bitnami/common +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- email: containers@bitnami.com + name: Bitnami +name: common +sources: +- https://github.com/bitnami/charts +- http://www.bitnami.com/ +type: library +version: 1.1.2 diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/README.md b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/README.md new file mode 100644 index 000000000..a68895368 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/README.md @@ -0,0 +1,309 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 0.x.x + repository: https://charts.bitnami.com/bitnami +``` + +```bash +$ helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. + +## Prerequisites + +- Kubernetes 1.12+ +- Helm 3.0-beta3+ + +## Parameters + +The following table lists the helpers available in the library which are scoped in different sections. + +### Affinities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.node.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.pod.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.pod.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | + +### Capabilities + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.capabilities.deployment.apiVersion` | Return the appropriate apiVersion for deployment. | `.` Chart context | +| `common.capabilities.statefulset.apiVersion` | Return the appropriate apiVersion for statefulset. | `.` Chart context | +| `common.capabilities.ingress.apiVersion` | Return the appropriate apiVersion for ingress. | `.` Chart context | + +### Errors + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.errors.upgrade.passwords.empty` | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01) "context" $` | + +### Images + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.images.image` | Return the proper and full image name | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure. | +| `common.images.pullSecrets` | Return the proper Docker Image Registry Secret Names | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global` | + +### Labels + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.labels.standard` | Return Kubernetes standard labels | `.` Chart context | +| `common.labels.matchLabels` | Return the proper Docker Image Registry Secret Names | `.` Chart context | + +### Names + +| Helper identifier | Description | Expected Inpput | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.names.name` | Expand the name of the chart or use `.Values.nameOverride` | `.` Chart context | +| `common.names.fullname` | Create a default fully qualified app name. | `.` Chart context | +| `common.names.chart` | Chart name plus version | `.` Chart context | + +### Secrets + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.secrets.name` | Generate the name of the secret. | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.key` | Generate secret key. | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure. | + +### Storage + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. | + +### TplValues + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.tplvalues.render` | Renders a value that contains template | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frecuently is the chart context `$` or `.` | + +### Utils + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.utils.fieldToEnvVar` | Build environment variable name given a field. | `dict "field" "my-password"` | +| `common.utils.secret.getvalue` | Print instructions to get a secret value. | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` | +| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path | `dict "key" "path.to.key" "context" $` | + +### Validations + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.validations.values.single.empty` | Validate a value must not be empty. | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "context" $` secret and field are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) | +| `common.validations.values.multiple.empty` | Validate a multiple values must not be empty. It returns a shared error for all the values. | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue) | +| `common.validations.values.mariadb.passwords` | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values. | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mariadb chart and the helper. | +| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values. | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper. | +| `common.validations.values.redis.passwords` | This helper will ensure required password for Redis are not empty. It returns a shared error for all the values. | `dict "secret" "redis-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use redis chart and the helper. | +| `common.validations.values.cassandra.passwords` | This helper will ensure required password for Cassandra are not empty. It returns a shared error for all the values. | `dict "secret" "cassandra-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use cassandra chart and the helper. | +| `common.validations.values.mongodb.passwords` | This helper will ensure required password for MongoDB are not empty. It returns a shared error for all the values. | `dict "secret" "mongodb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mongodb chart and the helper. | + +### Warnings + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.warnings.rollingTag` | Warning about using rolling tag. | `ImageRoot` see [ImageRoot](#imageroot) for the structure. | + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets. + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possiblity of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +$ helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 --decode) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 --decode) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_affinities.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_affinities.tpl new file mode 100644 index 000000000..1ff26d585 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_affinities.tpl @@ -0,0 +1,94 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname + weight: 1 +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + namespaces: + - {{ .context.Release.Namespace }} + topologyKey: kubernetes.io/hostname +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_capabilities.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_capabilities.tpl new file mode 100644 index 000000000..143bef2a4 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_capabilities.tpl @@ -0,0 +1,33 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_errors.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_errors.tpl new file mode 100644 index 000000000..d6d3ec65a --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_errors.tpl @@ -0,0 +1,20 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: you must provide your current passwords when upgrade the release%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_images.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_images.tpl new file mode 100644 index 000000000..aafde9f3b --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_images.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $tag := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_labels.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_labels.tpl new file mode 100644 index 000000000..252066c7e --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_labels.tpl @@ -0,0 +1,18 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Kubernetes standard labels +*/}} +{{- define "common.labels.standard" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector +*/}} +{{- define "common.labels.matchLabels" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_names.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_names.tpl new file mode 100644 index 000000000..adf2a74f4 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_names.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "common.names.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_secrets.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_secrets.tpl new file mode 100644 index 000000000..ebfb5d42d --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_secrets.tpl @@ -0,0 +1,57 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- $name = .name -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_storage.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_storage.tpl new file mode 100644 index 000000000..60e2a844f --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_storage.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} + +{{- $storageClass := .persistence.storageClass -}} +{{- if .global -}} + {{- if .global.storageClass -}} + {{- $storageClass = .global.storageClass -}} + {{- end -}} +{{- end -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} + +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl new file mode 100644 index 000000000..2db166851 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,13 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "common.tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_utils.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_utils.tpl new file mode 100644 index 000000000..74774a3ca --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_utils.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_warnings.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_warnings.tpl new file mode 100644 index 000000000..ae10fa41e --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/_warnings.tpl @@ -0,0 +1,14 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ +{{- end }} + +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 000000000..7a274a08c --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 000000000..3bf669dd8 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 000000000..7e0c1cbc3 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,108 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (not $existingSecret) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 000000000..f25e0ffbf --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,131 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl new file mode 100644 index 000000000..2ccc04d2d --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,72 @@ + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $existingSecret := include "common.redis.values.existingSecret" . -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $valueKeyRedisPassword := printf "%s%s" $valueKeyPrefix "password" -}} + {{- $valueKeyRedisUsePassword := printf "%s%s" $valueKeyPrefix "usePassword" -}} + + {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $usePassword := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUsePassword "context" .context) -}} + {{- if eq $usePassword "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Redis Auxiliar function to get the right value for existingSecret. + +Usage: +{{ include "common.redis.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.redis.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliar function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl new file mode 100644 index 000000000..d4cf32c77 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,44 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s=$%s' to the command.%s" .valueKey .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/values.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/values.yaml new file mode 100644 index 000000000..9ecdc93f5 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/charts/common/values.yaml @@ -0,0 +1,3 @@ +## bitnami/common +## It is required by CI/CD tools and processes. +exampleValue: common-chart diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/commonAnnotations.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/commonAnnotations.yaml new file mode 100644 index 000000000..97e18a4cc --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/commonAnnotations.yaml @@ -0,0 +1,3 @@ +commonAnnotations: + helm.sh/hook: "\"pre-install, pre-upgrade\"" + helm.sh/hook-weight: "-1" diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/default-values.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/default-values.yaml new file mode 100644 index 000000000..fc2ba605a --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/default-values.yaml @@ -0,0 +1 @@ +# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml. diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml new file mode 100644 index 000000000..347d3b40a --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/ci/shmvolume-disabled-values.yaml @@ -0,0 +1,2 @@ +shmVolume: + enabled: false diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/README.md b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/README.md new file mode 100644 index 000000000..1813a2fea --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/README.md @@ -0,0 +1 @@ +Copy here your postgresql.conf and/or pg_hba.conf files to use it as a config map. diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/conf.d/README.md b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/conf.d/README.md new file mode 100644 index 000000000..184c1875d --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/conf.d/README.md @@ -0,0 +1,4 @@ +If you don't want to provide the whole configuration file and only specify certain parameters, you can copy here your extended `.conf` files. +These files will be injected as a config maps and add/overwrite the default configuration using the `include_dir` directive that allows settings to be loaded from files other than the default `postgresql.conf`. + +More info in the [bitnami-docker-postgresql README](https://github.com/bitnami/bitnami-docker-postgresql#configuration-file). diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md new file mode 100644 index 000000000..cba38091e --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/files/docker-entrypoint-initdb.d/README.md @@ -0,0 +1,3 @@ +You can copy here your custom `.sh`, `.sql` or `.sql.gz` file so they are executed during the first boot of the image. + +More info in the [bitnami-docker-postgresql](https://github.com/bitnami/bitnami-docker-postgresql#initializing-a-new-instance) repository. \ No newline at end of file diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/NOTES.txt b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/NOTES.txt new file mode 100644 index 000000000..4e98958c1 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/NOTES.txt @@ -0,0 +1,59 @@ +** Please be patient while the chart is being deployed ** + +PostgreSQL can be accessed via port {{ template "postgresql.port" . }} on the following DNS name from within your cluster: + + {{ template "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - Read/Write connection +{{- if .Values.replication.enabled }} + {{ template "common.names.fullname" . }}-read.{{ .Release.Namespace }}.svc.cluster.local - Read only connection +{{- end }} + +{{- if not (eq (include "postgresql.username" .) "postgres") }} + +To get the password for "postgres" run: + + export POSTGRES_ADMIN_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-postgres-password}" | base64 --decode) +{{- end }} + +To get the password for "{{ template "postgresql.username" . }}" run: + + export POSTGRES_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "postgresql.secretName" . }} -o jsonpath="{.data.postgresql-password}" | base64 --decode) + +To connect to your database run the following command: + + kubectl run {{ template "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --namespace {{ .Release.Namespace }} --image {{ template "postgresql.image" . }} --env="PGPASSWORD=$POSTGRES_PASSWORD" {{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} + --labels="{{ template "common.names.fullname" . }}-client=true" {{- end }} --command -- psql --host {{ template "common.names.fullname" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to this PostgreSQL cluster. +{{- end }} + +To connect to your database from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $NODE_IP --port $NODE_PORT -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host $SERVICE_IP --port {{ template "postgresql.port" . }} -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "common.names.fullname" . }} {{ template "postgresql.port" . }}:{{ template "postgresql.port" . }} & + {{ if (include "postgresql.password" . ) }}PGPASSWORD="$POSTGRES_PASSWORD" {{ end }}psql --host 127.0.0.1 -U {{ .Values.postgresqlUsername }} -d {{- if .Values.postgresqlDatabase }} {{ .Values.postgresqlDatabase }}{{- else }} postgres{{- end }} -p {{ template "postgresql.port" . }} + +{{- end }} + +{{- include "postgresql.validateValues" . -}} + +{{- include "common.warnings.rollingTag" .Values.image -}} + +{{- $passwordValidationErrors := include "common.validations.values.postgresql.passwords" (dict "secret" (include "common.names.fullname" .) "context" $) -}} + +{{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $passwordValidationErrors) "context" $) -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/_helpers.tpl b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/_helpers.tpl new file mode 100644 index 000000000..7509941cf --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/_helpers.tpl @@ -0,0 +1,330 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "postgresql.primary.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- $fullname := default (printf "%s-%s" .Release.Name $name) .Values.fullnameOverride -}} +{{- if .Values.replication.enabled -}} +{{- printf "%s-%s" $fullname "primary" | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $fullname | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper PostgreSQL image name +*/}} +{{- define "postgresql.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper PostgreSQL metrics image name +*/}} +{{- define "postgresql.metrics.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "postgresql.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "postgresql.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Return PostgreSQL postgres user password +*/}} +{{- define "postgresql.postgres.password" -}} +{{- if .Values.global.postgresql.postgresqlPostgresPassword }} + {{- .Values.global.postgresql.postgresqlPostgresPassword -}} +{{- else if .Values.postgresqlPostgresPassword -}} + {{- .Values.postgresqlPostgresPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL password +*/}} +{{- define "postgresql.password" -}} +{{- if .Values.global.postgresql.postgresqlPassword }} + {{- .Values.global.postgresql.postgresqlPassword -}} +{{- else if .Values.postgresqlPassword -}} + {{- .Values.postgresqlPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication password +*/}} +{{- define "postgresql.replication.password" -}} +{{- if .Values.global.postgresql.replicationPassword }} + {{- .Values.global.postgresql.replicationPassword -}} +{{- else if .Values.replication.password -}} + {{- .Values.replication.password -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL username +*/}} +{{- define "postgresql.username" -}} +{{- if .Values.global.postgresql.postgresqlUsername }} + {{- .Values.global.postgresql.postgresqlUsername -}} +{{- else -}} + {{- .Values.postgresqlUsername -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL replication username +*/}} +{{- define "postgresql.replication.username" -}} +{{- if .Values.global.postgresql.replicationUser }} + {{- .Values.global.postgresql.replicationUser -}} +{{- else -}} + {{- .Values.replication.user -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL port +*/}} +{{- define "postgresql.port" -}} +{{- if .Values.global.postgresql.servicePort }} + {{- .Values.global.postgresql.servicePort -}} +{{- else -}} + {{- .Values.service.port -}} +{{- end -}} +{{- end -}} + +{{/* +Return PostgreSQL created database +*/}} +{{- define "postgresql.database" -}} +{{- if .Values.global.postgresql.postgresqlDatabase }} + {{- .Values.global.postgresql.postgresqlDatabase -}} +{{- else if .Values.postgresqlDatabase -}} + {{- .Values.postgresqlDatabase -}} +{{- end -}} +{{- end -}} + +{{/* +Get the password secret. +*/}} +{{- define "postgresql.secretName" -}} +{{- if .Values.global.postgresql.existingSecret }} + {{- printf "%s" (tpl .Values.global.postgresql.existingSecret $) -}} +{{- else if .Values.existingSecret -}} + {{- printf "%s" (tpl .Values.existingSecret $) -}} +{{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if we should use an existingSecret. +*/}} +{{- define "postgresql.useExistingSecret" -}} +{{- if or .Values.global.postgresql.existingSecret .Values.existingSecret -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created +*/}} +{{- define "postgresql.createSecret" -}} +{{- if not (include "postgresql.useExistingSecret" .) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the configuration ConfigMap name. +*/}} +{{- define "postgresql.configurationCM" -}} +{{- if .Values.configurationConfigMap -}} +{{- printf "%s" (tpl .Values.configurationConfigMap $) -}} +{{- else -}} +{{- printf "%s-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the extended configuration ConfigMap name. +*/}} +{{- define "postgresql.extendedConfigurationCM" -}} +{{- if .Values.extendedConfConfigMap -}} +{{- printf "%s" (tpl .Values.extendedConfConfigMap $) -}} +{{- else -}} +{{- printf "%s-extended-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap should be mounted with PostgreSQL configuration +*/}} +{{- define "postgresql.mountConfigurationCM" -}} +{{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "postgresql.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts Secret name. +*/}} +{{- define "postgresql.initdbScriptsSecret" -}} +{{- printf "%s" (tpl .Values.initdbScriptsSecret $) -}} +{{- end -}} + +{{/* +Get the metrics ConfigMap name. +*/}} +{{- define "postgresql.metricsCM" -}} +{{- printf "%s-metrics" (include "common.names.fullname" .) -}} +{{- end -}} + +{{/* +Get the readiness probe command +*/}} +{{- define "postgresql.readinessProbeCommand" -}} +- | +{{- if (include "postgresql.database" .) }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- else }} + exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} +{{- end }} +{{- if contains "bitnami/" .Values.image.repository }} + [ -f /opt/bitnami/postgresql/tmp/.initialized ] || [ -f /bitnami/postgresql/.initialized ] +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "postgresql.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "postgresql.validateValues.ldapConfigurationMethod" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.psp" .) -}} +{{- $messages := append $messages (include "postgresql.validateValues.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If ldap.url is used then you don't need the other settings for ldap +*/}} +{{- define "postgresql.validateValues.ldapConfigurationMethod" -}} +{{- if and .Values.ldap.enabled (and (not (empty .Values.ldap.url)) (not (empty .Values.ldap.server))) }} +postgresql: ldap.url, ldap.server + You cannot set both `ldap.url` and `ldap.server` at the same time. + Please provide a unique way to configure LDAP. + More info at https://www.postgresql.org/docs/current/auth-ldap.html +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql - If PSP is enabled RBAC should be enabled too +*/}} +{{- define "postgresql.validateValues.psp" -}} +{{- if and .Values.psp.create (not .Values.rbac.create) }} +postgresql: psp.create, rbac.create + RBAC should be enabled if PSP is enabled in order for PSP to work. + More info at https://kubernetes.io/docs/concepts/policy/pod-security-policy/#authorizing-policies +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- if semverCompare "<1.10-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "postgresql.networkPolicy.apiVersion" -}} +{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"extensions/v1beta1" +{{- else if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion -}} +"networking.k8s.io/v1" +{{- end -}} +{{- end -}} + +{{/* +Validate values of Postgresql TLS - When TLS is enabled, so must be VolumePermissions +*/}} +{{- define "postgresql.validateValues.tls" -}} +{{- if and .Values.tls.enabled (not .Values.volumePermissions.enabled) }} +postgresql: tls.enabled, volumePermissions.enabled + When TLS is enabled you must enable volumePermissions as well to ensure certificates files have + the right permissions. +{{- end -}} +{{- end -}} + +{{/* +Return the path to the cert file. +*/}} +{{- define "postgresql.tlsCert" -}} +{{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the cert key file. +*/}} +{{- define "postgresql.tlsCertKey" -}} +{{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/postgresql/certs/%s" -}} +{{- end -}} + +{{/* +Return the path to the CA cert file. +*/}} +{{- define "postgresql.tlsCACert" -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.certCAFilename -}} +{{- end -}} + +{{/* +Return the path to the CRL file. +*/}} +{{- define "postgresql.tlsCRL" -}} +{{- if .Values.tls.crlFilename -}} +{{- printf "/opt/bitnami/postgresql/certs/%s" .Values.tls.crlFilename -}} +{{- end -}} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/configmap.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/configmap.yaml new file mode 100644 index 000000000..4508f95a4 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/configmap.yaml @@ -0,0 +1,26 @@ +{{ if and (or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration) (not .Values.configurationConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- if (.Files.Glob "files/postgresql.conf") }} +{{ (.Files.Glob "files/postgresql.conf").AsConfig | indent 2 }} +{{- else if .Values.postgresqlConfiguration }} + postgresql.conf: | +{{- range $key, $value := default dict .Values.postgresqlConfiguration }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- if (.Files.Glob "files/pg_hba.conf") }} +{{ (.Files.Glob "files/pg_hba.conf").AsConfig | indent 2 }} +{{- else if .Values.pgHbaConfiguration }} + pg_hba.conf: | +{{ .Values.pgHbaConfiguration | indent 4 }} +{{- end }} +{{ end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extended-config-configmap.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extended-config-configmap.yaml new file mode 100644 index 000000000..5ccdb08f8 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extended-config-configmap.yaml @@ -0,0 +1,21 @@ +{{- if and (or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf) (not .Values.extendedConfConfigMap)}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-extended-configuration + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- with .Files.Glob "files/conf.d/*.conf" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{ with .Values.postgresqlExtendedConf }} + override.conf: | +{{- range $key, $value := . }} + {{ $key | snakecase }}={{ $value }} +{{- end }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extra-list.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extra-list.yaml new file mode 100644 index 000000000..9ac65f9e1 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/initialization-configmap.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/initialization-configmap.yaml new file mode 100644 index 000000000..074ed5827 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/initialization-configmap.yaml @@ -0,0 +1,24 @@ +{{- if and (or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScripts) (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }}-init-scripts + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.sql.gz" }} +binaryData: +{{- range $path, $bytes := . }} + {{ base $path }}: {{ $.Files.Get $path | b64enc | quote }} +{{- end }} +{{- end }} +data: +{{- with .Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql}" }} +{{ .AsConfig | indent 2 }} +{{- end }} +{{- with .Values.initdbScripts }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-configmap.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-configmap.yaml new file mode 100644 index 000000000..6216eca84 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-configmap.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "postgresql.metricsCM" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + custom-metrics.yaml: {{ toYaml .Values.metrics.customMetrics | quote }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-svc.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-svc.yaml new file mode 100644 index 000000000..a8f7b3310 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/metrics-svc.yaml @@ -0,0 +1,25 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-metrics + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- toYaml .Values.metrics.service.annotations | nindent 4 }} +spec: + type: {{ .Values.metrics.service.type }} + {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }} + {{- end }} + ports: + - name: http-metrics + port: 9187 + targetPort: http-metrics + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/networkpolicy.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/networkpolicy.yaml new file mode 100644 index 000000000..ef48ba182 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/networkpolicy.yaml @@ -0,0 +1,38 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "postgresql.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + ingress: + # Allow inbound connections + - ports: + - port: {{ template "postgresql.port" . }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: +{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + role: read + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow prometheus scrapes + - ports: + - port: 9187 + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/podsecuritypolicy.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..a79ebf163 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/podsecuritypolicy.yaml @@ -0,0 +1,37 @@ +{{- if .Values.psp.create }} +apiVersion: {{ include "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + privileged: false + volumes: + - 'configMap' + - 'secret' + - 'persistentVolumeClaim' + - 'emptyDir' + - 'projected' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/prometheusrule.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/prometheusrule.yaml new file mode 100644 index 000000000..d0f408c78 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/prometheusrule.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "common.names.fullname" . }} +{{- with .Values.metrics.prometheusRule.namespace }} + namespace: {{ . }} +{{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- with .Values.metrics.prometheusRule.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: +{{- with .Values.metrics.prometheusRule.rules }} + groups: + - name: {{ template "postgresql.name" $ }} + rules: {{ tpl (toYaml .) $ | nindent 8 }} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/role.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/role.yaml new file mode 100644 index 000000000..5a6de3350 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/role.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + {{- if .Values.psp.create }} + - apiGroups: ["extensions"] + resources: ["podsecuritypolicies"] + verbs: ["use"] + resourceNames: + - {{ template "common.names.fullname" . }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/rolebinding.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/rolebinding.yaml new file mode 100644 index 000000000..2bdb1c5ea --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + kind: Role + name: {{ template "common.names.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/secrets.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/secrets.yaml new file mode 100644 index 000000000..8351cbe8b --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/secrets.yaml @@ -0,0 +1,21 @@ +{{- if (include "postgresql.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + postgresql-postgres-password: {{ include "postgresql.postgres.password" . | b64enc | quote }} + postgresql-password: {{ include "postgresql.password" . | b64enc | quote }} + {{- if .Values.replication.enabled }} + postgresql-replication-password: {{ include "postgresql.replication.password" . | b64enc | quote }} + {{- end }} + {{- if (and .Values.ldap.enabled .Values.ldap.bind_password)}} + postgresql-ldap-password: {{ .Values.ldap.bind_password | b64enc | quote }} + {{- end }} +{{- end -}} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/serviceaccount.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/serviceaccount.yaml new file mode 100644 index 000000000..8cba31e43 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if and (.Values.serviceAccount.enabled) (not .Values.serviceAccount.name) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "common.labels.standard" . | nindent 4 }} + name: {{ template "common.names.fullname" . }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/servicemonitor.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/servicemonitor.yaml new file mode 100644 index 000000000..587ce85b8 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- end }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} + {{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + +spec: + endpoints: + - port: http-metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset-readreplicas.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset-readreplicas.yaml new file mode 100644 index 000000000..1f5b97043 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset-readreplicas.yaml @@ -0,0 +1,410 @@ +{{- if .Values.replication.enabled }} +{{- $readReplicasResources := coalesce .Values.readReplicas.resources .Values.resources -}} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: "{{ template "common.names.fullname" . }}-read" + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: read +{{- with .Values.readReplicas.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.readReplicas.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: {{ .Values.replication.readReplicas }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: read + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: read + role: read +{{- with .Values.readReplicas.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.readReplicas.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.readReplicas.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAffinityPreset "component" "read" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.readReplicas.podAntiAffinityPreset "component" "read" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.readReplicas.nodeAffinityPreset.type "key" .Values.readReplicas.nodeAffinityPreset.key "values" .Values.readReplicas.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.readReplicas.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.readReplicas.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.readReplicas.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name}} + {{- end }} + {{- if or .Values.readReplicas.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{ if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.readReplicas.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.readReplicas.priorityClassName }} + priorityClassName: {{ .Values.readReplicas.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if $readReplicasResources }} + resources: {{- toYaml $readReplicasResources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + - name: POSTGRES_REPLICATION_MODE + value: "slave" + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + - name: POSTGRES_MASTER_HOST + value: {{ template "common.names.fullname" . }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ include "postgresql.port" . | quote }} + {{- if and (not (eq .Values.postgresqlUsername "postgres")) (or .Values.postgresqlPostgresPassword (include "postgresql.useExistingSecret" .)) }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{ end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.readReplicas.extraVolumeMounts }} + {{- toYaml .Values.readReplicas.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.readReplicas.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.readReplicas.sidecars "context" $ ) | nindent 8 }} +{{- end }} + volumes: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} + {{- if or (not .Values.persistence.enabled) (not .Values.readReplicas.persistence.enabled) }} + - name: data + emptyDir: {} + {{- end }} + {{- if .Values.readReplicas.extraVolumes }} + {{- toYaml .Values.readReplicas.extraVolumes | nindent 8 }} + {{- end }} + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} +{{- if and .Values.persistence.enabled .Values.readReplicas.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset.yaml new file mode 100644 index 000000000..e3de05e72 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/statefulset.yaml @@ -0,0 +1,589 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "postgresql.primary.fullname" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- with .Values.primary.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- with .Values.primary.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + serviceName: {{ template "common.names.fullname" . }}-headless + replicas: 1 + updateStrategy: + type: {{ .Values.updateStrategy.type }} + {{- if (eq "Recreate" .Values.updateStrategy.type) }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 6 }} + role: primary + template: + metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 8 }} + role: primary + app.kubernetes.io/component: primary + {{- with .Values.primary.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.primary.podAnnotations }} + annotations: {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} +{{- include "postgresql.imagePullSecrets" . | indent 6 }} + {{- if .Values.primary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.primary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAffinityPreset "component" "primary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "component" "primary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.primary.nodeAffinityPreset.type "key" .Values.primary.nodeAffinityPreset.key "values" .Values.primary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.primary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.primary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ default (include "common.names.fullname" . ) .Values.serviceAccount.name }} + {{- end }} + {{- if or .Values.primary.extraInitContainers (and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled))) }} + initContainers: + {{- if and .Values.volumePermissions.enabled (or .Values.persistence.enabled (and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled) .Values.tls.enabled) }} + - name: init-chmod-data + image: {{ template "postgresql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + chmod 700 {{ .Values.persistence.mountPath }}/data {{- if (include "postgresql.mountConfigurationCM" .) }} {{ .Values.persistence.mountPath }}/conf {{- end }} + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 {{- if not (include "postgresql.mountConfigurationCM" .) }} -not -name "conf" {{- end }} -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if and .Values.shmVolume.enabled .Values.shmVolume.chmod.enabled }} + chmod -R 777 /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + cp /tmp/certs/* /opt/bitnami/postgresql/certs/ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown -R `id -u`:`id -G | cut -d " " -f2` /opt/bitnami/postgresql/certs/ + {{- else }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /opt/bitnami/postgresql/certs/ + {{- end }} + chmod 600 {{ template "postgresql.tlsCertKey" . }} + {{- end }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + mountPath: /tmp/certs + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + {{- end }} + {{- end }} + {{- if .Values.primary.extraInitContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.extraInitContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.primary.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName }} + {{- end }} + containers: + - name: {{ template "common.names.fullname" . }} + image: {{ template "postgresql.image" . }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" .Values.image.debug | quote }} + - name: POSTGRESQL_PORT_NUMBER + value: "{{ template "postgresql.port" . }}" + - name: POSTGRESQL_VOLUME_DIR + value: "{{ .Values.persistence.mountPath }}" + {{- if .Values.postgresqlInitdbArgs }} + - name: POSTGRES_INITDB_ARGS + value: {{ .Values.postgresqlInitdbArgs | quote }} + {{- end }} + {{- if .Values.postgresqlInitdbWalDir }} + - name: POSTGRES_INITDB_WALDIR + value: {{ .Values.postgresqlInitdbWalDir | quote }} + {{- end }} + {{- if .Values.initdbUser }} + - name: POSTGRESQL_INITSCRIPTS_USERNAME + value: {{ .Values.initdbUser }} + {{- end }} + {{- if .Values.initdbPassword }} + - name: POSTGRESQL_INITSCRIPTS_PASSWORD + value: {{ .Values.initdbPassword }} + {{- end }} + {{- if .Values.persistence.mountPath }} + - name: PGDATA + value: {{ .Values.postgresqlDataDir | quote }} + {{- end }} + {{- if .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_MASTER_HOST + value: {{ .Values.primaryAsStandBy.primaryHost }} + - name: POSTGRES_MASTER_PORT_NUMBER + value: {{ .Values.primaryAsStandBy.primaryPort | quote }} + {{- end }} + {{- if or .Values.replication.enabled .Values.primaryAsStandBy.enabled }} + - name: POSTGRES_REPLICATION_MODE + {{- if .Values.primaryAsStandBy.enabled }} + value: "slave" + {{- else }} + value: "master" + {{- end }} + - name: POSTGRES_REPLICATION_USER + value: {{ include "postgresql.replication.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_REPLICATION_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-replication-password" + {{- else }} + - name: POSTGRES_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-replication-password + {{- end }} + {{- if not (eq .Values.replication.synchronousCommit "off")}} + - name: POSTGRES_SYNCHRONOUS_COMMIT_MODE + value: {{ .Values.replication.synchronousCommit | quote }} + - name: POSTGRES_NUM_SYNCHRONOUS_REPLICAS + value: {{ .Values.replication.numSynchronousReplicas | quote }} + {{- end }} + - name: POSTGRES_CLUSTER_APP_NAME + value: {{ .Values.replication.applicationName }} + {{- end }} + {{- if not (eq (include "postgresql.username" .) "postgres") }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-postgres-password" + {{- else }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-postgres-password + {{- end }} + {{- end }} + - name: POSTGRES_USER + value: {{ include "postgresql.username" . | quote }} + {{- if .Values.usePasswordFile }} + - name: POSTGRES_PASSWORD_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + {{- if (include "postgresql.database" .) }} + - name: POSTGRES_DB + value: {{ (include "postgresql.database" .) | quote }} + {{- end }} + {{- if .Values.extraEnv }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnv "context" $) | nindent 12 }} + {{- end }} + - name: POSTGRESQL_ENABLE_LDAP + value: {{ ternary "yes" "no" .Values.ldap.enabled | quote }} + {{- if .Values.ldap.enabled }} + - name: POSTGRESQL_LDAP_SERVER + value: {{ .Values.ldap.server }} + - name: POSTGRESQL_LDAP_PORT + value: {{ .Values.ldap.port | quote }} + - name: POSTGRESQL_LDAP_SCHEME + value: {{ .Values.ldap.scheme }} + {{- if .Values.ldap.tls }} + - name: POSTGRESQL_LDAP_TLS + value: "1" + {{- end }} + - name: POSTGRESQL_LDAP_PREFIX + value: {{ .Values.ldap.prefix | quote }} + - name: POSTGRESQL_LDAP_SUFFIX + value: {{ .Values.ldap.suffix | quote }} + - name: POSTGRESQL_LDAP_BASE_DN + value: {{ .Values.ldap.baseDN }} + - name: POSTGRESQL_LDAP_BIND_DN + value: {{ .Values.ldap.bindDN }} + {{- if (not (empty .Values.ldap.bind_password)) }} + - name: POSTGRESQL_LDAP_BIND_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-ldap-password + {{- end}} + - name: POSTGRESQL_LDAP_SEARCH_ATTR + value: {{ .Values.ldap.search_attr }} + - name: POSTGRESQL_LDAP_SEARCH_FILTER + value: {{ .Values.ldap.search_filter }} + - name: POSTGRESQL_LDAP_URL + value: {{ .Values.ldap.url }} + {{- end}} + - name: POSTGRESQL_ENABLE_TLS + value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} + {{- if .Values.tls.enabled }} + - name: POSTGRESQL_TLS_PREFER_SERVER_CIPHERS + value: {{ ternary "yes" "no" .Values.tls.preferServerCiphers | quote }} + - name: POSTGRESQL_TLS_CERT_FILE + value: {{ template "postgresql.tlsCert" . }} + - name: POSTGRESQL_TLS_KEY_FILE + value: {{ template "postgresql.tlsCertKey" . }} + {{- if .Values.tls.certCAFilename }} + - name: POSTGRESQL_TLS_CA_FILE + value: {{ template "postgresql.tlsCACert" . }} + {{- end }} + {{- if .Values.tls.crlFilename }} + - name: POSTGRESQL_TLS_CRL_FILE + value: {{ template "postgresql.tlsCRL" . }} + {{- end }} + {{- end }} + - name: POSTGRESQL_LOG_HOSTNAME + value: {{ .Values.audit.logHostname | quote }} + - name: POSTGRESQL_LOG_CONNECTIONS + value: {{ .Values.audit.logConnections | quote }} + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: {{ .Values.audit.logDisconnections | quote }} + {{- if .Values.audit.logLinePrefix }} + - name: POSTGRESQL_LOG_LINE_PREFIX + value: {{ .Values.audit.logLinePrefix | quote }} + {{- end }} + {{- if .Values.audit.logTimezone }} + - name: POSTGRESQL_LOG_TIMEZONE + value: {{ .Values.audit.logTimezone | quote }} + {{- end }} + {{- if .Values.audit.pgAuditLog }} + - name: POSTGRESQL_PGAUDIT_LOG + value: {{ .Values.audit.pgAuditLog | quote }} + {{- end }} + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: {{ .Values.audit.pgAuditLogCatalog | quote }} + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: {{ .Values.audit.clientMinMessages | quote }} + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: {{ .Values.postgresqlSharedPreloadLibraries | quote }} + {{- if .Values.postgresqlMaxConnections }} + - name: POSTGRESQL_MAX_CONNECTIONS + value: {{ .Values.postgresqlMaxConnections | quote }} + {{- end }} + {{- if .Values.postgresqlPostgresConnectionLimit }} + - name: POSTGRESQL_POSTGRES_CONNECTION_LIMIT + value: {{ .Values.postgresqlPostgresConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlDbUserConnectionLimit }} + - name: POSTGRESQL_USERNAME_CONNECTION_LIMIT + value: {{ .Values.postgresqlDbUserConnectionLimit | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesInterval }} + - name: POSTGRESQL_TCP_KEEPALIVES_INTERVAL + value: {{ .Values.postgresqlTcpKeepalivesInterval | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeepalivesIdle }} + - name: POSTGRESQL_TCP_KEEPALIVES_IDLE + value: {{ .Values.postgresqlTcpKeepalivesIdle | quote }} + {{- end }} + {{- if .Values.postgresqlStatementTimeout }} + - name: POSTGRESQL_STATEMENT_TIMEOUT + value: {{ .Values.postgresqlStatementTimeout | quote }} + {{- end }} + {{- if .Values.postgresqlTcpKeealivesCount }} + - name: POSTGRESQL_TCP_KEEPALIVES_COUNT + value: {{ .Values.postgresqlTcpKeealivesCount | quote }} + {{- end }} + {{- if .Values.postgresqlPghbaRemoveFilters }} + - name: POSTGRESQL_PGHBA_REMOVE_FILTERS + value: {{ .Values.postgresqlPghbaRemoveFilters | quote }} + {{- end }} + {{- if .Values.extraEnvVarsCM }} + envFrom: + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . }} + {{- end }} + ports: + - name: tcp-postgresql + containerPort: {{ template "postgresql.port" . }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + {{- if (include "postgresql.database" .) }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} -d "dbname={{ include "postgresql.database" . }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}{{- end }}" -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- else }} + - exec pg_isready -U {{ include "postgresql.username" . | quote }} {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} -d "sslcert={{ include "postgresql.tlsCert" . }} sslkey={{ include "postgresql.tlsCertKey" . }}"{{- end }} -h 127.0.0.1 -p {{ template "postgresql.port" . }} + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- else if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + {{- include "postgresql.readinessProbeCommand" . | nindent 16 }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- else if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d/ + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + mountPath: /docker-entrypoint-initdb.d/secret + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + mountPath: /bitnami/postgresql/conf/conf.d/ + {{- end }} + # {{- if .Values.usePasswordFile }} + #- name: postgresql-password + # mountPath: /opt/bitnami/postgresql/secrets/ + #{{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + mountPath: /dev/shm + {{- end }} + {{- if .Values.persistence.enabled }} + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap }} + - name: postgresql-config + mountPath: /bitnami/postgresql/conf + {{- end }} + {{- if .Values.primary.extraVolumeMounts }} + {{- toYaml .Values.primary.extraVolumeMounts | nindent 12 }} + {{- end }} +{{- if .Values.primary.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.primary.sidecars "context" $ ) | nindent 8 }} +{{- end }} +{{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "postgresql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.securityContext.enabled }} + securityContext: {{- omit .Values.metrics.securityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- $database := required "In order to enable metrics you need to specify a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase)" (include "postgresql.database" .) }} + {{- $sslmode := ternary "require" "disable" .Values.tls.enabled }} + {{- if and .Values.tls.enabled .Values.tls.certCAFilename }} + - name: DATA_SOURCE_NAME + value: {{ printf "host=127.0.0.1 port=%d user=%s sslmode=%s sslcert=%s sslkey=%s" (int (include "postgresql.port" .)) (include "postgresql.username" .) $sslmode (include "postgresql.tlsCert" .) (include "postgresql.tlsCertKey" .) }} + {{- else }} + - name: DATA_SOURCE_URI + value: {{ printf "127.0.0.1:%d/%s?sslmode=%s" (int (include "postgresql.port" .)) $database $sslmode }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: DATA_SOURCE_PASS_FILE + value: "/opt/bitnami/postgresql/secrets/postgresql-password" + {{- else }} + - name: DATA_SOURCE_PASS + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secretName" . }} + key: postgresql-password + {{- end }} + - name: DATA_SOURCE_USER + value: {{ template "postgresql.username" . }} + {{- if .Values.metrics.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http-metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} + {{- end }} + volumeMounts: + {{- if .Values.usePasswordFile }} + - name: postgresql-password + mountPath: /opt/bitnami/postgresql/secrets/ + {{- end }} + {{- if .Values.tls.enabled }} + - name: postgresql-certificates + mountPath: /opt/bitnami/postgresql/certs + readOnly: true + {{- end }} + {{- if .Values.metrics.customMetrics }} + - name: custom-metrics + mountPath: /conf + readOnly: true + args: ["--extend.query-path", "/conf/custom-metrics.yaml"] + {{- end }} + ports: + - name: http-metrics + containerPort: 9187 + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} +{{- end }} + volumes: + {{- if or (.Files.Glob "files/postgresql.conf") (.Files.Glob "files/pg_hba.conf") .Values.postgresqlConfiguration .Values.pgHbaConfiguration .Values.configurationConfigMap}} + - name: postgresql-config + configMap: + name: {{ template "postgresql.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/conf.d/*.conf") .Values.postgresqlExtendedConf .Values.extendedConfConfigMap }} + - name: postgresql-extended-config + configMap: + name: {{ template "postgresql.extendedConfigurationCM" . }} + {{- end }} + {{- if .Values.usePasswordFile }} + - name: postgresql-password + secret: + secretName: {{ template "postgresql.secretName" . }} + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "postgresql.initdbScriptsCM" . }} + {{- end }} + {{- if .Values.initdbScriptsSecret }} + - name: custom-init-scripts-secret + secret: + secretName: {{ template "postgresql.initdbScriptsSecret" . }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: raw-certificates + secret: + secretName: {{ required "A secret containing TLS certificates is required when TLS is enabled" .Values.tls.certificatesSecret }} + - name: postgresql-certificates + emptyDir: {} + {{- end }} + {{- if .Values.primary.extraVolumes }} + {{- toYaml .Values.primary.extraVolumes | nindent 8 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.customMetrics }} + - name: custom-metrics + configMap: + name: {{ template "postgresql.metricsCM" . }} + {{- end }} + {{- if .Values.shmVolume.enabled }} + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 1Gi + {{- end }} +{{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: +{{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} +{{- end }} +{{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} +{{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-headless.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-headless.yaml new file mode 100644 index 000000000..6ad0dd5f2 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-headless.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-headless + labels: + {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + # Use this annotation in addition to the actual publishNotReadyAddresses + # field below because the annotation will stop being respected soon but the + # field is broken in some versions of Kubernetes: + # https://github.com/kubernetes/kubernetes/issues/58662 + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +spec: + type: ClusterIP + clusterIP: None + # We want all pods in the StatefulSet to have their addresses published for + # the sake of the other Postgresql pods even before they're ready, since they + # have to be able to talk to each other in order to become ready. + publishNotReadyAddresses: true + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-read.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-read.yaml new file mode 100644 index 000000000..8c9ea54e8 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc-read.yaml @@ -0,0 +1,42 @@ +{{- if .Values.replication.enabled }} +{{- $serviceAnnotations := coalesce .Values.readReplicas.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.readReplicas.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.readReplicas.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.readReplicas.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.readReplicas.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.readReplicas.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-read + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: read +{{- end }} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc.yaml new file mode 100644 index 000000000..5bc2b50ee --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/templates/svc.yaml @@ -0,0 +1,40 @@ +{{- $serviceAnnotations := coalesce .Values.primary.service.annotations .Values.service.annotations -}} +{{- $serviceType := coalesce .Values.primary.service.type .Values.service.type -}} +{{- $serviceLoadBalancerIP := coalesce .Values.primary.service.loadBalancerIP .Values.service.loadBalancerIP -}} +{{- $serviceLoadBalancerSourceRanges := coalesce .Values.primary.service.loadBalancerSourceRanges .Values.service.loadBalancerSourceRanges -}} +{{- $serviceClusterIP := coalesce .Values.primary.service.clusterIP .Values.service.clusterIP -}} +{{- $serviceNodePort := coalesce .Values.primary.service.nodePort .Values.service.nodePort -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if $serviceAnnotations }} + {{- include "common.tplvalues.render" (dict "value" $serviceAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ $serviceType }} + {{- if and $serviceLoadBalancerIP (eq $serviceType "LoadBalancer") }} + loadBalancerIP: {{ $serviceLoadBalancerIP }} + {{- end }} + {{- if and (eq $serviceType "LoadBalancer") $serviceLoadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- include "common.tplvalues.render" (dict "value" $serviceLoadBalancerSourceRanges "context" $) | nindent 4 }} + {{- end }} + {{- if and (eq $serviceType "ClusterIP") $serviceClusterIP }} + clusterIP: {{ $serviceClusterIP }} + {{- end }} + ports: + - name: tcp-postgresql + port: {{ template "postgresql.port" . }} + targetPort: tcp-postgresql + {{- if $serviceNodePort }} + nodePort: {{ $serviceNodePort }} + {{- end }} + selector: + {{- include "common.labels.matchLabels" . | nindent 4 }} + role: primary diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/values-production.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values-production.yaml new file mode 100644 index 000000000..4e1ee0416 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values-production.yaml @@ -0,0 +1,791 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: true + user: repl_user + password: repl_password + readReplicas: 2 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + ## + synchronousCommit: "on" + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + ## + numSynchronousReplicas: 1 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +## existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +# usePasswordFile: false + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: "" + server: "" + port: "" + prefix: "" + suffix: "" + baseDN: "" + bindDN: "" + bind_password: + search_attr: "" + search_filter: "" + scheme: "" + tls: {} + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read replica(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: "" + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Additional PostgreSQL Primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL Read Only Replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: "" + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + ## Additional PostgreSQL Read Replica Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL Read Replica Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for Read Replicas + ## + service: {} + # type: + # nodePort: + # clusterIP: + ## Whether to enable PostgreSQL readReplicas replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for readReplicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: "" + # + # Certificate filename + certFilename: "" + # + # Certificate Key filename + certKeyFilename: "" + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: true + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9187" + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.schema.json b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.schema.json new file mode 100644 index 000000000..66a2a9dd0 --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "postgresqlUsername": { + "type": "string", + "title": "Admin user", + "form": true + }, + "postgresqlPassword": { + "type": "string", + "title": "Password", + "form": true + }, + "persistence": { + "type": "object", + "properties": { + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi" + } + } + }, + "resources": { + "type": "object", + "title": "Required Resources", + "description": "Configure resource requests", + "form": true, + "properties": { + "requests": { + "type": "object", + "properties": { + "memory": { + "type": "string", + "form": true, + "render": "slider", + "title": "Memory Request", + "sliderMin": 10, + "sliderMax": 2048, + "sliderUnit": "Mi" + }, + "cpu": { + "type": "string", + "form": true, + "render": "slider", + "title": "CPU Request", + "sliderMin": 10, + "sliderMax": 2000, + "sliderUnit": "m" + } + } + } + } + }, + "replication": { + "type": "object", + "form": true, + "title": "Replication Details", + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable Replication", + "form": true + }, + "readReplicas": { + "type": "integer", + "title": "read Replicas", + "form": true, + "hidden": { + "value": false, + "path": "replication/enabled" + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable Init Containers", + "description": "Change the owner of the persist volume mountpoint to RunAsUser:fsGroup" + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "title": "Configure metrics exporter", + "form": true + } + } + } + } +} diff --git a/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.yaml b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.yaml new file mode 100644 index 000000000..e2884371c --- /dev/null +++ b/sample-cnfs/sample_unmounted_secret_volume/postgresql/values.yaml @@ -0,0 +1,813 @@ +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +global: + postgresql: {} +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami PostgreSQL image version +## ref: https://hub.docker.com/r/bitnami/postgresql/tags/ +## +image: + registry: docker.io + repository: bitnami/postgresql + tag: 11.10.0-debian-10-r24 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + ## + debug: false + +## String to partially override common.names.fullname template (will maintain the release name) +## +# nameOverride: + +## String to fully override common.names.fullname template +## +# fullnameOverride: + +## +## Init containers parameters: +## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup +## +volumePermissions: + enabled: false + image: + registry: docker.io + repository: bitnami/minideb + tag: buster + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + runAsUser: 0 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Pod Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + +## Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + +## Pod Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + enabled: false + ## Name of an already existing service account. Setting this value disables the automatic service account creation. + # name: + +## Pod Security Policy +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +psp: + create: false + +## Creates role for ServiceAccount +## Required for PSP +## +rbac: + create: false + +replication: + enabled: false + user: repl_user + password: repl_password + readReplicas: 1 + ## Set synchronous commit mode: on, off, remote_apply, remote_write and local + ## ref: https://www.postgresql.org/docs/9.6/runtime-config-wal.html#GUC-WAL-LEVEL + synchronousCommit: 'off' + ## From the number of `readReplicas` defined above, set the number of those that will have synchronous replication + ## NOTE: It cannot be > readReplicas + numSynchronousReplicas: 0 + ## Replication Cluster application name. Useful for defining multiple replication policies + ## + applicationName: my_application + +## PostgreSQL admin password (used when `postgresqlUsername` is not `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-user-on-first-run (see note!) +# postgresqlPostgresPassword: + +## PostgreSQL user (has superuser privileges if username is `postgres`) +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +postgresqlUsername: postgres + +## PostgreSQL password +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#setting-the-root-password-on-first-run +## +# postgresqlPassword: + +## PostgreSQL password using existing secret +# existingSecret: secret +## + +## Mount PostgreSQL secret as a file instead of passing environment variable +usePasswordFile: true + +## Create a database +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md#creating-a-database-on-first-run +## +# postgresqlDatabase: + +## PostgreSQL data dir +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +postgresqlDataDir: /bitnami/postgresql/data + +## An array to add extra environment variables +## For example: +## extraEnv: +## - name: FOO +## value: "bar" +## +# extraEnv: +extraEnv: [] + +## Name of a ConfigMap containing extra env vars +## +# extraEnvVarsCM: + +## Specify extra initdb args +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbArgs: + +## Specify a custom location for the PostgreSQL transaction log +## ref: https://github.com/bitnami/bitnami-docker-postgresql/blob/master/README.md +## +# postgresqlInitdbWalDir: + +## PostgreSQL configuration +## Specify runtime configuration parameters as a dict, using camelCase, e.g. +## {"sharedBuffers": "500MB"} +## Alternatively, you can put your postgresql.conf under the files/ directory +## ref: https://www.postgresql.org/docs/current/static/runtime-config.html +## +# postgresqlConfiguration: + +## PostgreSQL extended configuration +## As above, but _appended_ to the main configuration +## Alternatively, you can put your *.conf under the files/conf.d/ directory +## https://github.com/bitnami/bitnami-docker-postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf +## +# postgresqlExtendedConf: + +## Configure current cluster's primary server to be the standby server in other cluster. +## This will allow cross cluster replication and provide cross cluster high availability. +## You will need to configure pgHbaConfiguration if you want to enable this feature with local cluster replication enabled. +## +primaryAsStandBy: + enabled: false + # primaryHost: + # primaryPort: + +## PostgreSQL client authentication configuration +## Specify content for pg_hba.conf +## Default: do not create pg_hba.conf +## Alternatively, you can put your pg_hba.conf under the files/ directory +# pgHbaConfiguration: |- +# local all all trust +# host all all localhost trust +# host mydatabase mysuser 192.168.0.0/24 md5 + +## ConfigMap with PostgreSQL configuration +## NOTE: This will override postgresqlConfiguration and pgHbaConfiguration +# configurationConfigMap: + +## ConfigMap with PostgreSQL extended configuration +# extendedConfConfigMap: + +## initdb scripts +## Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## +# initdbScripts: +# my_init_script.sh: | +# #!/bin/sh +# echo "Do something." + +## ConfigMap with scripts to be run at first boot +## NOTE: This will override initdbScripts +# initdbScriptsConfigMap: + +## Secret with scripts to be run at first boot (in case it contains sensitive information) +## NOTE: This can work along initdbScripts or initdbScriptsConfigMap +# initdbScriptsSecret: + +## Specify the PostgreSQL username and password to execute the initdb scripts +# initdbUser: +# initdbPassword: + +## Audit settings +## https://github.com/bitnami/bitnami-docker-postgresql#auditing +## +audit: + ## Log client hostnames + ## + logHostname: false + ## Log connections to the server + ## + logConnections: false + ## Log disconnections + ## + logDisconnections: false + ## Operation to audit using pgAudit (default if not set) + ## + pgAuditLog: "" + ## Log catalog using pgAudit + ## + pgAuditLogCatalog: "off" + ## Log level for clients + ## + clientMinMessages: error + ## Template for log line prefix (default if not set) + ## + logLinePrefix: "" + ## Log timezone + ## + logTimezone: "" + +## Shared preload libraries +## +postgresqlSharedPreloadLibraries: "pgaudit" + +## Maximum total connections +## +postgresqlMaxConnections: + +## Maximum connections for the postgres user +## +postgresqlPostgresConnectionLimit: + +## Maximum connections for the created user +## +postgresqlDbUserConnectionLimit: + +## TCP keepalives interval +## +postgresqlTcpKeepalivesInterval: + +## TCP keepalives idle +## +postgresqlTcpKeepalivesIdle: + +## TCP keepalives count +## +postgresqlTcpKeepalivesCount: + +## Statement timeout +## +postgresqlStatementTimeout: + +## Remove pg_hba.conf lines with the following comma-separated patterns +## (cannot be used with custom pg_hba.conf) +## +postgresqlPghbaRemoveFilters: + +## Optional duration in seconds the pod needs to terminate gracefully. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +# terminationGracePeriodSeconds: 30 + +## LDAP configuration +## +ldap: + enabled: false + url: '' + server: '' + port: '' + prefix: '' + suffix: '' + baseDN: '' + bindDN: '' + bind_password: + search_attr: '' + search_filter: '' + scheme: '' + tls: {} + +## PostgreSQL service configuration +## +service: + ## PosgresSQL service type + ## + type: ClusterIP + # clusterIP: None + port: 5432 + + ## Specify the nodePort value for the LoadBalancer and NodePort service types. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + # nodePort: + + ## Provide any additional annotations which may be required. Evaluated as a template. + ## + annotations: {} + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources. Evaluated as a template. + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + # loadBalancerSourceRanges: + # - 10.10.10.0/24 + +## Start primary and read(s) pod(s) without limitations on shm memory. +## By default docker and containerd (and possibly other container runtimes) +## limit `/dev/shm` to `64M` (see e.g. the +## [docker issue](https://github.com/docker-library/postgres/issues/416) and the +## [containerd issue](https://github.com/containerd/containerd/issues/3654), +## which could be not enough if PostgreSQL uses parallel workers heavily. +## +shmVolume: + ## Set `shmVolume.enabled` to `true` to mount a new tmpfs volume to remove + ## this limitation. + ## + enabled: true + ## Set to `true` to `chmod 777 /dev/shm` on a initContainer. + ## This option is ignored if `volumePermissions.enabled` is `false` + ## + chmod: + enabled: true + +## PostgreSQL data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: true + ## A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template, so, for example, the name can depend on .Release or .Chart + ## + # existingClaim: + + ## The path the volume will be mounted at, useful when using different + ## PostgreSQL images. + ## + mountPath: /bitnami/postgresql + + ## The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: '' + + # storageClass: "-" + accessModes: + - ReadWriteOnce + size: 8Gi + annotations: {} + ## selector can be used to match an existing PersistentVolume + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + +## updateStrategy for PostgreSQL StatefulSet and its reads StatefulSets +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + +## +## PostgreSQL Primary parameters +## +primary: + ## PostgreSQL Primary pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL Primary pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: primary.podAffinityPreset, primary.podAntiAffinityPreset, and primary.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL primary Volume mounts + ## + extraVolumeMounts: [] + ## Additional PostgreSQL primary Volumes + ## + extraVolumes: [] + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for primary + ## + service: {} + # type: + # nodePort: + # clusterIP: + +## +## PostgreSQL read only replica parameters +## +readReplicas: + ## PostgreSQL read only pod affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAffinityPreset: "" + + ## PostgreSQL read only pod anti-affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + + ## PostgreSQL read only node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## Node affinity type + ## Allowed values: soft, hard + type: "" + ## Node label key to match + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## Node label values to match + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + + ## Affinity for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: readReplicas.podAffinityPreset, readReplicas.podAntiAffinityPreset, and readReplicas.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + + ## Node labels for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for PostgreSQL read only pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + labels: {} + annotations: {} + podLabels: {} + podAnnotations: {} + priorityClassName: '' + + ## Extra init containers + ## Example + ## + ## extraInitContainers: + ## - name: do-something + ## image: busybox + ## command: ['do', 'something'] + ## + extraInitContainers: [] + + ## Additional PostgreSQL read replicas Volume mounts + ## + extraVolumeMounts: [] + + ## Additional PostgreSQL read replicas Volumes + ## + extraVolumes: [] + + ## Add sidecars to the pod + ## + ## For example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + + ## Override the service configuration for read + ## + service: {} + # type: + # nodePort: + # clusterIP: + + ## Whether to enable PostgreSQL read replicas data Persistent + ## + persistence: + enabled: true + + # Override the resource configuration for read replicas + resources: {} + # requests: + # memory: 256Mi + # cpu: 250m + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 250m + +## Add annotations to all the deployed resources +## +commonAnnotations: {} + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the port PostgreSQL is listening + ## on. When true, PostgreSQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + + ## if explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Custom Liveness probe +## +customLivenessProbe: {} + +## Custom Rediness probe +## +customReadinessProbe: {} + +## +## TLS configuration +## +tls: + # Enable TLS traffic + enabled: false + # + # Whether to use the server's TLS cipher preferences rather than the client's. + preferServerCiphers: true + # + # Name of the Secret that contains the certificates + certificatesSecret: '' + # + # Certificate filename + certFilename: '' + # + # Certificate Key filename + certKeyFilename: '' + # + # CA Certificate filename + # If provided, PostgreSQL will authenticate TLS/SSL clients by requesting them a certificate + # ref: https://www.postgresql.org/docs/9.6/auth-methods.html + certCAFilename: + # + # File containing a Certificate Revocation List + crlFilename: + +## Configure metrics exporter +## +metrics: + enabled: false + # resources: {} + service: + type: ClusterIP + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '9187' + loadBalancerIP: + serviceMonitor: + enabled: false + additionalLabels: {} + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + ## Custom PrometheusRule to be defined + ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + enabled: false + additionalLabels: {} + namespace: '' + ## These are just examples rules, please adapt them to your needs. + ## Make sure to constraint the rules to the current postgresql service. + ## rules: + ## - alert: HugeReplicationLag + ## expr: pg_replication_lag{service="{{ template "common.names.fullname" . }}-metrics"} / 3600 > 1 + ## for: 1m + ## labels: + ## severity: critical + ## annotations: + ## description: replication for {{ template "common.names.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s). + ## summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s). + ## + rules: [] + + image: + registry: docker.io + repository: bitnami/postgres-exporter + tag: 0.8.0-debian-10-r293 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName + ## Define additional custom metrics + ## ref: https://github.com/wrouesnel/postgres_exporter#adding-new-metrics-via-a-config-file + # customMetrics: + # pg_database: + # query: "SELECT d.datname AS name, CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') THEN pg_catalog.pg_database_size(d.datname) ELSE 0 END AS size_bytes FROM pg_catalog.pg_database d where datname not in ('template0', 'template1', 'postgres')" + # metrics: + # - name: + # usage: "LABEL" + # description: "Name of the database" + # - size_bytes: + # usage: "GAUGE" + # description: "Size of the database in bytes" + # + ## An array to add extra env vars to configure postgres-exporter + ## see: https://github.com/wrouesnel/postgres_exporter#environment-variables + ## For example: + # extraEnvVars: + # - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS + # value: "true" + extraEnvVars: {} + + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + enabled: false + runAsUser: 1001 + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## Configure extra options for liveness and readiness probes + ## + livenessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +## Array with extra yaml to deploy with the chart. Evaluated as a template +## +extraDeploy: [] diff --git a/sample-cnfs/sample_whitelisted_privileged_cnf/cnf-conformance.yml b/sample-cnfs/sample_whitelisted_privileged_cnf/cnf-conformance.yml index 77e8733dc..42acc60c5 100644 --- a/sample-cnfs/sample_whitelisted_privileged_cnf/cnf-conformance.yml +++ b/sample-cnfs/sample_whitelisted_privileged_cnf/cnf-conformance.yml @@ -7,6 +7,8 @@ deployment_name: privileged-coredns-coredns deployment_label: k8s-app service_name: privileged-coredns-coredns application_deployment_names: [privileged-coredns-coredns] -helm_chart: stable/coredns helm_chart_container_name: privileged-coredns-coredns -white_list_helm_chart_container_names: [coredns] +allowlist_helm_chart_container_names: [coredns] +container_names: + - name: coredns + rolling_update_test_tag: "1.8.0" diff --git a/scoring_config/points_v1.yml b/scoring_config/points_v1.yml index 2804033f6..dfb1a0159 100644 --- a/scoring_config/points_v1.yml +++ b/scoring_config/points_v1.yml @@ -2,7 +2,14 @@ - name: default_scoring tags: pass: 5 - fail: -1 + fail: -1 + skipped: 0 + +- name: reasonable_image_size + tags: workload, microservice, dynamic +- name: reasonable_startup_time + tags: workload, microservice, dynamic + - name: cni_spec tags: compatibility, dynamic - name: api_snoop_alpha @@ -12,67 +19,101 @@ - name: api_snoop_general_apis tags: compatibility, dynamic -- name: reset_cnf - tags: statelessness, dynamic, configuration_lifecycle -- name: check_reaped - tags: statelessness, dynamic, configuration_lifecycle +#- name: reset_cnf +# tags: workload, statelessness, dynamic, configuration_lifecycle +#- name: check_reaped +# tags: workload, statelessness, dynamic, configuration_lifecycle +- name: volume_hostpath_not_found + tags: workload, statelessness, dynamic +- name: no_local_volume_configuration + tags: workload, statelessness, dynamic - name: privileged - tags: security, dynamic + tags: workload, security, dynamic required: true -- name: shells - tags: security, dynamic -- name: protected_access - tags: security, dynamic +#- name: shells +# tags: workload, security, dynamic +#- name: protected_access +# tags: workload, security, dynamic - name: increase_capacity - tags: scalability, dynamic + tags: workload, scalability, dynamic pass: 10 fail: -5 - name: decrease_capacity - tags: scalability, dynamic + tags: workload, scalability, dynamic pass: 10 fail: -5 -- name: small_autoscaling - tags: scalability, dynamic -- name: large_autoscaling - tags: scalability, dynamic -- name: network_chaos - tags: scalability, dynamic -- name: external_retry - tags: scalability, dynamic +#- name: small_autoscaling +# tags: workload, scalability, dynamic +#- name: large_autoscaling +# tags: workload, scalability, dynamic +#- name: external_retry +# tags: workload, scalability, dynamic -- name: versioned_helm_chart - tags: configuration_lifecycle, dynamic +#- name: versioned_helm_chart +# tags: workload, configuration_lifecycle, dynamic - name: ip_addresses - tags: configuration_lifecycle, static + pass: 0 + fail: -1 + tags: workload, configuration_lifecycle, static - name: liveness - tags: configuration_lifecycle, dynamic + tags: workload, configuration_lifecycle, dynamic - name: readiness - tags: configuration_lifecycle, dynamic + tags: workload, configuration_lifecycle, dynamic - name: no_volume_with_configuration - tags: configuration_lifecycle, dynamic + tags: workload, configuration_lifecycle, dynamic - name: rolling_update - tags: configuration_lifecycle, dynamic, installability + tags: workload, configuration_lifecycle, dynamic +- name: rolling_downgrade + tags: workload, configuration_lifecycle, dynamic +- name: rolling_version_change + tags: workload, configuration_lifecycle, dynamic +- name: rollback + tags: workload, configuration_lifecycle, dynamic +- name: nodeport_not_used + tags: workload, configuration_lifecycle, dynamic +- name: hardcoded_ip_addresses_in_k8s_runtime_configuration + tags: workload, configuration_lifecycle, dynamic +- name: secrets_used + tags: workload, configuration_lifecycle, dynamic +- name: immutable_configmap + tags: workload, configuration_lifecycle, dynamic -- name: fluentd_traffic - tags: observability, dynamic -- name: jaeger_traffic - tags: observability, dynamic -- name: prometheus_traffic - tags: observability, dynamic -- name: opentelemetry_compatible - tags: observability, dynamic -- name: openmetric_compatible - tags: observability, dynamic +#- name: fluentd_traffic +# tags: workload, observability, dynamic +#- name: jaeger_traffic +# tags: workload, observability, dynamic +#- name: prometheus_traffic +# tags: workload, observability, dynamic +#- name: opentelemetry_compatible +# tags: workload, observability, dynamic +#- name: openmetric_compatible +# tags: workload, observability, dynamic +- name: helm_deploy + tags: workload, installability, dynamic - name: install_script_helm - tags: installability, static + tags: workload, installability, static - name: helm_chart_valid - tags: installability, dynamic + tags: workload, installability, dynamic +- name: helm_chart_published + tags: workload, installability, dynamic -- name: hardware_affinity - tags: hardware, dynamic +- name: chaos_network_loss + tags: workload, resilience, dynamic +- name: pod_network_latency + tags: workload, resilience, dynamic +- name: chaos_cpu_hog + tags: workload, resilience, dynamic +- name: chaos_container_kill + tags: workload, resilience, dynamic +- name: disk_fill + tags: scalability, dynamic, workload + + +- name: hardware_and_scheduling + tags: workload, hardware, dynamic - name: static_accessing_hardware tags: hardware, static - name: dynamic_accessing_hardware @@ -84,3 +125,18 @@ - name: k8s_conformance tags: platform, dynamic + +- name: kube_state_metrics + tags: platform, platform:observability, dynamic +- name: node_exporter + tags: platform, platform:observability, dynamic +- name: prometheus_adapter + tags: platform, platform:observability, dynamic +- name: metrics_server + tags: platform, platform:observability, dynamic + +- name: worker_reboot_recovery + tags: platform, platform:resilience, dynamic + +- name: oci_compliant + tags: platform, platform:hardware_and_scheduling, dynamic diff --git a/spec/cnf_conformance_all/cnf_conformance_config_lifecycle_spec.cr b/spec/cnf_conformance_all/cnf_conformance_config_lifecycle_spec.cr new file mode 100644 index 000000000..9a9198d13 --- /dev/null +++ b/spec/cnf_conformance_all/cnf_conformance_config_lifecycle_spec.cr @@ -0,0 +1,28 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe CnfConformance do + before_all do + `./cnf-conformance setup` + $?.success?.should be_true + end + + after_all do + `./cnf-conformance samples_cleanup` + $?.success?.should be_true + end + + it "'conformance all' should run the configuration lifecycle tests", tags: ["conformance-config-lifecycle"] do + `./cnf-conformance samples_cleanup` + response_s = `./cnf-conformance all ~reasonable_startup_time ~reasonable_image_size ~disk_fill ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~volume_hostpath_not_found ~privileged ~increase_capacity ~decrease_capacity ~install_script_helm ~helm_chart_valid ~helm_chart_published "cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml" verbose` + LOGGING.info response_s + (/PASSED: Helm readiness probe found/ =~ response_s).should_not be_nil + (/PASSED: Helm liveness probe/ =~ response_s).should_not be_nil + (/Final workload score:/ =~ response_s).should_not be_nil + (/Final score:/ =~ response_s).should_not be_nil + (CNFManager::Points.all_result_test_names(CNFManager::Points.final_cnf_results_yml).sort).should eq(["ip_addresses", "liveness", "readiness", "rolling_update", "rolling_downgrade", "rolling_version_change", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "rollback", "secrets_used", "immutable_configmap"].sort) + (/^.*\.cr:[0-9].*/ =~ response_s).should be_nil + $?.success?.should be_true + end +end diff --git a/spec/cnf_conformance_all/cnf_conformance_container_chaos_spec.cr b/spec/cnf_conformance_all/cnf_conformance_container_chaos_spec.cr new file mode 100644 index 000000000..c8ef2c89e --- /dev/null +++ b/spec/cnf_conformance_all/cnf_conformance_container_chaos_spec.cr @@ -0,0 +1,28 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe "CNF Conformance all Container Chaos" do + # before_all do + # `./cnf-conformance setup` + # $?.success?.should be_true + # end + + # after_all do + # `./cnf-conformance samples_cleanup` + # $?.success?.should be_true + # end + + # it "'all ~platform ~compatibilty ~statelessness ~security ~scalability ~configuration_lifecycle ~observability ~installability ~hardware_and_scheduling ~microservice ~chaos_network_loss' should run the chaos tests" do + # `./cnf-conformance samples_cleanup` + # response_s = `./cnf-conformance all ~platform ~compatibilty ~statelessness ~security ~scalability ~configuration_lifecycle ~observability ~installability ~hardware_and_scheduling ~microservice ~chaos_network_loss cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false verbose` + # LOGGING.info response_s + # (/Final workload score:/ =~ response_s).should_not be_nil + # (/Final score:/ =~ response_s).should_not be_nil + # (CNFManager::Points.all_result_test_names(CNFManager.final_cnf_results_yml)).should eq([ "chaos_cpu_hog", "chaos_container_kill"]) + # $?.success?.should be_true + # ensure + # LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false ` + # end + +end diff --git a/spec/cnf_conformance_all/cnf_conformance_microservice_spec.cr b/spec/cnf_conformance_all/cnf_conformance_microservice_spec.cr new file mode 100644 index 000000000..b3924ae08 --- /dev/null +++ b/spec/cnf_conformance_all/cnf_conformance_microservice_spec.cr @@ -0,0 +1,26 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe CnfConformance do + before_all do + `./cnf-conformance setup` + $?.success?.should be_true + end + + after_all do + `./cnf-conformance samples_cleanup` + $?.success?.should be_true + end + + it "'conformance all' should run all the microservice tests", tags: ["conformance-microservice"] do + `./cnf-conformance samples_cleanup` + response_s = `./cnf-conformance all ~disk_fill ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~volume_hostpath_not_found ~privileged ~increase_capacity ~decrease_capacity ~ip_addresses ~liveness ~readiness ~rolling_update ~rolling_downgrade ~rolling_version_change ~nodeport_not_used ~hardcoded_ip_addresses_in_k8s_runtime_configuration ~install_script_helm ~helm_chart_valid ~helm_chart_published ~rollback ~secrets_used ~immutable_configmap "cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml" verbose` + LOGGING.info response_s + (/Final workload score:/ =~ response_s).should_not be_nil + (/Final score:/ =~ response_s).should_not be_nil + (CNFManager::Points.all_result_test_names(CNFManager::Points.final_cnf_results_yml).sort).should eq(["reasonable_startup_time", "reasonable_image_size"].sort) + (/^.*\.cr:[0-9].*/ =~ response_s).should be_nil + $?.success?.should be_true + end +end diff --git a/spec/cnf_conformance_all/cnf_conformance_network_chaos_spec.cr b/spec/cnf_conformance_all/cnf_conformance_network_chaos_spec.cr new file mode 100644 index 000000000..062e4a269 --- /dev/null +++ b/spec/cnf_conformance_all/cnf_conformance_network_chaos_spec.cr @@ -0,0 +1,30 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe "CNF Conformance all Network Chaos" do + # before_all do + # `./cnf-conformance setup` + # $?.success?.should be_true + # end + + # after_all do + # `./cnf-conformance samples_cleanup` + # $?.success?.should be_true + # end + + # it "'all' should run the whole test suite" do + # `./cnf-conformance samples_cleanup` + + # response_s = `./cnf-conformance all ~platform ~compatibilty ~statelessness ~security ~scalability ~configuration_lifecycle ~observability ~installability ~hardware_and_scheduling ~microservice ~chaos_cpu_hog ~chaos_container_kill cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false verbose` + # response_s = `./cnf-conformance all ~platform ~compatibilty ~statelessness ~security ~scalability ~configuration_lifecycle ~observability ~installability ~hardware_and_scheduling ~microservice ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false verbose` + # LOGGING.info response_s + # (/Final workload score:/ =~ response_s).should_not be_nil + # (/Final score:/ =~ response_s).should_not be_nil + # (CNFManager::Points.all_result_test_names(CNFManager.final_cnf_results_yml)).should eq([ "chaos_network_loss"]) + # $?.success?.should be_true + # ensure + # LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false ` + + # end +end diff --git a/spec/cnf_conformance_all/cnf_conformance_spec.cr b/spec/cnf_conformance_all/cnf_conformance_spec.cr new file mode 100644 index 000000000..2379397dc --- /dev/null +++ b/spec/cnf_conformance_all/cnf_conformance_spec.cr @@ -0,0 +1,33 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe CnfConformance do + before_all do + `./cnf-conformance setup` + $?.success?.should be_true + end + + after_all do + `./cnf-conformance samples_cleanup` + $?.success?.should be_true + end + + it "'all' should run the workloads test suite", tags: ["conformance-all"] do + `./cnf-conformance samples_cleanup` + # the workload resilience tests are run in the chaos specs + # the ommisions (i.e. ~resilience) are done for performance reasons for the spec suite + # response_s = `./cnf-conformance all ~platform ~resilience cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose` + response_s = `./cnf-conformance all ~disk_fill ~pod_network_latency ~chaos_network_loss ~chaos_cpu_hog ~chaos_container_kill ~platform ~ip_addresses ~liveness ~readiness ~rolling_update ~rolling_downgrade ~rolling_version_change ~nodeport_not_used ~hardcoded_ip_addresses_in_k8s_runtime_configuration ~rollback ~secrets_used ~immutable_configmap ~reasonable_startup_time ~reasonable_image_size "cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml" verbose` + LOGGING.info response_s + (/Lint Passed/ =~ response_s).should_not be_nil + (/PASSED: Replicas increased to 3/ =~ response_s).should_not be_nil + (/PASSED: Replicas decreased to 1/ =~ response_s).should_not be_nil + (/PASSED: Published Helm Chart Found/ =~ response_s).should_not be_nil + (/Final workload score:/ =~ response_s).should_not be_nil + (/Final score:/ =~ response_s).should_not be_nil + (CNFManager::Points.all_result_test_names(CNFManager::Points.final_cnf_results_yml).sort).should eq(["volume_hostpath_not_found", "privileged", "increase_capacity", "decrease_capacity", "install_script_helm", "helm_chart_valid", "helm_chart_published"].sort) + (/^.*\.cr:[0-9].*/ =~ response_s).should be_nil + $?.success?.should be_true + end +end diff --git a/spec/cnf_conformance_spec.cr b/spec/cnf_conformance_spec.cr deleted file mode 100644 index ac36912d3..000000000 --- a/spec/cnf_conformance_spec.cr +++ /dev/null @@ -1,63 +0,0 @@ -require "./spec_helper" -require "../src/tasks/utils/utils.cr" -require "colorize" - -describe CnfConformance do - before_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance samples_cleanup` - $?.success?.should be_true - `./cnf-conformance setup` - $?.success?.should be_true - # `./cnf-conformance sample_coredns_with_wait_setup` - # $?.success?.should be_true - end - - after_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance samples_cleanup` - $?.success?.should be_true - end - - it "'all' should run the whole test suite", tags: "happy-path" do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - # Test the binary - # Build should already be present - # build_s = `crystal build src/cnf-conformance.cr` - # $?.success?.should be_true - # LOGGING.debug build_s - `./cnf-conformance samples_cleanup` - response_s = `./cnf-conformance all cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose` - LOGGING.info response_s - (/PASSED: Helm readiness probe found/ =~ response_s).should_not be_nil - (/PASSED: Helm liveness probe/ =~ response_s).should_not be_nil - (/Lint Passed/ =~ response_s).should_not be_nil - (/PASSED: Replicas increased to 3/ =~ response_s).should_not be_nil - (/PASSED: Replicas decreased to 1/ =~ response_s).should_not be_nil - (/PASSED: Published Helm Chart Found/ =~ response_s).should_not be_nil - (/Final workload score:/ =~ response_s).should_not be_nil - (/Final platform score:/ =~ response_s).should_not be_nil - (/Final score:/ =~ response_s).should_not be_nil - (all_result_test_names(CNFManager.final_cnf_results_yml)).should eq(["volume_hostpath_not_found", "privileged", "increase_capacity", "decrease_capacity", "ip_addresses", "liveness", "readiness", "rolling_update", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "install_script_helm", "helm_chart_valid", "helm_chart_published","helm_deploy", "reasonable_image_size", "reasonable_startup_time", "chaos_network_loss", "chaos_cpu_hog", "chaos_container_kill", "k8s_conformance", "oci_compliant"]) - $?.success?.should be_true - end - - it "'scalability' should run all of the scalability tests", tags: "happy-path" do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance samples_cleanup` - response_s = `./cnf-conformance setup` - LOGGING.info response_s - `./cnf-conformance sample_coredns_with_wait_setup` - $?.success?.should be_true - response_s = `./cnf-conformance scalability` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: Replicas increased to 3/ =~ response_s).should_not be_nil - (/PASSED: Replicas decreased to 1/ =~ response_s).should_not be_nil - end - -end diff --git a/spec/configuration_lifecycle_spec.cr b/spec/configuration_lifecycle_spec.cr deleted file mode 100644 index b77265288..000000000 --- a/spec/configuration_lifecycle_spec.cr +++ /dev/null @@ -1,155 +0,0 @@ -require "./spec_helper" -require "colorize" - -describe CnfConformance do - before_all do - LOGGING.debug `pwd` - LOGGING.debug `echo $KUBECONFIG` - - `./cnf-conformance samples_cleanup` - $?.success?.should be_true - `./cnf-conformance configuration_file_setup` - - # `./cnf-conformance setup` - # $?.success?.should be_true - end - - it "'ip_addresses' should pass when no uncommented ip addresses are found in helm chart source", tags: "happy-path" do - begin - `./cnf-conformance sample_coredns_source_setup verbose` - $?.success?.should be_true - response_s = `./cnf-conformance ip_addresses verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: No IP addresses found/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance sample_coredns_source_cleanup verbose` - end - end - it "'liveness' should pass when livenessProbe is set", tags: ["liveness", "happy-path"] do - begin - `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance liveness verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: Helm liveness probe/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cleanup_sample_coredns verbose` - end - end - it "'liveness' should fail when livenessProbe is not set", tags: "liveness" do - begin - `./cnf-conformance sample_coredns_bad_liveness` - $?.success?.should be_true - response_s = `./cnf-conformance liveness verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: No livenessProbe found/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance sample_coredns_bad_liveness_cleanup` - end - end - it "'readiness' should pass when readinessProbe is set", tags: ["readiness","happy-path"] do - begin - `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance readiness verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: Helm readiness probe/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cleanup_sample_coredns verbose` - end - end - it "'readiness' should fail when readinessProbe is not set", tags: "readiness" do - begin - `./cnf-conformance sample_coredns_bad_liveness` - $?.success?.should be_true - response_s = `./cnf-conformance readiness verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: No readinessProbe found/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance sample_coredns_bad_liveness_cleanup` - end - end - it "'rolling_update' should pass when valid version is given", tags: ["rolling_update", "happy-path"] do - begin - LOGGING.info `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance rolling_update verbose` - LOGGING.info response_s - $?.success?.should be_true - (/Rolling Update Passed/ =~ response_s).should_not be_nil - ensure - # `./cnf-conformance cleanup_sample_coredns` - end - end - it "'rolling_update' should fail when invalid version is given", tags: "rolling_update" do - begin - LOGGING.info `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance rolling_update verbose version_tag=this_is_not_real_version` - LOGGING.info response_s - $?.success?.should be_true - (/Rolling Update Failed/ =~ response_s).should_not be_nil - ensure - # `./cnf-conformance cleanup_sample_coredns` - end - end - - it "'nodeport_not_used' should fail when a node port is being used", tags: "nodeport_not_used" do - begin - `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_nodeport deploy_with_chart=false` - $?.success?.should be_true - response_s = `./cnf-conformance nodeport_not_used verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: NodePort is being used/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_nodeport deploy_with_chart=false` - end - end - it "'nodeport_not_used' should pass when a node port is not being used", tags: "nodeport_not_used" do - begin - `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance nodeport_not_used verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: NodePort is not used/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cleanup_sample_coredns` - end - end - - - - - it "'hardcoded_ip_addresses_in_k8s_runtime_configuration' should fail when a hardcoded ip is found in the K8s configuration", tags: "hardcoded_ip_addresses_in_k8s_runtime_configuration" do - begin - `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_coredns_hardcoded_ips deploy_with_chart=false` - $?.success?.should be_true - response_s = `LOG_LEVEL=info ./cnf-conformance hardcoded_ip_addresses_in_k8s_runtime_configuration verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: Hard-coded IP addresses found in the runtime K8s configuration/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_coredns_hardcoded_ips deploy_with_chart=false` - end - end - it "'hardcoded_ip_addresses_in_k8s_runtime_configuration' should pass when no ip addresses are found in the K8s configuration", tags: "hardcoded_ip_addresses_in_k8s_runtime_configuration" do - begin - `./cnf-conformance sample_coredns` - $?.success?.should be_true - response_s = `./cnf-conformance hardcoded_ip_addresses_in_k8s_runtime_configuration verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: No hard-coded IP addresses found in the runtime K8s configuration/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cleanup_sample_coredns` - end - end - -end diff --git a/spec/curl_install_spec.cr b/spec/curl_install_spec.cr index cdd44d5ee..1c00c378f 100644 --- a/spec/curl_install_spec.cr +++ b/spec/curl_install_spec.cr @@ -16,12 +16,12 @@ describe "CurlInstall" do raise "crystal build failed in spec_helper" end end - it "'source curl_install.sh' should download a cnf-conformance binary" do + it "'source curl_install.sh' should download a cnf-conformance binary", tags: ["curl"] do response_s = `/bin/bash -c "source ./curl_install.sh"` LOGGING.info response_s (/cnf-conformance/ =~ response_s).should_not be_nil end - it "'curl_install.sh' should download a cnf-conformance binary" do + it "'curl_install.sh' should download a cnf-conformance binary", tags: ["curl"] do response_s = `./curl_install.sh` LOGGING.info response_s (/To use cnf-conformance please restart you terminal session to load the new 'path'/ =~ response_s).should_not be_nil diff --git a/spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml b/spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml index 458ad60ab..a1c125faa 100644 --- a/spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml +++ b/spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml @@ -1,16 +1,19 @@ --- +invalid_key: # invalid because missing helm_chart key -git_clone_url: -install_script: -release_name: coredns -deployment_name: coredns-coredns -application_deployment_names: [coredns-coredns] -helm_repository: - name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com - test_on_helm_repo: -helm_chart: stable/coredns -helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] -test_at_root: +# git_clone_url: +# install_script: +# release_name: coredns +# deployment_name: coredns-coredns +# application_deployment_names: [coredns-coredns] +# helm_repository: +# name: stable +# repo_url: https://cncf.gitlab.io/stable +# test_on_helm_repo: +# # helm_chart: stable/coredns +# helm_chart_container_name: coredns +# container_names: +# - name: coredns +# rolling_update_test_tag: 1.8.0 +# # allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +# test_at_root: diff --git a/spec/fixtures/cnf-conformance-not-exclusive.yml b/spec/fixtures/cnf-conformance-not-exclusive.yml new file mode 100644 index 000000000..010fc08db --- /dev/null +++ b/spec/fixtures/cnf-conformance-not-exclusive.yml @@ -0,0 +1,27 @@ +--- +helm_directory: +helm_chart: stable/coredns +git_clone_url: +install_script: +release_name: coredns +deployment_name: coredns-coredns +application_deployment_names: +- coredns-coredns +helm_repository: + name: stable + repo_url: https://cncf.gitlab.io/stable +helm_chart_container_name: coredns +container_names: +- name: coredns + rolling_update_test_tag: 1.8.0 + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: +- falco +- node-cache +- nginx +- coredns +- calico-node +- kube-proxy +- nginx-proxy diff --git a/spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml b/spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml index 9b4ed3c0c..c72425674 100644 --- a/spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml +++ b/spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml @@ -9,10 +9,12 @@ deployment_label: k8s-app application_deployment_names: [coredns-coredns] helm_repository: name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + repo_url: https://cncf.gitlab.io/stable test_on_helm_repo: helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: + - name: coredns + rolling_update_test_tag: 1.8.0 +allowlist_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] test_at_root: diff --git a/spec/fixtures/cnf-conformance.yml b/spec/fixtures/cnf-conformance.yml index 4f2df5fc8..da967f165 100644 --- a/spec/fixtures/cnf-conformance.yml +++ b/spec/fixtures/cnf-conformance.yml @@ -1,15 +1,26 @@ --- -helm_directory: cnfs/coredns/helm_chart/coredns -# helm_directory: helm_chart git_clone_url: install_script: release_name: coredns -deployment_name: coredns-coredns -application_deployment_names: [coredns-coredns] +deployment_name: coredns-coredns +application_deployment_names: +- coredns-coredns helm_repository: - name: stable - repo_url: https://kubernetes-charts.storage.googleapis.com + name: stable + repo_url: https://cncf.gitlab.io/stable helm_chart: stable/coredns helm_chart_container_name: coredns -rolling_update_tag: 1.6.7 -white_list_helm_chart_container_names: [falco, node-cache, nginx, coredns, calico-node, kube-proxy, nginx-proxy] +container_names: +- name: coredns + rolling_update_test_tag: 1.8.0 + rolling_downgrade_test_tag: 1.6.7 + rolling_version_change_test_tag: latest + rollback_from_tag: latest +allowlist_helm_chart_container_names: +- falco +- node-cache +- nginx +- coredns +- calico-node +- kube-proxy +- nginx-proxy diff --git a/spec/microservice_spec.cr b/spec/microservice_spec.cr deleted file mode 100644 index 7260037e3..000000000 --- a/spec/microservice_spec.cr +++ /dev/null @@ -1,74 +0,0 @@ -require "./spec_helper" -require "colorize" -require "../src/tasks/utils/utils.cr" -require "../src/tasks/utils/system_information/helm.cr" -require "file_utils" -require "sam" - -describe "Microservice" do - before_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance samples_cleanup force=true` - $?.success?.should be_true - `./cnf-conformance configuration_file_setup` - # `./cnf-conformance setup` - # $?.success?.should be_true - end - - it "'reasonable_startup_time' should pass if the cnf has a reasonable startup time(helm_directory)", tags: ["reasonable_startup_time", "happy-path"] do - begin - response_s = `./cnf-conformance reasonable_startup_time cnf-config=sample-cnfs/sample_coredns/cnf-conformance.yml` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: CNF had a reasonable startup time/ =~ response_s).should_not be_nil - ensure - `kubectl delete -f sample-cnfs/sample_coredns/reasonable_startup_orig.yml` - `./cnf-conformance samples_cleanup force=true` - $?.success?.should be_true - end - end - - it "'reasonable_startup_time' should fail if the cnf doesn't has a reasonable startup time(helm_directory)", tags: "reasonable_startup_time" do - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml force=true` - `kubectl delete -f sample-cnfs/sample_envoy_slow_startup/reasonable_startup_orig.yml` - begin - response_s = `./cnf-conformance reasonable_startup_time cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: CNF had a startup time of/ =~ response_s).should_not be_nil - ensure - `kubectl delete -f sample-cnfs/sample_envoy_slow_startup/reasonable_startup_orig.yml` - $?.success?.should be_true - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml force=true` - $?.success?.should be_true - end - end - - it "'reasonable_image_size' should pass if image is smaller than 5gb", tags: ["reasonable_image_size","happy-path"] do - begin - `./cnf-conformance cleanup force=true` - `./cnf-conformance sample_coredns_setup` - response_s = `./cnf-conformance reasonable_image_size verbose` - LOGGING.info response_s - $?.success?.should be_true - (/Image size is good/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance sample_coredns_cleanup force=true` - end - end - - it "'reasonable_image_size' should fail if image is larger than 5gb", tags: "reasonable_image_size" do - begin - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample-large-cnf force=true` - `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-large-cnf deploy_with_chart=false` - response_s = `./cnf-conformance reasonable_image_size verbose` - LOGGING.info response_s - $?.success?.should be_true - (/Image size too large/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample-large-cnf force=true` - end - end - -end diff --git a/spec/platform/cluster_api_spec.cr b/spec/platform/cluster_api_spec.cr index ded634208..93f9c4fd0 100644 --- a/spec/platform/cluster_api_spec.cr +++ b/spec/platform/cluster_api_spec.cr @@ -11,71 +11,26 @@ describe "Cluster API" do after_all do # cleanup cluster api stuff - current_dir = FileUtils.pwd - cluster_api_dir = "#{current_dir}/#{TOOLS_DIR}/cluster-api" - `kubectl delete -f #{cluster_api_dir}/capd.yaml` - `clusterctl delete --all --include-crd --include-namespace --config #{cluster_api_dir}/clusterctl.yaml` - `rm -rf #{current_dir}/#{TOOLS_DIR}/cluster-api` + # `./cnf-conformance cluster_api_cleanup` end - it "'clusterapi_enabled' test works" do + it "'clusterapi_enabled' should pass if cluster api is installed", tags: ["cluster-api"] do begin - # `./tools/cluster-api-dev-setup/spec_mock_cluster_api_spec_commands.sh` + LOGGING.info `./cnf-conformance cluster_api_setup` current_dir = FileUtils.pwd - cluster_api_dir = "#{current_dir}/#{TOOLS_DIR}/cluster-api"; - unless Dir.exists?(cluster_api_dir) - `git clone https://github.com/kubernetes-sigs/cluster-api --depth 1 --branch v0.3.10 "#{cluster_api_dir}"` - end - FileUtils.cd(cluster_api_dir) - File.write("clusterctl-settings.json", -<<-EOF -{"providers": ["cluster-api","bootstrap-kubeadm","control-plane-kubeadm", "infrastructure-docker"]} -EOF - ) - `./cmd/clusterctl/hack/create-local-repository.py` - File.write("clusterctl.yaml", -<<-EOF -providers: - - name: docker - url: #{Path["~"].expand(home: true)}/.cluster-api/dev-repository/infrastructure-docker/v0.3.8/infrastructure-components.yaml - type: InfrastructureProvider -EOF - ) - - - test = `clusterctl init --core cluster-api:v0.3.8 --bootstrap kubeadm:v0.3.8 --control-plane kubeadm:v0.3.8 --infrastructure docker:v0.3.8 --config #{FileUtils.pwd}/clusterctl.yaml` - puts test - - $?.success?.should be_true - - - ## TODO: wait here for crds to be created if needed -create_capd_response =` -CNI_RESOURCES="$(cat test/e2e/data/cni/kindnet/kindnet.yaml)" \ -DOCKER_POD_CIDRS="192.168.0.0/16" \ -DOCKER_SERVICE_CIDRS="172.17.0.0/16" \ -DOCKER_SERVICE_DOMAIN="cluster.local" \ -clusterctl config cluster capd --kubernetes-version v1.17.5 \ ---from https://github.com/kubernetes-sigs/cluster-api/blob/v0.3.9/test/e2e/data/infrastructure-docker/cluster-template.yaml \ ---target-namespace default \ ---control-plane-machine-count=1 \ ---worker-machine-count=2 -` - - LOGGING.info create_capd_response - - File.write("capd.yaml", create_capd_response) - - CNFManager.wait_for_install_by_apply("capd.yaml") - - LOGGING.info `kubectl apply -f capd.yaml` - - ensure - FileUtils.cd("#{current_dir}") - response_s = `./cnf-conformance clusterapi_enabled poc` - LOGGING.info response_s - (/Cluster API is enabled/ =~ response_s).should_not be_nil + FileUtils.cd("#{current_dir}") + response_s = `./cnf-conformance clusterapi_enabled poc` + LOGGING.info response_s + (/Cluster API is enabled/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cluster_api_cleanup` end end + + it "'clusterapi_enabled' should fail if cluster api is not installed", tags: ["cluster-api"] do + response_s = `./cnf-conformance clusterapi_enabled poc` + LOGGING.info response_s + (/Cluster API NOT enabled/ =~ response_s).should_not be_nil + end end diff --git a/spec/platform/hardware_and_scheduler_spec.cr b/spec/platform/hardware_and_scheduler_spec.cr index 470fefd98..dcd14fa92 100644 --- a/spec/platform/hardware_and_scheduler_spec.cr +++ b/spec/platform/hardware_and_scheduler_spec.cr @@ -12,7 +12,7 @@ describe "Platform" do $?.success?.should be_true end - it "'oci_compliant' should pass if all runtimes are oci_compliant", tags: "platform:oci_compliant" do + it "'oci_compliant' should pass if all runtimes are oci_compliant", tags: ["platform:oci_compliant"] do response_s = `./cnf-conformance platform:oci_compliant` LOGGING.info response_s (/(PASSED){1}.*(which are OCI compliant runtimes){1}/ =~ response_s).should_not be_nil diff --git a/spec/platform/observability_spec.cr b/spec/platform/observability_spec.cr index bb12b2275..ab75b045a 100644 --- a/spec/platform/observability_spec.cr +++ b/spec/platform/observability_spec.cr @@ -1,6 +1,7 @@ require "./../spec_helper" require "colorize" require "./../../src/tasks/utils/utils.cr" +require "./../../src/tasks/utils/kubectl_client.cr" describe "Observability" do before_all do @@ -13,7 +14,7 @@ describe "Observability" do LOGGING.info "Installing kube_state_metrics" resp = `#{helm} install kube-state-metrics stable/kube-state-metrics` LOGGING.info resp - CNFManager.wait_for_install("kube-state-metrics") + KubectlClient::Get.wait_for_install("kube-state-metrics") LOGGING.info "Installing prometheus-node-exporter" resp = `#{helm} install node-exporter stable/prometheus-node-exporter` @@ -22,12 +23,12 @@ describe "Observability" do LOGGING.info "Installing prometheus-adapter" resp = `#{helm} install prometheus-adapter stable/prometheus-adapter` LOGGING.info resp - CNFManager.wait_for_install("prometheus-adapter") + KubectlClient::Get.wait_for_install("prometheus-adapter") LOGGING.info "Installing metrics_server" resp = `kubectl create -f spec/fixtures/metrics-server.yaml` LOGGING.info resp - CNFManager.wait_for_install(deployment_name: "metrics-server", namespace:"kube-system") + KubectlClient::Get.wait_for_install(deployment_name: "metrics-server", namespace:"kube-system") rescue ex LOGGING.error ex.message ex.backtrace.each do |x| @@ -56,17 +57,17 @@ describe "Observability" do $?.success?.should be_true end - it "'kube_state_metrics' should return some json", tags: "platform:kube_state_metrics" do + it "'kube_state_metrics' should return some json", tags: ["platform:kube_state_metrics"] do response_s = `./cnf-conformance platform:kube_state_metrics poc` LOGGING.info response_s (/(PASSED){1}.*(Your platform is using the){1}.*(release for kube state metrics){1}/ =~ response_s).should_not be_nil end - it "'node_exporter' should detect the named release of the installed node_exporter", tags: "platform:node_exporter" do + it "'node_exporter' should detect the named release of the installed node_exporter", tags: ["platform:node_exporter"] do pod_ready = "" pod_ready_timeout = 45 until (pod_ready == "true" || pod_ready_timeout == 0) - pod_ready = CNFManager.pod_status("node-exporter-prometheus").split(",")[2] + pod_ready = KubectlClient::Get.pod_status("node-exporter-prometheus").split(",")[2] puts "Pod Ready Status: #{pod_ready}" sleep 1 pod_ready_timeout = pod_ready_timeout - 1 @@ -76,13 +77,13 @@ describe "Observability" do (/(PASSED){1}.*(Your platform is using the){1}.*(release for the node exporter){1}/ =~ response_s).should_not be_nil end - it "'prometheus_adapter' should detect the named release of the installed prometheus_adapter", tags: "platform:prometheus_adapter" do + it "'prometheus_adapter' should detect the named release of the installed prometheus_adapter", tags: ["platform:prometheus_adapter"] do response_s = `./cnf-conformance platform:prometheus_adapter poc` LOGGING.info response_s (/(PASSED){1}.*(Your platform is using the){1}.*(release for the prometheus adapter){1}/ =~ response_s).should_not be_nil end - it "'metrics_server' should detect the named release of the installed metrics_server", tags: "platform:metrics_server" do + it "'metrics_server' should detect the named release of the installed metrics_server", tags: ["platform:metrics_server"] do response_s = `./cnf-conformance platform:metrics_server poc` LOGGING.info response_s (/(PASSED){1}.*(Your platform is using the){1}.*(release for the metrics server){1}/ =~ response_s).should_not be_nil diff --git a/spec/platform/platform_spec.cr b/spec/platform/platform_spec.cr index b819e2958..a0ed6a155 100644 --- a/spec/platform/platform_spec.cr +++ b/spec/platform/platform_spec.cr @@ -7,19 +7,19 @@ describe "Platform" do # LOGGING.debug `echo $KUBECONFIG` `./cnf-conformance samples_cleanup` $?.success?.should be_true - `./cnf-conformance setup` + LOGGING.info `./cnf-conformance setup` $?.success?.should be_true - # `./cnf-conformance sample_coredns_with_wait_setup` + # LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose` # $?.success?.should be_true end - it "'platform:*' should not error out when no cnf is installed" do + it "'platform:*' should not error out when no cnf is installed", tags: ["platform"] do response_s = `./cnf-conformance cleanup` response_s = `./cnf-conformance platform:oci_compliant` LOGGING.info response_s puts response_s (/No cnf_conformance.yml found/ =~ response_s).should be_nil end - it "'platform' should not run prerequisites that are prefixed with a ~" do + it "'platform' should not run prerequisites that are prefixed with a ~", tags: ["platform"] do response_s = `./cnf-conformance cleanup` # response_s = `./cnf-conformance platform` stdout = IO::Memory.new @@ -33,7 +33,7 @@ describe "Platform" do LOGGING.info "response #{response_s}" (/kind=namespace namespace=sonobuoy/ =~ (response_s + error)).should be_nil end - it "'k8s_conformance' should pass if the sonobuoy tests pass" do + it "'k8s_conformance' should pass if the sonobuoy tests pass", tags: ["platform"] do response_s = `./cnf-conformance k8s_conformance` LOGGING.info response_s (/PASSED: K8s conformance test has no failures/ =~ response_s).should_not be_nil diff --git a/spec/platform/resilience_spec.cr b/spec/platform/resilience_spec.cr index fc6d1fa14..7d00482ea 100644 --- a/spec/platform/resilience_spec.cr +++ b/spec/platform/resilience_spec.cr @@ -7,16 +7,16 @@ describe "Platform" do `./cnf-conformance setup` $?.success?.should be_true end - it "'worker_reboot_recovery' should pass if platform successfully recovers after reboot", tags: "platform:worker_reboot_recovery" do + it "'worker_reboot_recovery' should pass if platform successfully recovers after reboot", tags: ["platform:worker_reboot_recovery"] do if check_destructive - puts "Tests running in destructive mode".colorize(:red) + puts "Tests running in destructive mode".colorize(:red) response_s = `./cnf-conformance platform:worker_reboot_recovery destructive` LOGGING.info response_s (/(PASSED: Node came back online)/ =~ response_s).should_not be_nil else response_s = `./cnf-conformance platform:worker_reboot_recovery` LOGGING.info response_s - (/Skipped/ =~ response_s).should_not be_nil + (/SKIPPED/ =~ response_s).should_not be_nil end end end diff --git a/spec/prereqs_spec.cr b/spec/prereqs_spec.cr index 110a1e2b4..b5df26cd2 100644 --- a/spec/prereqs_spec.cr +++ b/spec/prereqs_spec.cr @@ -6,13 +6,13 @@ require "file_utils" require "sam" describe "Prereq" do - it "'prereq' should check the system for prerequisites", tags: "prereqs" do + it "'prereq' should check the system for prerequisites", tags: ["points"] do response_s = `./cnf-conformance prereqs verbose` LOGGING.info response_s $?.success?.should be_true (/helm found/ =~ response_s).should_not be_nil - (/wget found/ =~ response_s).should_not be_nil - (/curl found/ =~ response_s).should_not be_nil + # (/wget found/ =~ response_s).should_not be_nil + # (/curl found/ =~ response_s).should_not be_nil (/kubectl found/ =~ response_s).should_not be_nil (/git found/ =~ response_s).should_not be_nil end diff --git a/spec/resilience_spec.cr b/spec/resilience_spec.cr deleted file mode 100644 index aed517e5b..000000000 --- a/spec/resilience_spec.cr +++ /dev/null @@ -1,69 +0,0 @@ -require "./spec_helper" -require "colorize" -require "../src/tasks/utils/utils.cr" -require "../src/tasks/utils/system_information/helm.cr" -require "file_utils" -require "sam" - -describe "Resilience" do - before_all do - `./cnf-conformance configuration_file_setup` - $?.success?.should be_true - end - - it "'chaos_container_kill' A 'Good' CNF should recover when its container is killed", tags: ["chaos_container_kill"] do - begin - `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - response_s = `./cnf-conformance chaos_container_kill verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: Replicas available match desired count after container kill test/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - end - end - - it "'chaos_container_kill' A 'Bad' CNF should NOT recover when its container is killed", tags: ["chaos_container_kill"] do - begin - `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-fragile-state deploy_with_chart=false` - $?.success?.should be_true - response_s = `./cnf-conformance chaos_container_kill verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: Replicas did not return desired count after container kill test/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample-fragile-state deploy_with_chart=false` - $?.success?.should be_true - end - end - - it "'chaos_network_loss' A 'Good' CNF should not crash when network loss occurs", tags: ["chaos_network_loss"] do - begin - `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - response_s = `./cnf-conformance chaos_network_loss verbose` - LOGGING.info response_s - $?.success?.should be_true - (/PASSED: Replicas available match desired count after network chaos test/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - end - end - - it "'chaos_network_loss' A 'Bad' CNF should crash when network loss occurs", tags: ["chaos_network_loss"] do - begin - `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_network_loss deploy_with_chart=false` - $?.success?.should be_true - response_s = `./cnf-conformance chaos_network_loss verbose` - LOGGING.info response_s - $?.success?.should be_true - (/FAILURE: Replicas did not return desired count after network chaos test/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_network_loss deploy_with_chart=false` - $?.success?.should be_true - end - end -end diff --git a/spec/setup_spec.cr b/spec/setup_spec.cr index 972ad2ed7..9885f536e 100644 --- a/spec/setup_spec.cr +++ b/spec/setup_spec.cr @@ -16,14 +16,14 @@ describe "Setup" do $?.success?.should be_true end - it "'setup' should completely setup the cnf conformance environment before installing cnfs", tags: "happy-path" do + it "'setup' should completely setup the cnf conformance environment before installing cnfs", tags: ["setup"] do response_s = `./cnf-conformance setup` LOGGING.info response_s $?.success?.should be_true (/Setup complete/ =~ response_s).should_not be_nil end - it "'cnf_setup/cnf_cleanup' should install/cleanup a cnf with a cnf-conformance.yml", tags: "happy-path" do + it "'cnf_setup/cnf_cleanup' should install/cleanup a cnf with a cnf-conformance.yml", tags: ["setup"] do begin response_s = `./cnf-conformance cnf_setup cnf-config=example-cnfs/coredns/cnf-conformance.yml` LOGGING.info response_s @@ -37,7 +37,7 @@ describe "Setup" do (/Successfully cleaned up/ =~ response_s).should_not be_nil end end - it "'cnf_setup/cnf_cleanup' should work with cnf-conformance.yml that has no directory associated with it", tags: "happy-path" do + it "'cnf_setup/cnf_cleanup' should work with cnf-conformance.yml that has no directory associated with it", tags: ["setup"] do begin #TODO force cnfs/ to be deployment name and not the directory name response_s = `./cnf-conformance cnf_setup cnf-config=spec/fixtures/cnf-conformance.yml verbose` diff --git a/spec/statelessness_spec.cr b/spec/statelessness_spec.cr deleted file mode 100644 index e89553ae2..000000000 --- a/spec/statelessness_spec.cr +++ /dev/null @@ -1,38 +0,0 @@ -require "./spec_helper" -require "colorize" -require "../src/tasks/utils/utils.cr" -require "../src/tasks/utils/system_information/helm.cr" -require "file_utils" -require "sam" - -describe "Statelessness" do - before_all do - `./cnf-conformance configuration_file_setup` - end - - it "'volume_hostpath_not_found' should pass if the cnf doesn't have a hostPath volume", tags: ["volume_hostpath_not_found"] do - begin - `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - response_s = `./cnf-conformance volume_hostpath_not_found verbose` - LOGGING.info "Status: #{response_s}" - (/PASSED: hostPath volumes not found/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` - $?.success?.should be_true - end - end - - it "'volume_hostpath_not_found' should fail if the cnf has a hostPath volume", tags: ["volume_hostpath_not_found"] do - begin - `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-fragile-state/cnf-conformance.yml deploy_with_chart=false` - $?.success?.should be_true - response_s = `./cnf-conformance volume_hostpath_not_found verbose` - LOGGING.info "Status: #{response_s}" - (/FAILURE: hostPath volumes found/ =~ response_s).should_not be_nil - ensure - `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-fragile-state/cnf-conformance.yml deploy_with_chart=false` - $?.success?.should be_true - end - end -end diff --git a/spec/utils/cnf_manager_spec.cr b/spec/utils/cnf_manager_spec.cr index 2d2b4b3e4..596e7a760 100644 --- a/spec/utils/cnf_manager_spec.cr +++ b/spec/utils/cnf_manager_spec.cr @@ -1,127 +1,290 @@ require "../spec_helper" require "colorize" require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/kubectl_client.cr" require "file_utils" require "sam" describe "SampleUtils" do before_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` `./cnf-conformance helm_local_install` $?.success?.should be_true `./cnf-conformance cleanup` $?.success?.should be_true end - after_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance sample_coredns_setup` - $?.success?.should be_true - end + # after_all do + # LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose wait_count=0` + # $?.success?.should be_true + # end after_each do `./cnf-conformance cleanup` $?.success?.should be_true end - it "'CNFManager.wait_for_install' should wait for a cnf to be installed", tags: "happy-path" do - `./cnf-conformance sample_coredns_setup` + it "'cnf_setup' should pass with a minimal cnf-conformance.yml", tags: ["cnf-setup"] do + LOGGING.info `./cnf-conformance cnf_setup cnf-path=./sample-cnfs/sample-minimal-cnf/ wait_count=0` $?.success?.should be_true + ensure + `./cnf-conformance cnf_cleanup cnf-path=./sample-cnfs/sample-minimal-cnf/ force=true` + end - current_dir = FileUtils.pwd - LOGGING.info current_dir - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - LOGGING.info helm - helm_install = `#{helm} install coredns stable/coredns` - LOGGING.info helm_install - CNFManager.wait_for_install("coredns-coredns") - current_replicas = `kubectl get deployments coredns-coredns -o=jsonpath='{.status.readyReplicas}'` - (current_replicas.to_i > 0).should be_true + it "'points_yml' should parse and return the points yaml file", tags: ["points"] do + (CNFManager::Points.points_yml.find {|x| x["name"] =="liveness"}).should be_truthy end - it "'CNFManager.sample_setup' should set up a sample cnf", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup(config_file: "sample-cnfs/sample-generic-cnf", release_name: "coredns", deployment_name: "coredns-coredns", helm_chart: "stable/coredns", helm_directory: "helm_chart", git_clone_url: "https://github.com/coredns/coredns.git", wait_count: 0 ) + it "'task_points' should return the amount of points for a passing test", tags: ["points"] do + # default + (CNFManager::Points.task_points("liveness")).should eq(5) + # assigned + (CNFManager::Points.task_points("increase_capacity")).should eq(10) + end + + it "'task_points(, false)' should return the amount of points for a failing test", tags: ["points"] do + # default + (CNFManager::Points.task_points("liveness", false)).should eq(-1) + # assigned + (CNFManager::Points.task_points("increase_capacity", false)).should eq(-5) + end + + it "'task_points(, skipped)' should return the amount of points for a skipped test", tags: ["points"] do + # default + (CNFManager::Points.task_points("liveness", CNFManager::Points::Results::ResultStatus::Skipped)).should eq(0) + end + + it "'task_required' should return if the passed task is required", tags: ["tasks"] do + CNFManager::Points.clean_results_yml + (CNFManager::Points.task_required("privileged")).should be_true + end + + it "'failed_required_tasks' should return a list of failed required tasks", tags: ["tasks"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.failed_task("privileged", "FAILED: Privileged container found") + (CNFManager::Points.failed_required_tasks).should eq(["privileged"]) + end + + it "'upsert_task' insert task in the results file", tags: ["tasks"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + # LOGGING.debug yaml["items"].as_a.inspect + (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == CNFManager::Points.task_points("liveness")}).should be_truthy + end + + it "'upsert_task' should find and update an existing task in the file", tags: ["tasks"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + # LOGGING.debug yaml["items"].as_a.inspect + (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == CNFManager::Points.task_points("liveness")}).should be_truthy + (CNFManager::Points.total_points).should eq(5) + end + + it "'CNFManager::Points.total_points' should sum the total amount of points in the results", tags: ["points"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + (CNFManager::Points.total_points).should eq(5) + end + + it "'CNFManager::Points.tasks_by_tag' should return the tasks assigned to a tag", tags: ["points"] do + CNFManager::Points.clean_results_yml + (CNFManager::Points.tasks_by_tag("configuration_lifecycle")).should eq(["ip_addresses", "liveness", "readiness", "rolling_update", "rolling_downgrade", "rolling_version_change", "rollback", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "secrets_used", "immutable_configmap"]) + (CNFManager::Points.tasks_by_tag("does-not-exist")).should eq([] of YAML::Any) + end + + it "'CNFManager::Points.all_task_test_names' should return all tasks names", tags: ["points"] do + CNFManager::Points.clean_results_yml + (CNFManager::Points.all_task_test_names()).should eq(["reasonable_image_size", "reasonable_startup_time", "privileged", "increase_capacity", "decrease_capacity", "network_chaos", "pod_network_latency", "disk_fill", "ip_addresses", "liveness", "readiness", "rolling_update", "rolling_downgrade", "rolling_version_change", "rollback", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "secrets_used", "immutable_configmap" , "helm_deploy", "install_script_helm", "helm_chart_valid", "helm_chart_published", "chaos_network_loss", "chaos_cpu_hog", "chaos_container_kill", "volume_hostpath_not_found", "no_local_volume_configuration"]) + end + + it "'CNFManager::Points.all_result_test_names' should return the tasks assigned to a tag", tags: ["points"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + (CNFManager::Points.all_result_test_names(CNFManager::Points::Results.file)).should eq(["liveness"]) + end + it "'CNFManager::Points.results_by_tag' should return a list of results by tag", tags: ["points"] do + CNFManager::Points.clean_results_yml + CNFManager::Points.upsert_task("liveness", PASSED, CNFManager::Points.task_points("liveness")) + (CNFManager::Points.results_by_tag("configuration_lifecycle")).should eq([{"name" => "liveness", "status" => "passed", "points" => 5}]) + (CNFManager::Points.results_by_tag("does-not-exist")).should eq([] of YAML::Any) + end + + + it "'#CNFManager::Points::Results.file' should return the name of the current yaml file", tags: ["points"] do + CNFManager::Points.clean_results_yml + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + (yaml["name"]).should eq("cnf conformance") + (yaml["exit_code"]).should eq(0) + end + + it "'CNFManager::Points.final_cnf_results_yml. should return the latest time stamped results file", tags: ["points"] do + (CNFManager::Points.final_cnf_results_yml).should contain("cnf-conformance-results") + end + + + it "'CNFManager.sample_setup_cli_args(args) and CNFManager.sample_setup(cli_args)' should set up a sample cnf", tags: ["cnf-setup"] do + args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml", "verbose", "wait_count=180"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(cli_hash[:config_file])) + release_name = config.cnf_config[:release_name] + + (Dir.exists? "cnfs/#{release_name}").should be_true + (File.exists?("cnfs/#{release_name}/cnf-conformance.yml")).should be_true + (File.exists?("cnfs/#{release_name}/exported_chart/Chart.yaml")).should be_true + CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) + (Dir.exists? "cnfs/#{release_name}").should be_false + end + + it "'CNFManager.sample_setup' should set up a sample cnf", tags: ["cnf-setup"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # CNFManager.sample_setup(config_file: config_file, release_name: "", deployment_name: "coredns-coredns", helm_chart: "stable/coredns", helm_directory: "", git_clone_url: "https://github.com/coredns/coredns.git", wait_count: 0, verbose: true) # check if directory exists - (Dir.exists? "cnfs/coredns-coredns").should be_true - (File.exists?("cnfs/coredns-coredns/cnf-conformance.yml")).should be_true - (File.exists?("cnfs/coredns-coredns/helm_chart/Chart.yaml")).should be_true + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + + (Dir.exists? "cnfs/#{release_name}").should be_true + (File.exists?("cnfs/#{release_name}/cnf-conformance.yml")).should be_true + (File.exists?("cnfs/#{release_name}/exported_chart/Chart.yaml")).should be_true CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) - (Dir.exists? "cnfs/coredns-coredns").should be_false + (Dir.exists? "cnfs/#{release_name}").should be_false end - it "'CNFManager.sample_setup_args' should set up a sample cnf from a argument", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 0 ) + it "'CNFManager.sample_setup_args' should set up a sample cnf from a argument", tags: ["cnf-setup"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # CNFManager.sample_setup_args(sample_dir: config_file, args: args, verbose: true, wait_count: 0 ) # check if directory exists - (Dir.exists? "cnfs/coredns-coredns").should be_true - (File.exists?("cnfs/coredns-coredns/cnf-conformance.yml")).should be_true - (File.exists?("cnfs/coredns-coredns/helm_chart/Chart.yaml")).should be_true + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + (Dir.exists? "cnfs/#{release_name}").should be_true + (File.exists?("cnfs/#{release_name}/cnf-conformance.yml")).should be_true + # (File.exists?("cnfs/#{release_name}/helm_chart/Chart.yaml")).should be_true CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) - (Dir.exists? "cnfs/coredns-coredns").should be_false + (Dir.exists? "cnfs/#{release_name}").should be_false end - it "'CNFManager.sample_setup_args' should set up a sample cnf from a config file", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf/cnf-conformance.yml", args: args, verbose: true, wait_count: 0 ) + it "'CNFManager.sample_setup_args' should set up a sample cnf from a config file", tags: ["cnf-setup"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # CNFManager.sample_setup_args(sample_dir: config_file, args: args, verbose: true, wait_count: 0 ) # check if directory exists + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] (Dir.exists? "sample-cnfs/sample-generic-cnf").should be_true - (File.exists?("cnfs/coredns-coredns/cnf-conformance.yml")).should be_true - (File.exists?("cnfs/coredns-coredns/helm_chart/Chart.yaml")).should be_true + (File.exists?("cnfs/#{release_name}/cnf-conformance.yml")).should be_true + # (File.exists?("cnfs/#{release_name}/helm_chart/Chart.yaml")).should be_true CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) - (Dir.exists? "cnfs/coredns-coredns").should be_false + (Dir.exists? "cnfs/#{release_name}").should be_false end - it "'CNFManager.sample_cleanup' should clean up a sample cnf from a argument", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 0 ) + it "'CNFManager.sample_cleanup' should clean up a sample cnf from a argument", tags: ["cnf-setup"] do + args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 0 ) cleanup = CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) (cleanup).should be_true - (Dir.exists? "cnfs/coredns-coredns").should be_false - (File.exists?("cnfs/coredns-coredns/cnf-conformance.yml")).should be_false - (File.exists?("cnfs/coredns-coredns/helm_chart/Chart.yaml")).should be_false + (Dir.exists? "cnfs/coredns").should be_false + (File.exists?("cnfs/coredns/cnf-conformance.yml")).should be_false + (File.exists?("cnfs/coredns/helm_chart/Chart.yaml")).should be_false end - it "'CNFManager.sample_setup_args' should be able to deploy using a helm_directory", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) - (Dir.exists? "cnfs/privileged-coredns-coredns").should be_true + it "'CNFManager.sample_setup_args' should be able to deploy using a helm_directory", tags: ["cnf-setup"] do + config_file = "sample-cnfs/sample_privileged_cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # CNFManager.sample_setup_args(sample_dir: config_file, deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + (Dir.exists? "cnfs/#{release_name}").should be_true # should not clone - (Dir.exists? "cnfs/privileged-coredns-coredns/privileged-coredns").should be_false - (File.exists? "cnfs/privileged-coredns-coredns/cnf-conformance.yml").should be_true - (File.exists? "cnfs/privileged-coredns-coredns/chart/Chart.yaml").should be_true + (Dir.exists? "cnfs/#{release_name}/privileged-coredns").should be_false + (File.exists? "cnfs/#{release_name}/cnf-conformance.yml").should be_true + (File.exists? "cnfs/#{release_name}/chart/Chart.yaml").should be_true CNFManager.sample_cleanup(config_file: "sample-cnfs/sample_privileged_cnf", verbose: true) - (Dir.exists? "cnfs/privileged-coredns-coredns").should be_false + (Dir.exists? "cnfs/#{release_name}").should be_false + end + + it "'CNFManager.sample_setup_args and CNFManager.sample_cleanup' should be able to deploy and cleanup using a manifest_directory", tags: ["cnf-setup"] do + config_file = "sample-cnfs/k8s-non-helm" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # config_file = "sample-cnfs/k8s-non-helm" + # CNFManager.sample_setup_args(sample_dir: config_file, deploy_with_chart: false, args: args, verbose: true, install_from_manifest: true, wait_count: 0 ) + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + (Dir.exists? "cnfs/#{release_name}").should be_true + (Dir.exists? "cnfs/#{release_name}/manifests").should be_true + (File.exists? "cnfs/#{release_name}/cnf-conformance.yml").should be_true + (KubectlClient::Get.pod_exists?("nginx-webapp")).should be_true + CNFManager.sample_cleanup(config_file: "sample-cnfs/k8s-non-helm", installed_from_manifest: true, verbose: true) + # TODO check for pod status = terminating + (KubectlClient::Get.pod_exists?("nginx-webapp", check_ready: true)).should be_false + (Dir.exists? "cnfs/#{release_name}").should be_false end it "'cnf_destination_dir' should return the full path of the potential destination cnf directory based on the deployment name", tags: "WIP" do args = Sam::Args.new - CNFManager.cnf_destination_dir("spec/fixtures/cnf-conformance.yml").should contain("/cnfs/coredns-coredns") + CNFManager.cnf_destination_dir("spec/fixtures/cnf-conformance.yml").should contain("/cnfs/coredns") end - it "'CNFManager.cnf_config_list' should return a list of all of the config files from the cnf directory", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 1 ) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: args, verbose: true ) - CNFManager.cnf_config_list()[0].should contain("coredns-coredns/#{CONFIG_FILE}") + it "'CNFManager.cnf_config_list' should return a list of all of the config files from the cnf directory", tags: ["cnf-setup"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # args = Sam::Args.new + # config_file = "sample-cnfs/sample-generic-cnf" + # CNFManager.sample_setup_args(sample_dir: config_file, args: args, verbose: true, wait_count: 1 ) + args = Sam::Args.new(["cnf-config=./sample-cnfs/sample_privileged_cnf/cnf-conformance.yml", "verbose"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: args, verbose: true ) + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + CNFManager.cnf_config_list()[0].should contain("#{release_name}/#{CONFIG_FILE}") end - it "'CNFManager.helm_repo_add' should add a helm repo if the helm repo is valid", tags: "happy-path" do - args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 1 ) + it "'CNFManager.helm_repo_add' should add a helm repo if the helm repo is valid", tags: ["helm-repo"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + # args = Sam::Args.new + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: args, verbose: true, wait_count: 1 ) # CNFManager.helm_repo_add.should eq(true) args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) CNFManager.helm_repo_add(args: args).should eq(true) end - it "'CNFManager.helm_repo_add' should return false if the helm repo is invalid", tags: "happy-path" do + it "'CNFManager.helm_repo_add' should return false if the helm repo is invalid", tags: ["helm-repo"] do CNFManager.helm_repo_add("invalid", "invalid").should eq(false) end - it "'CNFManager.validate_cnf_conformance_yml' (function) should pass, when a cnf has a valid config file yml", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (function) should pass, when a cnf has a valid config file yml", tags: ["validate_config"] do args = Sam::Args.new(["cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml"]) yml = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) @@ -134,14 +297,14 @@ describe "SampleUtils" do (command_output).should eq (nil) end - it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, when a cnf has a valid config file yml", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, when a cnf has a valid config file yml", tags: ["validate_config"] do response_s = `./cnf-conformance validate_config cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` $?.success?.should be_true (/PASSED: CNF configuration validated/ =~ response_s).should_not be_nil end - it "'CNFManager.validate_cnf_conformance_yml' (function) should warn, but be valid when a cnf config file yml has fields that are not a part of the validation type", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (function) should warn, but be valid when a cnf config file yml has fields that are not a part of the validation type", tags: ["validate_config"] do args = Sam::Args.new(["cnf-config=./spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml"]) yml = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) @@ -157,21 +320,25 @@ describe "SampleUtils" do end - it "'CNFManager.validate_cnf_conformance_yml' (command) should warn, but be valid when a cnf config file yml has fields that are not a part of the validation type", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (command) should warn, but be valid when a cnf config file yml has fields that are not a part of the validation type", tags: ["validate_config"] do response_s = `./cnf-conformance validate_config cnf-config=spec/fixtures/cnf-conformance-unmapped-keys-and-subkeys.yml` $?.success?.should be_true + LOGGING.debug "validate_config resp: #{response_s}" (/WARNING: Unmapped cnf_conformance.yml keys. Please add them to the validator/ =~ response_s).should_not be_nil (/WARNING: helm_repository is unset or has unmapped subkeys. Please update your cnf_conformance.yml/ =~ response_s).should_not be_nil (/PASSED: CNF configuration validated/ =~ response_s).should_not be_nil end - it "'CNFManager.validate_cnf_conformance_yml' (function) should fail when an invalid cnf config file yml is used", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (function) should fail when an invalid cnf config file yml is used", tags: ["validate_config"] do args = Sam::Args.new(["cnf-config=spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml"]) + yml = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) LOGGING.info yml.inspect - ("#{yml.get("release_name").as_s?}").should eq("coredns") + # config = CNFManager::Config.parse_config_yml(args.named["cnf-config"].as(String)) + # release_name = config.cnf_config[:release_name] + # ("#{yml.get("release_name").as_s?}").should eq(release_name) status, warning_output = CNFManager.validate_cnf_conformance_yml(yml) @@ -179,44 +346,77 @@ describe "SampleUtils" do (warning_output).should eq(nil) end - it "'CNFManager.validate_cnf_conformance_yml' (command) should fail when an invalid cnf config file yml is used", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (command) should fail when an invalid cnf config file yml is used", tags: ["validate_config"] do response_s = `./cnf-conformance validate_config cnf-config=spec/fixtures/cnf-conformance-invalid-and-unmapped-keys.yml` $?.success?.should be_true (/ERROR: cnf_conformance.yml field validation error/ =~ response_s).should_not be_nil - (/FAILURE: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s).should_not be_nil + (/FAILED: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s).should_not be_nil end - it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, for all sample-cnfs", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, for all sample-cnfs", tags: ["validate_config"] do get_dirs = Dir.entries("sample-cnfs") dir_list = get_dirs - [".", ".."] dir_list.each do |dir| conformance_yml = "sample-cnfs/#{dir}/cnf-conformance.yml" response_s = `./cnf-conformance validate_config cnf-config=#{conformance_yml}` - if (/FAILURE: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s) + if (/FAILED: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s) LOGGING.info "\n #{conformance_yml}: #{response_s}" end (/PASSED: CNF configuration validated/ =~ response_s).should_not be_nil end end - it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, for all example-cnfs", tags: ["unhappy-path", "validate_config"] do + it "'CNFManager.validate_cnf_conformance_yml' (command) should pass, for all example-cnfs", tags: ["validate_config"] do get_dirs = Dir.entries("example-cnfs") dir_list = get_dirs - [".", ".."] dir_list.each do |dir| conformance_yml = "example-cnfs/#{dir}/cnf-conformance.yml" response_s = `./cnf-conformance validate_config cnf-config=#{conformance_yml}` - if (/FAILURE: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s) + if (/FAILED: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file/ =~ response_s) LOGGING.info "\n #{conformance_yml}: #{response_s}" end (/PASSED: CNF configuration validated/ =~ response_s).should_not be_nil end end - it "'CNFManager.helm_gives_k8s_warning?' should pass when k8s config = chmod 700" do - (CNFManager.helm_gives_k8s_warning?(true)).should be_false + + it "'CNFManager::Config#parse_config_yml' should return a populated CNFManager::Config.cnf_config", tags: ["cnf-config"] do + begin + yaml = CNFManager::Config.parse_config_yml("spec/fixtures/cnf-conformance.yml") + (yaml.cnf_config[:release_name]).should eq("coredns") + ensure + end + end + + it "'CNFManager.workload_resource_test' should accept an args and cnf-config argument, populate a deployment, container, and intialized argument, and then apply a test to a cnf", tags: ["cnf-config"] do + args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) + # check_cnf_config_then_deploy(args) + cli_hash = CNFManager.sample_setup_cli_args(args, false) + CNFManager.sample_setup(cli_hash) if cli_hash["config_file"] + config = CNFManager::Config.parse_config_yml("./sample-cnfs/sample-generic-cnf/cnf-conformance.yml") + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + test_passed = true + begin + VERBOSE_LOGGING.debug container.as_h["name"].as_s if check_verbose(args) + container.as_h["livenessProbe"].as_h + rescue ex + VERBOSE_LOGGING.error ex.message if check_verbose(args) + test_passed = false + puts "No livenessProbe found for resource: #{resource} and container: #{container.as_h["name"].as_s}".colorize(:red) + end + test_passed + end + (task_response).should be_true + CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) + end + + it "'CNFManager.exclusive_install_method_tags' should return false if install method tags are not exclusive", tags: ["cnf-config"] do + config = CNFManager.parsed_config_file("./spec/fixtures/cnf-conformance-not-exclusive.yml") + resp = CNFManager.exclusive_install_method_tags?(config) + (resp).should be_false end end diff --git a/spec/utils/kubectl_client_spec.cr b/spec/utils/kubectl_client_spec.cr index a57469364..97cbc7a64 100644 --- a/spec/utils/kubectl_client_spec.cr +++ b/spec/utils/kubectl_client_spec.cr @@ -1,6 +1,6 @@ require "../spec_helper" -require "colorize" require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/dockerd_setup.cr" require "../../src/tasks/utils/kubectl_client.cr" require "file_utils" require "sam" @@ -8,18 +8,118 @@ require "sam" describe "KubectlClient" do # after_all do # end - it "'#KubectlClient.get_nodes' should return the information about a node in json" do + + it "'Kubectl::Get.wait_for_install' should wait for a cnf to be installed", tags: ["kubectl-install"] do + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose wait_count=0` + + $?.success?.should be_true + + current_dir = FileUtils.pwd + LOGGING.info current_dir + #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" + helm = CNFSingleton.helm + LOGGING.info helm + #TODO only need previous install now this helm install + helm_install = `#{helm} install coredns stable/coredns` + LOGGING.info helm_install + KubectlClient::Get.wait_for_install("coredns-coredns") + current_replicas = `kubectl get deployments coredns-coredns -o=jsonpath='{.status.readyReplicas}'` + (current_replicas.to_i > 0).should be_true + end + + it "'Kubectl::Get.resource_wait_for_uninstall' should wait for a cnf to be installed", tags: ["kubectl-install"] do + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml verbose wait_count=0` + + $?.success?.should be_true + + LOGGING.debug `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml` + resp = KubectlClient::Get.resource_wait_for_uninstall("deployment", "my-release-wordpress") + (resp).should be_true + end + + it "'#KubectlClient.pods_for_resource' should return the pods for a resource", tags: ["kubectl-nodes"] do + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml verbose wait_count=0` + json = KubectlClient::Get.pods_for_resource("deployment", "my-release-wordpress") + #(json["items"].size).should be > 0 + end + + it "'#KubectlClient.get_nodes' should return the information about a node in json", tags: ["kubectl-nodes"] do json = KubectlClient::Get.nodes (json["items"].size).should be > 0 end - it "'#KubectlClient.container_runtime' should return the information about a node in json" do + it "'#KubectlClient.container_runtime' should return the information about the container runtime", tags: ["kubectl-runtime"] do resp = KubectlClient::Get.container_runtime (resp.match(KubectlClient::OCI_RUNTIME_REGEX)).should_not be_nil end - it "'#KubectlClient.container_runtimes' should return all container runtimes" do + it "'#KubectlClient.container_runtimes' should return all container runtimes", tags: ["kubectl-runtime"] do resp = KubectlClient::Get.container_runtimes (resp[0].match(KubectlClient::OCI_RUNTIME_REGEX)).should_not be_nil end + + it "'#KubectlClient.schedulable_nodes' should return all schedulable worker nodes", tags: ["kubectl-nodes"] do + retry_limit = 50 + retries = 1 + nodes = nil + until (nodes && nodes.size > 0 && !nodes[0].empty?) || retries > retry_limit + LOGGING.info "schedulable_node retry: #{retries}" + sleep 1.0 + nodes = KubectlClient::Get.schedulable_nodes + retries = retries + 1 + end + LOGGING.info "schedulable_node node: #{nodes}" + # resp = KubectlClient::Get.schedulable_nodes + (nodes).should_not be_nil + if nodes + (nodes.size).should be > 0 + (nodes[0]).should_not be_nil + (nodes[0]).should_not be_empty + end + end + + it "'#KubectlClient.containers' should return all containers defined in a deployment", tags: ["kubectl-pods"] do + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/k8s-sidecar-container-pattern/cnf-conformance.yml wait_count=0` + resp = KubectlClient::Get.deployment_containers("nginx-webapp") + (resp.size).should be > 0 + ensure + LOGGING.debug `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/k8s-sidecar-container-pattern/cnf-conformance.yml deploy_with_chart=false` + end + + it "'#KubectlClient.pod_exists?' should true if a pod exists", tags: ["kubectl-pods"] do + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml` + resp = KubectlClient::Get.pod_exists?("coredns") + (resp).should be_true + ensure + LOGGING.debug `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml` + end + it "'#KubectlClient.pod_status' should return a status of false if the pod is not installed (failed to install) and other pods exist", tags: ["kubectl-pods"] do + cnf="./sample-cnfs/sample-coredns-cnf" + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + LOGGING.info `./cnf-conformance uninstall_dockerd` + dockerd_tempname_helper + LOGGING.info `./cnf-conformance install_dockerd` + + resp = KubectlClient::Get.pod_status(pod_name_prefix: "dockerd").split(",")[2] # true/false + LOGGING.info resp + (resp && !resp.empty? && resp == "true").should be_false + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + dockerd_name_helper + LOGGING.info `./cnf-conformance install_dockerd` + end + + it "'#KubectlClient.pod_status' should return a status of true if the pod is installed and other pods exist", tags: ["kubectl-pods"] do + cnf="./sample-cnfs/sample-coredns-cnf" + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + LOGGING.info `./cnf-conformance install_dockerd` + + resp = KubectlClient::Get.pod_status(pod_name_prefix: "dockerd").split(",")[2] # true/false + LOGGING.info resp + (resp && !resp.empty? && resp == "true").should be_true + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + dockerd_name_helper + LOGGING.info `./cnf-conformance install_dockerd` + end end diff --git a/spec/utils/release_manager_spec.cr b/spec/utils/release_manager_spec.cr index 3a72bc24d..ab96629dd 100644 --- a/spec/utils/release_manager_spec.cr +++ b/spec/utils/release_manager_spec.cr @@ -9,14 +9,14 @@ describe "ReleaseManager" do after_all do ReleaseManager::GithubReleaseManager.delete_release("test_version") end - it "'#ReleaseManager.tag' should return the list of tags on the current branch" do + it "'#ReleaseManager.tag' should return the list of tags on the current branch", tags: ["release"] do (ReleaseManager.tag.size).should be > 0 end - it "'#ReleaseManager.tag' should accept a list of options" do + it "'#ReleaseManager.tag' should accept a list of options", tags: ["release"] do (ReleaseManager.tag("--list")).should_not eq([""]) (ReleaseManager.tag("--list 'shouldbeempty'")).should eq([""]) end - it "'#ReleaseManager.current_branch' should return the current branch as a string" do + it "'#ReleaseManager.current_branch' should return the current branch as a string", tags: ["release"] do if ReleaseManager.on_a_tag? (ReleaseManager.tag("--list")).should_not eq([""]) else @@ -24,15 +24,15 @@ describe "ReleaseManager" do end end - it "'#ReleaseManager.current_hash' should return the current hash as a string" do + it "'#ReleaseManager.current_hash' should return the current hash as a string", tags: ["release"] do (ReleaseManager.current_hash).should_not eq("") end - it "'#ReleaseManager.remote_master_branch_hash' should return the current hash as a string" do - (ReleaseManager.remote_master_branch_hash).should_not eq("") + it "'#ReleaseManager.remote_main_branch_hash' should return the current hash as a string", tags: ["release"] do + (ReleaseManager.remote_main_branch_hash).should_not eq("") end - it "'#ReleaseManager::GithubReleaseManager.github_releases' should return the existing releases", tags: "release" do + it "'#ReleaseManager::GithubReleaseManager.github_releases' should return the existing releases", tags: ["release"] do if ENV["GITHUB_USER"]?.nil? puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) else @@ -40,7 +40,7 @@ describe "ReleaseManager" do end end - it "'#ReleaseManager::GithubReleaseManager.upsert_release' should return the upserted release and asset response", tags: "release" do + it "'#ReleaseManager::GithubReleaseManager.upsert_release' should return the upserted release and asset response", tags: ["release"] do if ENV["GITHUB_USER"]?.nil? puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) else @@ -53,31 +53,32 @@ describe "ReleaseManager" do end end - it "'#ReleaseManager::GithubReleaseManager.upsert_release' should return nil if not on a valid version", tags: "release" do + it "'#ReleaseManager::GithubReleaseManager.upsert_release' should return nil if not on a valid version", tags: ["release"] do found_release, asset = ReleaseManager::GithubReleaseManager.upsert_release("invalid_version") (asset).should be_nil end - it "'#ReleaseManager::GithubReleaseManager.delete_release' should delete the release from the found_id", tags: "release" do + it "'#ReleaseManager::GithubReleaseManager.delete_release' should delete the release from the found_id", tags: ["release"] do if ENV["GITHUB_USER"]?.nil? puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) else found_release, asset = ReleaseManager::GithubReleaseManager.upsert_release("test_version") + # wait for upsert to finish resp_code = ReleaseManager::GithubReleaseManager.delete_release("test_version") (resp_code == 204).should be_truthy end end - it "'#ReleaseManager.detached_head?' should return if the head is detached", tags: "release" do + it "'#ReleaseManager.detached_head?' should return if the head is detached", tags: ["release"] do (ReleaseManager.detached_head?).should_not be_nil end - it "'#ReleaseManager.commit_message_issues' should list previsions releases", tags: "release" do + it "'#ReleaseManager.commit_message_issues' should list previsions releases", tags: ["release"] do hash = ReleaseManager.current_hash - issues = ReleaseManager.commit_message_issues("0.0.5", hash) + issues = ReleaseManager.commit_message_issues("v0.9.19", hash) (issues[0].match(/#/)).should_not be_nil end - it "'#ReleaseManager.latest_release' should return latest release", tags: "release" do + it "'#ReleaseManager.latest_release' should return latest release", tags: ["release"] do if ENV["GITHUB_USER"]?.nil? puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) else @@ -87,7 +88,18 @@ describe "ReleaseManager" do end end - it "'#ReleaseManager.issue_title' should return issue title", tags: "release" do + it "'#ReleaseManager.latest_snapshot' should return the latest snapshot", tags: ["release"] do + if ENV["GITHUB_USER"]?.nil? + puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) + else + issues = ReleaseManager.latest_snapshot + # https://github.com/semver/semver/blob/master/semver.md#is-v123-a-semantic-version + (issues.match(/(?i)(main)/)).should_not be_nil + end + end + + + it "'#ReleaseManager.issue_title' should return issue title", tags: ["release"] do if ENV["GITHUB_USER"]?.nil? puts "Warning: Set GITHUB_USER and GITHUB_TOKEN to activate release manager tests!".colorize(:red) else diff --git a/spec/utils/system_information/curl_spec.cr b/spec/utils/system_information/curl_spec.cr index 47f6807fc..fdad28421 100644 --- a/spec/utils/system_information/curl_spec.cr +++ b/spec/utils/system_information/curl_spec.cr @@ -8,20 +8,20 @@ require "sam" describe "Curl" do - it "'curl_global_response()' should return the information about the curl installation", tags: "happy-path" do + it "'curl_global_response()' should return the information about the curl installation", tags: ["curl"] do (curl_global_response(true)).should contain("curl") end - it "'curl_local_response()' should return the information about the curl installation", tags: "happy-path" do + it "'curl_local_response()' should return the information about the curl installation", tags: ["curl"] do (curl_local_response(true)).should eq("") end - it "'curl_version()' should return the information about the curl version", tags: "happy-path" do + it "'curl_version()' should return the information about the curl version", tags: ["curl"] do (curl_version(curl_global_response)).should match(/(([0-9]{1,3}[\.]){1,2}[0-9]{1,3})/) (curl_version(curl_local_response)).should contain("") end - it "'curl_installations()' should return the information about the curl installation", tags: "happy-path" do + it "'curl_installations()' should return the information about the curl installation", tags: ["curl"] do (curl_installation(true)).should contain("curl found") end end diff --git a/spec/utils/system_information/git_spec.cr b/spec/utils/system_information/git_spec.cr index c91c274ac..0278ca999 100644 --- a/spec/utils/system_information/git_spec.cr +++ b/spec/utils/system_information/git_spec.cr @@ -8,20 +8,20 @@ require "sam" describe "Git" do - it "'git_global_response()' should return the information about the git installation", tags: "git-prereq" do + it "'git_global_response()' should return the information about the git installation", tags: ["git-prereq"] do (git_global_response(true)).should contain("git version") end - it "'git_local_response()' should return the information about the git installation", tags: "git-prereq" do + it "'git_local_response()' should return the information about the git installation", tags: ["git-prereq"] do (git_local_response(true)).should eq("") end - it "'git_version()' should return the information about the git version", tags: "git-prereq" do + it "'git_version()' should return the information about the git version", tags: ["git-prereq"] do (git_version(git_global_response)).should match(/(([0-9]{1,3}[\.]){1,2}[0-9]{1,3})/) (git_version(git_local_response)).should contain("") end - it "'git_installations()' should return the information about the git installation", tags: "git-prereq" do + it "'git_installations()' should return the information about the git installation", tags: ["git-prereq"] do (git_installation(true)).should contain("git found") end end diff --git a/spec/utils/system_information/helm_spec.cr b/spec/utils/system_information/helm_spec.cr index b52dd6a26..54d35d2f5 100644 --- a/spec/utils/system_information/helm_spec.cr +++ b/spec/utils/system_information/helm_spec.cr @@ -8,20 +8,24 @@ require "sam" describe "Helm" do - it "'helm_global_response()' should return the information about the helm installation", tags: "happy-path" do + it "'helm_global_response()' should return the information about the helm installation", tags: ["helm-utils"] do # TODO make global response be a regex of v. or nil? # (helm_global_response(true)).should contain("\"v2.") end - it "'helm_local_response()' should return the information about the helm installation", tags: "happy-path" do + it "'helm_local_response()' should return the information about the helm installation", tags: ["helm-utils"] do (helm_local_response(true)).should contain("\"v3.") end - it "'helm_version()' should return the information about the helm version", tags: "happy-path" do + it "'helm_version()' should return the information about the helm version", tags: ["helm-utils"] do (helm_version(helm_local_response)).should contain("v3.") end - it "'helm_installations()' should return the information about the helm installation", tags: "happy-path" do + it "'helm_installations()' should return the information about the helm installation", tags: ["helm-utils"] do (helm_installation(true)).should contain("helm found") end + + it "'Helm.helm_gives_k8s_warning?' should pass when k8s config = chmod 700", tags: ["helm-utils"] do + (Helm.helm_gives_k8s_warning?(true)).should be_false + end end diff --git a/spec/utils/system_information/kubectl_spec.cr b/spec/utils/system_information/kubectl_spec.cr index 6cd0293c3..fac11b68e 100644 --- a/spec/utils/system_information/kubectl_spec.cr +++ b/spec/utils/system_information/kubectl_spec.cr @@ -8,20 +8,20 @@ require "sam" describe "Kubectl" do - it "'kubectl_global_response()' should return the information about the kubectl installation", tags: "happy-path" do + it "'kubectl_global_response()' should return the information about the kubectl installation", tags: ["kubectl-utils"] do (kubectl_global_response(true)).should contain("Client Version") end - it "'kubectl_local_response()' should return the information about the kubectl installation", tags: "happy-path" do + it "'kubectl_local_response()' should return the information about the kubectl installation", tags: ["kubectl-utils"] do (kubectl_local_response(true)).should eq("") end - it "'kubectl_version()' should return the information about the kubectl version", tags: "happy-path" do + it "'kubectl_version()' should return the information about the kubectl version", tags: ["kubectl-utils"] do (kubectl_version(kubectl_global_response)).should match(/(([0-9]{1,3}[\.]){1,2}[0-9]{1,3}[+]?)/) (kubectl_version(kubectl_local_response)).should contain("") end - it "'kubectl_installations()' should return the information about the kubectl installation", tags: "happy-path" do + it "'kubectl_installations()' should return the information about the kubectl installation", tags: ["kubectl-utils"] do (kubectl_installation(true)).should contain("kubectl found") end end diff --git a/spec/utils/system_information/wget_spec.cr b/spec/utils/system_information/wget_spec.cr index 298f73275..ac7e664bb 100644 --- a/spec/utils/system_information/wget_spec.cr +++ b/spec/utils/system_information/wget_spec.cr @@ -1,27 +1,27 @@ -require "../../spec_helper" -require "colorize" -require "../../../src/tasks/utils/utils.cr" -require "../../../src/tasks/prereqs.cr" -require "../../../src/tasks/utils/system_information/wget.cr" -require "file_utils" -require "sam" +# require "../../spec_helper" +# require "colorize" +# require "../../../src/tasks/utils/utils.cr" +# require "../../../src/tasks/prereqs.cr" +# require "../../../src/tasks/utils/system_information/wget.cr" +# require "file_utils" +# require "sam" -describe "Wget" do +# describe "Wget" do - it "'wget_global_response()' should return the information about the wget installation", tags: "happy-path" do - (wget_global_response(true)).should contain("GNU Wget") - end +# it "'wget_global_response()' should return the information about the wget installation", tags: ["wget"] do +# (wget_global_response(true)).should contain("GNU Wget") +# end - it "'wget_local_response()' should return the information about the wget installation", tags: "happy-path" do - (wget_local_response(true)).should eq("") - end +# it "'wget_local_response()' should return the information about the wget installation", tags: ["wget"] do +# (wget_local_response(true)).should eq("") +# end - it "'wget_version()' should return the information about the wget version", tags: "happy-path" do - (wget_version(wget_global_response)).should match(/(([0-9]{1,3}[\.]){1,2}[0-9]{1,3})/) - (wget_version(wget_local_response)).should contain("") - end +# it "'wget_version()' should return the information about the wget version", tags: ["wget"] do +# (wget_version(wget_global_response)).should match(/(([0-9]{1,3}[\.]){1,2}[0-9]{1,3})/) +# (wget_version(wget_local_response)).should contain("") +# end - it "'wget_installations()' should return the information about the wget installation", tags: "happy-path" do - (wget_installation(true)).should contain("wget found") - end -end +# it "'wget_installations()' should return the information about the wget installation", tags: ["wget"] do +# (wget_installation(true)).should contain("wget found") +# end +# end diff --git a/spec/utils/utils_spec.cr b/spec/utils/utils_spec.cr index b448403b1..20efb2b7b 100644 --- a/spec/utils/utils_spec.cr +++ b/spec/utils/utils_spec.cr @@ -2,6 +2,7 @@ require "../spec_helper" require "colorize" require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/kubectl_client.cr" require "file_utils" require "sam" @@ -13,125 +14,11 @@ describe "Utils" do `./cnf-conformance results_yml_cleanup` end - it "'#Results.file' should return the name of the current yaml file" do - clean_results_yml - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - (yaml["name"]).should eq("cnf conformance") - end - - it "'CNFManager.final_cnf_results_yml' should return the latest time stamped results file" do - (CNFManager.final_cnf_results_yml).should contain("cnf-conformance-results") - end - - it "'points_yml' should parse and return the points yaml file" do - (points_yml.find {|x| x["name"] =="liveness"}).should be_truthy - end - - it "'task_points' should return the amount of points for a passing test" do - # default - (task_points("liveness")).should eq(5) - # assigned - (task_points("increase_capacity")).should eq(10) - end - - it "'task_points(, false)' should return the amount of points for a failing test" do - # default - (task_points("liveness", false)).should eq(-1) - # assigned - (task_points("increase_capacity", false)).should eq(-5) - end - - it "'failed_task' should find and update an existing task in the file" do - clean_results_yml - failed_task("liveness", "FAILURE: No livenessProbe found") - - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - LOGGING.info yaml.inspect - (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == task_points("liveness", false)}).should be_truthy - end - - it "'passed_task' should find and update an existing task in the file" do - clean_results_yml - passed_task("liveness", "PASSED: livenessProbe found") - - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - LOGGING.info yaml.inspect - (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == task_points("liveness")}).should be_truthy - end - - it "'task_required' should return if the passed task is required" do - clean_results_yml - (task_required("privileged")).should be_true - end - - it "'failed_required_tasks' should return a list of failed required tasks" do - clean_results_yml - failed_task("privileged", "FAILURE: Privileged container found") - (failed_required_tasks).should eq(["privileged"]) - end - - it "'upsert_task' insert task in the results file" do - clean_results_yml - upsert_task("liveness", PASSED, task_points("liveness")) - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - # LOGGING.debug yaml["items"].as_a.inspect - (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == task_points("liveness")}).should be_truthy - end - - it "'upsert_task' should find and update an existing task in the file" do - clean_results_yml - upsert_task("liveness", PASSED, task_points("liveness")) - upsert_task("liveness", PASSED, task_points("liveness")) - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - # LOGGING.debug yaml["items"].as_a.inspect - (yaml["items"].as_a.find {|x| x["name"] == "liveness" && x["points"] == task_points("liveness")}).should be_truthy - (total_points).should eq(5) - end - - it "'total_points' should sum the total amount of points in the results" do - clean_results_yml - upsert_task("liveness", PASSED, task_points("liveness")) - (total_points).should eq(5) - end - - it "'tasks_by_tag' should return the tasks assigned to a tag" do - clean_results_yml - (tasks_by_tag("configuration_lifecycle")).should eq(["ip_addresses", "liveness", "readiness", "rolling_update", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration"]) - (tasks_by_tag("does-not-exist")).should eq([] of YAML::Any) - end - - it "'all_task_test_names' should return all tasks names" do - clean_results_yml - (all_task_test_names()).should eq(["reasonable_image_size", "reasonable_startup_time", "privileged", "increase_capacity", "decrease_capacity", "network_chaos", "ip_addresses", "liveness", "readiness", "rolling_update", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "helm_deploy", "install_script_helm", "helm_chart_valid", "helm_chart_published", "chaos_network_loss", "chaos_cpu_hog", "chaos_container_kill", "volume_hostpath_not_found"]) - end - - it "'all_result_test_names' should return the tasks assigned to a tag" do - clean_results_yml - upsert_task("liveness", PASSED, task_points("liveness")) - (all_result_test_names(Results.file)).should eq(["liveness"]) - end - it "'results_by_tag' should return a list of results by tag" do - clean_results_yml - upsert_task("liveness", PASSED, task_points("liveness")) - (results_by_tag("configuration_lifecycle")).should eq([{"name" => "liveness", "status" => "passed", "points" => 5}]) - (results_by_tag("does-not-exist")).should eq([] of YAML::Any) - end - - it "'toggle' should return a boolean for a toggle in the config.yml" do + it "'toggle' should return a boolean for a toggle in the config.yml", tags: ["args"] do (toggle("wip")).should eq(false) end - it "'check_feature_level' should return the feature level for an argument variable" do + it "'check_feature_level' should return the feature level for an argument variable", tags: ["args"] do args = Sam::Args.new(["name", "arg1=1", "beta"]) (check_feature_level(args)).should eq("beta") args = Sam::Args.new(["name", "arg1=1", "alpha"]) @@ -143,51 +30,54 @@ describe "Utils" do end - it "'check_' should return the feature level for an argument variable" do + it "'check_' should return the feature level for an argument variable", tags: ["args"] do # (check_ga).should be_false (check_alpha).should be_false (check_beta).should be_false (check_wip).should be_false end - it "'check_(args)' should return the feature level for an argument variable" do + it "'check_(args)' should return the feature level for an argument variable", tags: ["args"] do args = Sam::Args.new(["name", "arg1=1", "alpha"]) (check_alpha(args)).should be_true (check_beta(args)).should be_true (check_wip(args)).should be_false end - # it "'LOGGGING.level' should be Severity::ERROR when checked in" do - # (LOGGING.level).should eq(Logger::ERROR) - # end - it "'check_cnf_config' should return the value for a cnf-config argument" do + + it "'check_cnf_config' should return the value for a cnf-config argument", tags: ["args"] do args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) #TODO make CNFManager.sample_setup_args accept the full path to the config yml instead of the directory (check_cnf_config(args)).should eq("./sample-cnfs/sample-generic-cnf") end + - it "'check_all_cnf_args' should return the value for a cnf-config argument" do - args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) - #TODO make CNFManager.sample_setup_args accept the full path to the config yml instead of the directory - (check_all_cnf_args(args)).should eq({"./sample-cnfs/sample-generic-cnf", true}) - end - it "'check_cnf_config_then_deploy' should accept a cnf-config argument" do - args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) - check_cnf_config_then_deploy(args) - CNFManager.cnf_config_list()[0].should contain("coredns-coredns/#{CONFIG_FILE}") - CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) + it "'upsert_skipped_task' should put a 0 in the results file", tags: ["task_runner"] do + CNFManager::Points.clean_results_yml + resp = upsert_skipped_task("ip_addresses","✖️ FAILED: IP addresses found") + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + (yaml["items"].as_a.find {|x| + x["name"] == "ip_addresses" && + x["points"] == CNFManager::Points.task_points("ip_addresses", CNFManager::Points::Results::ResultStatus::Skipped) + }).should be_truthy + + (yaml["items"].as_a.find {|x| x["name"] == "ip_addresses" && x["points"] == 0 }).should be_truthy end - it "'single_task_runner' should accept a cnf-config argument and apply a test to that cnf" do + it "'single_task_runner' should accept a cnf-config argument and apply a test to that cnf", tags: ["task_runner"] do args = Sam::Args.new(["cnf-config=./sample-cnfs/sample-generic-cnf/cnf-conformance.yml"]) - check_cnf_config_then_deploy(args) - task_response = single_task_runner(args) do + # check_cnf_config_then_deploy(args) + cli_hash = CNFManager.sample_setup_cli_args(args, false) + CNFManager.sample_setup(cli_hash) if cli_hash["config_file"] + task_response = CNFManager::Task.single_task_runner(args) do config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) helm_chart_container_name = config.get("helm_chart_container_name").as_s privileged_response = `kubectl get pods --all-namespaces -o jsonpath='{.items[*].spec.containers[?(@.securityContext.privileged==true)].name}'` privileged_list = privileged_response.to_s.split(" ").uniq LOGGING.info "privileged_list #{privileged_list}" if privileged_list.select {|x| x == helm_chart_container_name}.size > 0 - resp = "✖️ FAILURE: Found privileged containers: #{privileged_list.inspect}".colorize(:red) + resp = "✖️ FAILED: Found privileged containers: #{privileged_list.inspect}".colorize(:red) else resp = "✔️ PASSED: No privileged containers".colorize(:green) end @@ -198,37 +88,97 @@ describe "Utils" do CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) end - it "'all_cnfs_task_runner' should run a test against all cnfs in the cnfs directory if there is not cnf-config argument passed to it" do + it "'single_task_runner' should put a 1 in the results file if it has an exception", tags: ["task_runner"] do + CNFManager::Points.clean_results_yml + args = Sam::Args.new(["cnf-config=./cnf-conformance.yml"]) + task_response = CNFManager::Task.single_task_runner(args) do + cdir = FileUtils.pwd() + response = String::Builder.new + config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + helm_directory = "#{config.get("helm_directory").as_s?}" + if File.directory?(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) + helm_directory) + Dir.cd(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) + helm_directory) + Process.run("grep -r -P '^(?!.+0\.0\.0\.0)(?![[:space:]]*0\.0\.0\.0)(?!#)(?![[:space:]]*#)(?!\/\/)(?![[:space:]]*\/\/)(?!\/\\*)(?![[:space:]]*\/\\*)(.+([0-9]{1,3}[\.]){3}[0-9]{1,3})'", shell: true) do |proc| + while line = proc.output.gets + response << line + end + end + Dir.cd(cdir) + if response.to_s.size > 0 + resp = upsert_failed_task("ip_addresses","✖️ FAILED: IP addresses found") + else + resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") + end + resp + else + Dir.cd(cdir) + resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") + end + end + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + (yaml["exit_code"]).should eq(1) + end + + it "'all_cnfs_task_runner' should run a test against all cnfs in the cnfs directory if there is not cnf-config argument passed to it", tags: ["task_runner"] do my_args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: my_args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: my_args ) - task_response = all_cnfs_task_runner(my_args) do |args| + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: my_args) + LOGGING.info `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-generic-cnf` + LOGGING.info `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_privileged_cnf` + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: my_args ) + task_response = CNFManager::Task.all_cnfs_task_runner(my_args) do |args, config| LOGGING.info("all_cnfs_task_runner spec args #{args.inspect}") - # config = cnf_conformance_yml(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - helm_chart_container_name = config.get("helm_chart_container_name").as_s - privileged_response = `kubectl get pods --all-namespaces -o jsonpath='{.items[*].spec.containers[?(@.securityContext.privileged==true)].name}'` - privileged_list = privileged_response.to_s.split(" ").uniq - LOGGING.info "privileged_list #{privileged_list}" - if privileged_list.select {|x| x == helm_chart_container_name}.size > 0 - resp = "✖️ FAILURE: Found privileged containers: #{privileged_list.inspect}".colorize(:red) + VERBOSE_LOGGING.info "privileged" if check_verbose(args) + white_list_container_names = config.cnf_config[:white_list_container_names] + VERBOSE_LOGGING.info "white_list_container_names #{white_list_container_names.inspect}" if check_verbose(args) + violation_list = [] of String + resource_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + privileged_list = KubectlClient::Get.privileged_containers + white_list_containers = ((PRIVILEGED_WHITELIST_CONTAINERS + white_list_container_names) - [container]) + # Only check the containers that are in the deployed helm chart or manifest + (privileged_list & ([container.as_h["name"].as_s] - white_list_containers)).each do |x| + violation_list << x + end + if violation_list.size > 0 + false + else + true + end + end + LOGGING.debug "violator list: #{violation_list.flatten}" + emoji_security="" + if resource_response + resp = upsert_passed_task("privileged", "✔️ PASSED: No privileged containers") else - resp = "✔️ PASSED: No privileged containers".colorize(:green) + resp = upsert_failed_task("privileged", "✖️ FAILED: Found #{violation_list.size} privileged containers: #{violation_list.inspect}") end - LOGGING.info resp resp end - (task_response).should eq(["✔️ PASSED: No privileged containers".colorize(:green), "✔️ PASSED: No privileged containers".colorize(:green)]) + (task_response).should eq(["✔️ PASSED: No privileged containers", + "✖️ FAILED: Found 1 privileged containers: [\"coredns\"]"]) + ensure CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) CNFManager.sample_cleanup(config_file: "sample-cnfs/sample_privileged_cnf", verbose: true) end - it "'task_runner' should run a test against a single cnf if passed a cnf-config argument even if there are multiple cnfs installed" do - my_args = Sam::Args.new - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", args: my_args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: my_args ) - installed_args = Sam::Args.new(["cnf-config=./cnfs/coredns-coredns/cnf-conformance.yml"]) - task_response = task_runner(installed_args) do |args| + it "'task_runner' should run a test against a single cnf if passed a cnf-config argument even if there are multiple cnfs installed", tags: ["task_runner"] do + config_file = "sample-cnfs/sample-generic-cnf" + args = Sam::Args.new(["cnf-config=./#{config_file}/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + args = Sam::Args.new(["cnf-config=./sample-cnfs/sample_privileged_cnf/cnf-conformance.yml", "verbose", "wait_count=0"]) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) + # my_args = Sam::Args.new + # config_file = "sample-cnfs/sample-generic-cnf" + # CNFManager.sample_setup_args(sample_dir: config_file, args: my_args) + # CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", args: my_args ) + cnfmng_config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = cnfmng_config.cnf_config[:release_name] + installed_args = Sam::Args.new(["cnf-config=./cnfs/#{release_name}/cnf-conformance.yml"]) + task_response = CNFManager::Task.task_runner(installed_args) do |args| LOGGING.info("task_runner spec args #{args.inspect}") # config = cnf_conformance_yml(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) @@ -237,23 +187,19 @@ describe "Utils" do privileged_list = privileged_response.to_s.split(" ").uniq LOGGING.info "privileged_list #{privileged_list}" if privileged_list.select {|x| x == helm_chart_container_name}.size > 0 - resp = "✖️ FAILURE: Found privileged containers: #{privileged_list.inspect}".colorize(:red) + resp = "✖️ FAILED: Found privileged containers: #{privileged_list.inspect}".colorize(:red) else resp = "✔️ PASSED: No privileged containers".colorize(:green) end LOGGING.info resp resp end - (task_response).should eq("✔️ PASSED: No privileged containers".colorize(:green)) + (task_response).should eq("✖️ FAILED: Found privileged containers: [\"coredns\", \"kube-proxy\"]".colorize(:red)) CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-generic-cnf", verbose: true) CNFManager.sample_cleanup(config_file: "sample-cnfs/sample_privileged_cnf", verbose: true) end - it "'generate_version' should return the current version of the cnf_conformance library" do - (generate_version).should_not eq("") - end - - it "'logger' command line logger level setting via config.yml", tags: ["logger", "happy-path"] do + it "'logger' command line logger level setting via config.yml", tags: ["logger"] do # NOTE: the config.yml file is in the root of the repo directory. # as written this test depends on they key loglevel being set to 'info' in that config.yml response_s = `./cnf-conformance test` @@ -264,21 +210,29 @@ describe "Utils" do (/ERROR -- cnf-conformance: error test/ =~ response_s).should_not be_nil end - it "'logger' command line logger level setting works", tags: ["logger", "happy-path"] do + it "'logger' command line logger level setting works", tags: ["logger"] do # Note: implicitly tests the override of config.yml if it exist in repo root response_s = `./cnf-conformance -l debug test` + LOGGING.info response_s + $?.success?.should be_true + (/DEBUG -- cnf-conformance: debug test/ =~ response_s).should_not be_nil + end + + it "'logger' LOGLEVEL NO underscore environment variable level setting works", tags: ["logger"] do + # Note: implicitly tests the override of config.yml if it exist in repo root + response_s = `unset LOG_LEVEL; LOGLEVEL=DEBUG ./cnf-conformance test` $?.success?.should be_true (/DEBUG -- cnf-conformance: debug test/ =~ response_s).should_not be_nil end - it "'logger' environment variable level setting works", tags: ["logger", "happy-path"] do + it "'logger' LOG_LEVEL WITH underscore environment variable level setting works", tags: ["logger"] do # Note: implicitly tests the override of config.yml if it exist in repo root - response_s = `LOGLEVEL=DEBUG ./cnf-conformance test` + response_s = `LOG_LEVEL=DEBUG ./cnf-conformance test` $?.success?.should be_true (/DEBUG -- cnf-conformance: debug test/ =~ response_s).should_not be_nil end - it "'logger' command line level setting overrides environment variable", tags: ["logger", "happy-path"] do + it "'logger' command line level setting overrides environment variable", tags: ["logger"] do response_s = `LOGLEVEL=DEBUG ./cnf-conformance -l error test` $?.success?.should be_true (/DEBUG -- cnf-conformance: debug test/ =~ response_s).should be_nil @@ -289,17 +243,41 @@ describe "Utils" do it "'logger' defaults to error when level set is missplled", tags: ["logger"] do # Note: implicitly tests the override of config.yml if it exist in repo root - response_s = `LOGLEVEL=DEGUB ./cnf-conformance test` + response_s = `unset LOG_LEVEL; LOGLEVEL=DEGUB ./cnf-conformance test` $?.success?.should be_true (/ERROR -- cnf-conformance: Invalid logging level set. defaulting to ERROR/ =~ response_s).should_not be_nil end it "'logger' or verbose output should be shown when verbose flag is set", tags: ["logger"] do - response_s = `./cnf-conformance helm_deploy verbose` + response_s = `./cnf-conformance helm_deploy destructive verbose` LOGGING.info response_s puts response_s $?.success?.should be_true (/INFO -- cnf-conformance-verbose: helm_deploy/ =~ response_s).should_not be_nil end + + it "'#update_yml' should update the value for a key in a yml file", tags: ["logger"] do + begin + update_yml("spec/fixtures/cnf-conformance.yml", "release_name", "coredns --set worker-node='kind-control-plane'") + yaml = File.open("spec/fixtures/cnf-conformance.yml") do |file| + YAML.parse(file) + end + (yaml["release_name"]).should eq("coredns --set worker-node='kind-control-plane'") + ensure + update_yml("spec/fixtures/cnf-conformance.yml", "release_name", "coredns") + end + end + + it "spec directory should have tags for all of the specs", tags: ["spec-tags"] do + response = String::Builder.new + Process.run("grep -r -P '^ *it(?!.*tags(.*\"))' ./spec", shell: true) do |proc| + while line = proc.output.gets + response << line + LOGGING.info "#{line}" + end + end + (response.to_s.size > 0).should be_false + end + end diff --git a/spec/workload/configuration_lifecycle_spec.cr b/spec/workload/configuration_lifecycle_spec.cr new file mode 100644 index 000000000..87b90f232 --- /dev/null +++ b/spec/workload/configuration_lifecycle_spec.cr @@ -0,0 +1,452 @@ +require "../spec_helper" +require "../../src/tasks/utils/kubectl_client.cr" +require "colorize" + +describe CnfConformance do + before_all do + LOGGING.debug `pwd` + LOGGING.debug `echo $KUBECONFIG` + + `./cnf-conformance setup` + `./cnf-conformance samples_cleanup` + $?.success?.should be_true + `./cnf-conformance configuration_file_setup` + + # `./cnf-conformance setup` + # $?.success?.should be_true + end + + + it "'liveness' should pass when livenessProbe is set", tags: ["liveness"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `LOG_LEVEL=debug ./cnf-conformance liveness verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Helm liveness probe/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false ` + end + end + + it "'liveness' should fail when livenessProbe is not set", tags: ["liveness"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance liveness verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: No livenessProbe found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance sample_coredns_bad_liveness_cleanup` + end + end + + it "'readiness' should pass when readinessProbe is set", tags: ["readiness"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `LOG_LEVEL=debug ./cnf-conformance readiness verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Helm readiness probe/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/k8s-multiple-deployments/cnf-conformance.yml deploy_with_chart=false ` + end + end + + it "'readiness' should fail when readinessProbe is not set", tags: ["readiness"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns_bad_liveness/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance readiness verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: No readinessProbe found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance sample_coredns_bad_liveness_cleanup` + end + end + + it "'rolling_update' should pass when valid version is given", tags: ["rolling_update"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance rolling_update verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + it "'rolling_update' should fail when invalid version is given", tags: ["rolling_update"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance rolling_update verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Failed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'rolling_update' should pass if using local registry and a port", tags: ["rolling_update"] do + begin + install_registry = `kubectl create -f #{TOOLS_DIR}/registry/manifest.yml` + install_dockerd = `kubectl create -f #{TOOLS_DIR}/dockerd/manifest.yml` + KubectlClient::Get.resource_wait_for_install("Pod", "registry") + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.6.7 registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.8.0 registry:5000/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.8.0") + + cnf="./sample-cnfs/sample_local_registry" + + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance rolling_update verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + delete_registry = `kubectl delete -f #{TOOLS_DIR}/registry/manifest.yml` + delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end + end + + it "'rolling_downgrade' should pass when valid version is given", tags: ["rolling_downgrade"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + retry_limit = 5 + retries = 1 + response_s = "" + until (/Passed/ =~ response_s) || retries > retry_limit + LOGGING.info "rolling_downgrade retry: #{retries}" + sleep 1.0 + response_s = `./cnf-conformance rolling_downgrade verbose` + retries = retries + 1 + end + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + it "'rolling_downgrade' should fail when invalid version is given", tags: ["rolling_downgrade"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance rolling_downgrade verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Failed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'rolling_downgrade' should pass if using local registry and a port", tags: ["rolling_downgrade"] do + begin + install_registry = `kubectl create -f #{TOOLS_DIR}/registry/manifest.yml` + install_dockerd = `kubectl create -f #{TOOLS_DIR}/dockerd/manifest.yml` + KubectlClient::Get.resource_wait_for_install("Pod", "registry") + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.6.7 registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.8.0 registry:5000/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.8.0") + + cnf="./sample-cnfs/sample_local_registry" + + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance rolling_update verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + delete_registry = `kubectl delete -f #{TOOLS_DIR}/registry/manifest.yml` + delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end + end + + it "'rolling_version_change' should pass when valid version is given", tags: ["rolling_version_change"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance rolling_version_change verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + it "'rolling_version_change' should fail when invalid version is given", tags: ["rolling_version_change"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance rolling_version_change verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Failed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_coredns_invalid_version/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'rolling_version_change' should pass if using local registry and a port", tags: ["rolling_version_change"] do + begin + install_registry = `kubectl create -f #{TOOLS_DIR}/registry/manifest.yml` + install_dockerd = `kubectl create -f #{TOOLS_DIR}/dockerd/manifest.yml` + KubectlClient::Get.resource_wait_for_install("Pod", "registry") + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.6.7 registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.8.0 registry:5000/coredns:1.8.0") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.8.0") + + cnf="./sample-cnfs/sample_local_registry" + + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance rolling_version_change verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + delete_registry = `kubectl delete -f #{TOOLS_DIR}/registry/manifest.yml` + delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end + end + + it "'rollback' should pass ", tags: ["rollback"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance rollback verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + # TODO: figure out failing test for rollback + + it "'nodeport_not_used' should fail when a node port is being used", tags: ["nodeport_not_used"] do + begin + `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_nodeport deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance nodeport_not_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: NodePort is being used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_nodeport deploy_with_chart=false` + end + end + + it "'nodeport_not_used' should pass when a node port is not being used", tags: ["nodeport_not_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance nodeport_not_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: NodePort is not used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + it "'ip_addresses' should pass when no uncommented ip addresses are found in helm chart source", tags: ["ip_addresses"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance ip_addresses verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: No IP addresses found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance sample_coredns_source_cleanup verbose` + end + end + + it "'hardcoded_ip_addresses_in_k8s_runtime_configuration' should fail when a hardcoded ip is found in the K8s configuration", tags: ["ip_addresses"] do + begin + `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_coredns_hardcoded_ips deploy_with_chart=false` + $?.success?.should be_true + response_s = `LOG_LEVEL=info ./cnf-conformance hardcoded_ip_addresses_in_k8s_runtime_configuration verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: Hard-coded IP addresses found in the runtime K8s configuration/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_coredns_hardcoded_ips deploy_with_chart=false` + end + end + + it "'hardcoded_ip_addresses_in_k8s_runtime_configuration' should pass when no ip addresses are found in the K8s configuration", tags: ["ip_addresses"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0` + $?.success?.should be_true + response_s = `./cnf-conformance hardcoded_ip_addresses_in_k8s_runtime_configuration verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: No hard-coded IP addresses found in the runtime K8s configuration/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cleanup_sample_coredns` + end + end + + it "'secrets_used' should pass when secrets are provided as volumes and used by a container", tags: ["secrets_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_secret_volume/cnf-conformance.yml verbose ` + $?.success?.should be_true + response_s = `./cnf-conformance secrets_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Secrets defined and used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_secret_volume verbose` + end + end + + it "'secrets_used' should fail when secrets are provided as volumes and not mounted by a container", tags: ["secrets_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_unmounted_secret_volume/cnf-conformance.yml verbose wait_count=0 ` + $?.success?.should be_true + response_s = `./cnf-conformance secrets_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/SKIPPED: Secrets not used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_unmounted_secret_volume verbose` + end + end + + it "'secrets_used' should pass when secrets are provided as environment variables and used by a container", tags: ["secrets_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_secret_env/cnf-conformance.yml verbose ` + $?.success?.should be_true + response_s = `./cnf-conformance secrets_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Secrets defined and used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_secret_env verbose` + end + end + + it "'secrets_used' should skip when secrets are not referenced as environment variables by a container", tags: ["secrets_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_secret_env_no_ref/cnf-conformance.yml verbose ` + $?.success?.should be_true + response_s = `./cnf-conformance secrets_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/SKIPPED: Secrets not used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_secret_env verbose` + end + end + + it "'secrets_used' should pass when no secret volumes are mounted or no container secrets are provided (secrets ignored)`", tags: ["secrets_used"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml verbose wait_count=0 ` + $?.success?.should be_true + response_s = `./cnf-conformance secrets_used verbose` + LOGGING.info response_s + $?.success?.should be_true + (/SKIPPED: Secrets not used/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_coredns verbose` + end + end + + # # 1. test 1 fails because the sample_coredns helm chart configmap is not immutable + # # 2. copay that sample_coredns cnf and and make the config map immutable rename it and make sure test passes + + it "'immutable_configmap' fail without immutable configmaps", tags: ["immutable_configmap"] do + begin + `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance immutable_configmap verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: Found mutable configmap/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'immutable_configmap' fail with only some immutable configmaps", tags: ["immutable_configmap"] do + begin + `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_coredns/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance immutable_configmap verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: Found mutable configmap/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_immutable_configmap_some/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'immutable_configmap' should pass with all immutable configmaps", tags: ["immutable_configmap"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance immutable_configmap verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: All volume or container mounted configmaps immutable/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml deploy_with_chart=false` + end + end + + + it "'immutable_configmap' should pass with all immutable configmaps with env mounted", tags: ["immutable_configmap_env"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_immutable_configmap_all_plus_env/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance immutable_configmap verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: All volume or container mounted configmaps immutable/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml deploy_with_chart=false` + end + end + + it "'immutable_configmap' should fail with a mutable env mounted configmap", tags: ["immutable_configmap_fail"] do + begin + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_immutable_configmap_all_plus_env_but_fail/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance immutable_configmap verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: Found mutable configmap/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-config=./sample-cnfs/sample_immutable_configmap_all/cnf-conformance.yml deploy_with_chart=false` + end + end +end diff --git a/spec/cpu_hog_spec.cr b/spec/workload/cpu_hog_spec.cr similarity index 86% rename from spec/cpu_hog_spec.cr rename to spec/workload/cpu_hog_spec.cr index e169adefa..9b382846c 100644 --- a/spec/cpu_hog_spec.cr +++ b/spec/workload/cpu_hog_spec.cr @@ -1,7 +1,7 @@ -require "./spec_helper" +require "../spec_helper" require "colorize" -require "../src/tasks/utils/utils.cr" -require "../src/tasks/utils/system_information/helm.cr" +require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/system_information/helm.cr" require "file_utils" require "sam" diff --git a/spec/installability_spec.cr b/spec/workload/installability_spec.cr similarity index 60% rename from spec/installability_spec.cr rename to spec/workload/installability_spec.cr index f2a52941b..f418f0f93 100644 --- a/spec/installability_spec.cr +++ b/spec/workload/installability_spec.cr @@ -1,81 +1,68 @@ -require "./spec_helper" +require "../spec_helper" require "colorize" describe CnfConformance do before_all do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - `./cnf-conformance samples_cleanup` $?.success?.should be_true - # `./cnf-conformance configuration_file_setup` LOGGING.info `./cnf-conformance setup` - # $?.success?.should be_true end - it "'install_script_helm' should fail if install script does not have helm", tags: "happy-path" do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - # `./cnf-conformance cleanup` - # $?.success?.should be_true - `./cnf-conformance sample_coredns_source_setup` + it "'install_script_helm' should fail if install script does not have helm", tags: ["helm"] do + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf-source/cnf-conformance.yml verbose wait_count=0` $?.success?.should be_true - response_s = `./cnf-conformance install_script_helm` - #LOGGING.info response_s + response_s = `./cnf-conformance install_script_helm` + LOGGING.info response_s $?.success?.should be_true - (/FAILURE: Helm not found in supplied install script/ =~ response_s).should_not be_nil + (/FAILED: Helm not found in supplied install script/ =~ response_s).should_not be_nil `./cnf-conformance sample_coredns_source_cleanup` end - it "'helm_deploy' should fail on a bad helm chart", tags: "helm" do - response_s = `./cnf-conformance helm_deploy cnf-config=sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml verbose` - $?.success?.should be_true + it "'helm_deploy' should fail on a bad helm chart", tags: ["helm"] do + response_s = `./cnf-conformance helm_deploy destructive cnf-config=sample-cnfs/sample-bad-helm-deploy-repo/cnf-conformance.yml verbose` LOGGING.info response_s - (/FAILURE: Helm deploy failed/ =~ response_s).should_not be_nil + $?.success?.should be_true + (/FAILED: Helm deploy failed/ =~ response_s).should_not be_nil end - it "'helm_deploy' should fail if command is not supplied cnf-config argument", tags: "helm" do - response_s = `./cnf-conformance helm_deploy` + it "'helm_deploy' should fail if command is not supplied cnf-config argument", tags: ["helm"] do + response_s = `./cnf-conformance helm_deploy destructive` LOGGING.info response_s $?.success?.should be_true (/No cnf_conformance.yml found! Did you run the setup task/ =~ response_s).should_not be_nil end - it "'helm_deploy' should pass if command is supplied cnf-config argument with helm_chart declared", tags: ["helm", "happy-path"] do - response_s = `./cnf-conformance helm_deploy cnf-config=sample-cnfs/sample_coredns/cnf-conformance.yml verbose` + it "'helm_deploy' should pass if command is supplied cnf-config argument with helm_chart declared", tags: ["helm"] do + response_s = `./cnf-conformance helm_deploy destructive cnf-config=sample-cnfs/sample_coredns/cnf-conformance.yml verbose` $?.success?.should be_true LOGGING.info response_s (/PASSED: Helm deploy successful/ =~ response_s).should_not be_nil end - it "'helm_deploy' should pass if command is supplied cnf-config argument without helm_chart declared", tags: ["helm", "happy-path"] do - response_s = `./cnf-conformance helm_deploy cnf-config=sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml verbose` + it "'helm_deploy' should pass if command is supplied cnf-config argument without helm_chart declared", tags: ["helm"] do + response_s = `./cnf-conformance helm_deploy destructive cnf-config=sample-cnfs/sample_coredns_chart_directory/cnf-conformance.yml verbose` $?.success?.should be_true LOGGING.info response_s (/PASSED: Helm deploy successful/ =~ response_s).should_not be_nil end - it "'helm_chart_valid' should pass on a good helm chart", tags: "happy-path" do - # LOGGING.debug `pwd` - # LOGGING.debug `echo $KUBECONFIG` - # `./cnf-conformance cleanup` - # $?.success?.should be_true - `./cnf-conformance sample_coredns_setup` + it "'helm_chart_valid' should pass on a good helm chart", tags: ["helm"] do + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose wait_count=0` $?.success?.should be_true - response_s = `./cnf-conformance helm_chart_valid` + response_s = `./cnf-conformance helm_chart_valid verbose` LOGGING.info response_s $?.success?.should be_true (/Lint Passed/ =~ response_s).should_not be_nil end - it "'helm_chart_valid' should fail on a bad helm chart" do + it "'helm_chart_valid' should fail on a bad helm chart", tags: ["helm"] do # LOGGING.debug `pwd` # LOGGING.debug `echo $KUBECONFIG` begin `./cnf-conformance sample_coredns_cleanup force=true` $?.success?.should be_true - `./cnf-conformance bad_helm_cnf_setup` + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-bad_helm_coredns-cnf/cnf-conformance.yml verbose wait_count=0` $?.success?.should be_true response_s = `./cnf-conformance helm_chart_valid` LOGGING.info response_s @@ -83,11 +70,11 @@ describe CnfConformance do (/Lint Failed/ =~ response_s).should_not be_nil ensure `./cnf-conformance bad_helm_cnf_cleanup force=true` - `./cnf-conformance sample_coredns_setup` + `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose wait_count=0` end end - it "'helm_chart_published' should pass on a good helm chart repo", tags: ["helm_chart_published","happy-path"] do + it "'helm_chart_published' should pass on a good helm chart repo", tags: ["helm_chart_published"] do begin `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-coredns-cnf` $?.success?.should be_true @@ -100,22 +87,21 @@ describe CnfConformance do end end - it "'helm_chart_published' should fail on a bad helm chart repo", tags: "helm_chart_published" do + it "'helm_chart_published' should fail on a bad helm chart repo", tags: ["helm_chart_published"] do begin LOGGING.info "search command: #{`helm search repo stable/coredns`}" # LOGGING.info `#{CNFSingleton.helm} repo remove stable` # LOGGING.info "search command: #{`helm search repo stable/coredns`}" - LOGGING.info `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-bad-helm-repo wait-time=5 verbose` + LOGGING.info `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-bad-helm-repo wait_count=0` $?.success?.should be_true LOGGING.info "search command: #{`helm search repo stable/coredns`}" response_s = `./cnf-conformance helm_chart_published verbose` LOGGING.info response_s $?.success?.should be_true - (/FAILURE: Published Helm Chart Not Found/ =~ response_s).should_not be_nil + (/FAILED: Published Helm Chart Not Found/ =~ response_s).should_not be_nil ensure `#{CNFSingleton.helm} repo remove badrepo` `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample-bad-helm-repo` end end - end diff --git a/spec/workload/microservice_spec.cr b/spec/workload/microservice_spec.cr new file mode 100644 index 000000000..e3579073d --- /dev/null +++ b/spec/workload/microservice_spec.cr @@ -0,0 +1,137 @@ +require "../spec_helper" +require "colorize" +require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/kubectl_client.cr" +require "../../src/tasks/utils/system_information/helm.cr" +require "../../src/tasks/dockerd_setup.cr" +require "file_utils" +require "sam" + +describe "Microservice" do + before_all do + # LOGGING.debug `pwd` + # LOGGING.debug `echo $KUBECONFIG` + `./cnf-conformance samples_cleanup force=true` + $?.success?.should be_true + `./cnf-conformance configuration_file_setup` + # `./cnf-conformance setup` + # $?.success?.should be_true + end + + it "'reasonable_startup_time' should pass if the cnf has a reasonable startup time(helm_directory)", tags: ["reasonable_startup_time"] do + begin + response_s = `./cnf-conformance reasonable_startup_time destructive cnf-config=sample-cnfs/sample_coredns/cnf-conformance.yml` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: CNF had a reasonable startup time/ =~ response_s).should_not be_nil + ensure + `kubectl delete -f sample-cnfs/sample_coredns/reasonable_startup_orig.yml` + `./cnf-conformance samples_cleanup force=true` + $?.success?.should be_true + end + end + + it "'reasonable_startup_time' should fail if the cnf doesn't has a reasonable startup time(helm_directory)", tags: ["reasonable_startup_time"] do + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml force=true` + `kubectl delete -f sample-cnfs/sample_envoy_slow_startup/reasonable_startup_orig.yml` + begin + response_s = `./cnf-conformance reasonable_startup_time destructive cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml verbose` + LOGGING.info response_s + $?.success?.should be_true + (/FAILED: CNF had a startup time of/ =~ response_s).should_not be_nil + ensure + `kubectl delete -f sample-cnfs/sample_envoy_slow_startup/reasonable_startup_orig.yml` + $?.success?.should be_true + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample_envoy_slow_startup/cnf-conformance.yml force=true` + $?.success?.should be_true + end + end + + it "'reasonable_image_size' should pass if image is smaller than 5gb", tags: ["reasonable_image_size"] do + if ENV["PROTECTED_DOCKERHUB_USERNAME"]? && ENV["PROTECTED_DOCKERHUB_PASSWORD"]? && ENV["PROTECTED_DOCKERHUB_EMAIL"]? + cnf="./sample-cnfs/sample_coredns_protected" + else + cnf="./sample-cnfs/sample-coredns-cnf" + end + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance reasonable_image_size verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Image size is good/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + end + + it "'reasonable_image_size' should fail if image is larger than 5gb", tags: ["reasonable_image_size"] do + `./cnf-conformance cnf_setup cnf-path=./sample-cnfs/sample_envoy_slow_startup wait_count=0` + response_s = `./cnf-conformance reasonable_image_size verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Image size too large/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_envoy_slow_startup force=true` + end + + it "'reasonable_image_size' should skip if dockerd does not install", tags: ["reasonable_image_size"] do + cnf="./sample-cnfs/sample-coredns-cnf" + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + LOGGING.info `./cnf-conformance uninstall_dockerd` + dockerd_tempname_helper + + response_s = `./cnf-conformance reasonable_image_size verbose` + LOGGING.info response_s + $?.success?.should be_true + (/SKIPPED: Skipping reasonable_image_size: Dockerd tool failed to install/ =~ response_s).should_not be_nil + ensure + LOGGING.info "reasonable_image_size skipped ensure" + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + dockerd_name_helper + LOGGING.info `./cnf-conformance install_dockerd` + end + + + it "'reasonable_image_size' should pass if using local registry and a port", tags: ["private_registry"] do + install_registry = `kubectl create -f #{TOOLS_DIR}/registry/manifest.yml` + install_dockerd = `kubectl create -f #{TOOLS_DIR}/dockerd/manifest.yml` + KubectlClient::Get.resource_wait_for_install("Pod", "registry") + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.6.7 registry:5000/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns:1.6.7") + + cnf="./sample-cnfs/sample_local_registry" + + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance reasonable_image_size verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Image size is good/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + delete_registry = `kubectl delete -f #{TOOLS_DIR}/registry/manifest.yml` + delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end + + it "'reasonable_image_size' should pass if using local registry, a port and an org", tags: ["private_registry"] do + + install_registry = `kubectl create -f #{TOOLS_DIR}/registry/manifest.yml` + install_dockerd = `kubectl create -f #{TOOLS_DIR}/dockerd/manifest.yml` + KubectlClient::Get.resource_wait_for_install("Pod", "registry") + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd") + KubectlClient.exec("dockerd -ti -- docker pull coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker tag coredns/coredns:1.6.7 registry:5000/coredns/coredns:1.6.7") + KubectlClient.exec("dockerd -ti -- docker push registry:5000/coredns/coredns:1.6.7") + + cnf="./sample-cnfs/sample_local_registry_org_image" + + LOGGING.info `./cnf-conformance cnf_setup cnf-path=#{cnf}` + response_s = `./cnf-conformance reasonable_image_size verbose` + LOGGING.info response_s + $?.success?.should be_true + (/Image size is good/ =~ response_s).should_not be_nil + ensure + LOGGING.info `./cnf-conformance cnf_cleanup cnf-path=#{cnf}` + delete_registry = `kubectl delete -f #{TOOLS_DIR}/registry/manifest.yml` + delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end +end diff --git a/spec/workload/resilience/container_chaos_spec.cr b/spec/workload/resilience/container_chaos_spec.cr new file mode 100644 index 000000000..5df3cc09b --- /dev/null +++ b/spec/workload/resilience/container_chaos_spec.cr @@ -0,0 +1,43 @@ +require "../../spec_helper" +require "colorize" +require "../../../src/tasks/utils/utils.cr" +require "../../../src/tasks/utils/system_information/helm.cr" +require "file_utils" +require "sam" + +describe "Resilience Container Chaos" do + before_all do + `./cnf-conformance setup` + `./cnf-conformance configuration_file_setup` + $?.success?.should be_true + end + + it "'chaos_container_kill' A 'Good' CNF should recover when its container is killed", tags: ["chaos_container_kill"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + response_s = `./cnf-conformance chaos_container_kill verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Replicas available match desired count after container kill test/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + end + end + + # TODO upgrade chaos mesh + # it "'chaos_container_kill' A 'Bad' CNF should NOT recover when its container is killed", tags: ["chaos_container_kill"] do + # begin + # `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample-fragile-state deploy_with_chart=false` + # $?.success?.should be_true + # response_s = `./cnf-conformance chaos_container_kill verbose` + # LOGGING.info response_s + # $?.success?.should be_true + # (/FAILED: Replicas did not return desired count after container kill test/ =~ response_s).should_not be_nil + # ensure + # `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample-fragile-state deploy_with_chart=false` + # $?.success?.should be_true + # end + # end +end diff --git a/spec/workload/resilience/disk_fill_spec.cr b/spec/workload/resilience/disk_fill_spec.cr new file mode 100644 index 000000000..88af6573e --- /dev/null +++ b/spec/workload/resilience/disk_fill_spec.cr @@ -0,0 +1,30 @@ +require "../../spec_helper" +require "colorize" +require "../../../src/tasks/utils/utils.cr" +require "../../../src/tasks/utils/system_information/helm.cr" +require "file_utils" +require "sam" + +describe "Resilience Disk Fill Chaos" do + before_all do + `./cnf-conformance setup` + `./cnf-conformance configuration_file_setup` + $?.success?.should be_true + end + + it "'disk_fill' A 'Good' CNF should not crash when disk fill occurs", tags: ["disk_fill"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + response_s = `./cnf-conformance disk_fill verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: disk_fill chaos test passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + `./cnf-conformance uninstall_litmus` + $?.success?.should be_true + end + end +end diff --git a/spec/workload/resilience/network_chaos_spec.cr b/spec/workload/resilience/network_chaos_spec.cr new file mode 100644 index 000000000..4b380fa3e --- /dev/null +++ b/spec/workload/resilience/network_chaos_spec.cr @@ -0,0 +1,43 @@ +require "../../spec_helper" +require "colorize" +require "../../../src/tasks/utils/utils.cr" +require "../../../src/tasks/utils/system_information/helm.cr" +require "file_utils" +require "sam" + +describe "Resilience Network Chaos" do + before_all do + `./cnf-conformance setup` + `./cnf-conformance configuration_file_setup` + $?.success?.should be_true + end + + it "'chaos_network_loss' A 'Good' CNF should not crash when network loss occurs", tags: ["chaos_network_loss"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + response_s = `./cnf-conformance chaos_network_loss verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Replicas available match desired count after network chaos test/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + end + end + + #TODO upgrade chaos mesh + # it "'chaos_network_loss' A 'Bad' CNF should crash when network loss occurs", tags: ["chaos_network_loss"] do + # begin + # `./cnf-conformance cnf_setup cnf-path=sample-cnfs/sample_network_loss deploy_with_chart=false wait_count=60` + # $?.success?.should be_true + # response_s = `./cnf-conformance chaos_network_loss verbose` + # LOGGING.info response_s + # $?.success?.should be_true + # (/FAILED: Replicas did not return desired count after network chaos test/ =~ response_s).should_not be_nil + # ensure + # `./cnf-conformance cnf_cleanup cnf-path=sample-cnfs/sample_network_loss deploy_with_chart=false` + # $?.success?.should be_true + # end + # end +end diff --git a/spec/workload/resilience/pod_network_latency_spec.cr b/spec/workload/resilience/pod_network_latency_spec.cr new file mode 100644 index 000000000..2c808961a --- /dev/null +++ b/spec/workload/resilience/pod_network_latency_spec.cr @@ -0,0 +1,30 @@ +require "../../spec_helper" +require "colorize" +require "../../../src/tasks/utils/utils.cr" +require "../../../src/tasks/utils/system_information/helm.cr" +require "file_utils" +require "sam" + +describe "Resilience Pod Network Latency Chaos" do + before_all do + `./cnf-conformance setup` + `./cnf-conformance configuration_file_setup` + $?.success?.should be_true + end + + it "'pod_network_latency' A 'Good' CNF should not crash when network latency occurs", tags: ["pod_network_latency"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + response_s = `./cnf-conformance pod_network_latency verbose` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: pod_network_latency chaos test passed/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + `./cnf-conformance uninstall_litmus` + $?.success?.should be_true + end + end +end diff --git a/spec/workload/scalability_spec.cr b/spec/workload/scalability_spec.cr new file mode 100644 index 000000000..f955740d4 --- /dev/null +++ b/spec/workload/scalability_spec.cr @@ -0,0 +1,29 @@ +require "../spec_helper" +require "../../src/tasks/utils/utils.cr" +require "colorize" + +describe "Scalability" do + before_all do + `./cnf-conformance setup` + $?.success?.should be_true + end + + after_all do + `./cnf-conformance samples_cleanup` + $?.success?.should be_true + end + +it "'scalability' should run all of the scalability tests", tags: "[scalability]" do + `./cnf-conformance samples_cleanup` + response_s = `./cnf-conformance setup` + LOGGING.info response_s + # `./cnf-conformance sample_coredns_with_wait_setup` + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample-coredns-cnf/cnf-conformance.yml verbose` + $?.success?.should be_true + response_s = `./cnf-conformance scalability` + LOGGING.info response_s + $?.success?.should be_true + (/PASSED: Replicas increased to 3/ =~ response_s).should_not be_nil + (/PASSED: Replicas decreased to 1/ =~ response_s).should_not be_nil + end +end diff --git a/spec/security_spec.cr b/spec/workload/security_spec.cr similarity index 67% rename from spec/security_spec.cr rename to spec/workload/security_spec.cr index 717cdbead..16a7cc459 100644 --- a/spec/security_spec.cr +++ b/spec/workload/security_spec.cr @@ -1,6 +1,6 @@ -require "./spec_helper" +require "../spec_helper" require "colorize" -require "../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/utils.cr" describe CnfConformance do before_all do @@ -12,21 +12,20 @@ describe CnfConformance do # `./cnf-conformance setup` # $?.success?.should be_true end - it "'privileged' should pass with a non-privileged cnf", tags: ["privileged", "happy-path"] do + it "'privileged' should pass with a non-privileged cnf", tags: ["privileged"] do begin - `./cnf-conformance sample_coredns_setup` - $?.success?.should be_true - response_s = `./cnf-conformance privileged cnf-config=sample-cnfs/sample-coredns-cnf verbose` + LOGGING.debug `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml` + response_s = `./cnf-conformance privileged verbose` LOGGING.info response_s $?.success?.should be_true (/Found.*privileged containers.*coredns/ =~ response_s).should be_nil ensure - `./cnf-conformance sample_coredns_cleanup` + LOGGING.debug `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-statefulset-cnf/cnf-conformance.yml` end end - it "'privileged' should fail on a non-whitelisted, privileged cnf", tags: "privileged" do + it "'privileged' should fail on a non-whitelisted, privileged cnf", tags: ["privileged"] do begin - `./cnf-conformance sample_privileged_cnf_non_whitelisted_setup` + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_privileged_cnf/cnf-conformance.yml verbose wait_count=0` $?.success?.should be_true response_s = `./cnf-conformance privileged cnf-config=sample-cnfs/sample_privileged_cnf verbose` LOGGING.info response_s @@ -36,9 +35,9 @@ describe CnfConformance do `./cnf-conformance sample_privileged_cnf_non_whitelisted_cleanup` end end - it "'privileged' should pass on a whitelisted, privileged cnf", tags: "privileged" do + it "'privileged' should pass on a whitelisted, privileged cnf", tags: ["privileged"] do begin - `./cnf-conformance sample_privileged_cnf_whitelisted_setup` + LOGGING.info `./cnf-conformance cnf_setup cnf-config=./sample-cnfs/sample_whitelisted_privileged_cnf/cnf-conformance.yml verbose wait_count=0` $?.success?.should be_true response_s = `./cnf-conformance privileged cnf-config=sample-cnfs/sample_whitelisted_privileged_cnf verbose` LOGGING.info response_s diff --git a/spec/workload/statelessness_spec.cr b/spec/workload/statelessness_spec.cr new file mode 100644 index 000000000..3822761da --- /dev/null +++ b/spec/workload/statelessness_spec.cr @@ -0,0 +1,67 @@ +require "../spec_helper" +require "colorize" +require "../../src/tasks/utils/utils.cr" +require "../../src/tasks/utils/kubectl_client.cr" +require "../../src/tasks/utils/system_information/helm.cr" +require "file_utils" +require "sam" + +describe "Statelessness" do + before_all do + `./cnf-conformance configuration_file_setup` + end + + it "'volume_hostpath_not_found' should pass if the cnf doesn't have a hostPath volume", tags: ["volume_hostpath_not_found"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + response_s = `./cnf-conformance volume_hostpath_not_found verbose` + LOGGING.info "Status: #{response_s}" + (/PASSED: hostPath volumes not found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml` + $?.success?.should be_true + end + end + + it "'volume_hostpath_not_found' should fail if the cnf has a hostPath volume", tags: ["volume_hostpath_not_found"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-fragile-state/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + response_s = `./cnf-conformance volume_hostpath_not_found verbose` + LOGGING.info "Status: #{response_s}" + (/FAILED: hostPath volumes found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-fragile-state/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + end + end + it "'no_local_volume_configuration' should fail if local storage configuration found", tags: ["no_local_volume_configuration"] do + begin + # update the helm parameter with a schedulable node for the pv chart + schedulable_nodes = KubectlClient::Get.schedulable_nodes + update_yml("sample-cnfs/sample-local-storage/cnf-conformance.yml", "release_name", "coredns --set worker_node='#{schedulable_nodes[0]}'") + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-local-storage/cnf-conformance.yml verbose` + $?.success?.should be_true + response_s = `./cnf-conformance no_local_volume_configuration verbose` + LOGGING.info "Status: #{response_s}" + (/FAILED: local storage configuration volumes found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-local-storage/cnf-conformance.yml deploy_with_chart=false` + update_yml("sample-cnfs/sample-local-storage/cnf-conformance.yml", "release_name", "coredns") + $?.success?.should be_true + end + end + it "'no_local_volume_configuration' should pass if local storage configuration is not found", tags: ["no_local_volume_configuration"] do + begin + `./cnf-conformance cnf_setup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml wait_count=0 verbose` + $?.success?.should be_true + response_s = `./cnf-conformance no_local_volume_configuration verbose` + LOGGING.info "Status: #{response_s}" + (/PASSED: local storage configuration volumes not found/ =~ response_s).should_not be_nil + ensure + `./cnf-conformance cnf_cleanup cnf-config=sample-cnfs/sample-coredns-cnf/cnf-conformance.yml deploy_with_chart=false` + $?.success?.should be_true + end + end +end diff --git a/src/cnf-conformance.cr b/src/cnf-conformance.cr index 30768341f..7812e5553 100644 --- a/src/cnf-conformance.cr +++ b/src/cnf-conformance.cr @@ -9,37 +9,44 @@ desc "The CNF Conformance program enables interoperability of CNFs from multiple task "all", ["workload", "platform"] do |_, args| VERBOSE_LOGGING.info "all" if check_verbose(args) - # TODO make a workload and a platform total points - total = total_points + total = CNFManager::Points.total_points if total > 0 - stdout_success "Final score: #{total} of #{total_max_points}" + stdout_success "Final score: #{total} of #{CNFManager::Points.total_max_points}" else - stdout_failure "Final score: #{total} of #{total_max_points}" + stdout_failure "Final score: #{total} of #{CNFManager::Points.total_max_points}" end - if failed_required_tasks.size > 0 + if CNFManager::Points.failed_required_tasks.size > 0 stdout_failure "Conformance Suite failed!" - stdout_failure "Failed required tasks: #{failed_required_tasks.inspect}" + stdout_failure "Failed required tasks: #{CNFManager::Points.failed_required_tasks.inspect}" end - stdout_info "Results have been saved to #{Results.file}".colorize(:green) + stdout_info "CNFManager::Points::Results.have been saved to #{CNFManager::Points::Results.file}".colorize(:green) end desc "The CNF Conformance program enables interoperability of CNFs from multiple vendors running on top of Kubernetes supplied by different vendors. The goal is to provide an open source test suite to enable both open and closed source CNFs to demonstrate conformance and implementation of best practices." -task "workload", ["all_prereqs", "configuration_file_setup", "compatibility","statelessness", "security", "scalability", "configuration_lifecycle", "observability", "installability", "hardware_affinity", "microservice", "resilience"] do |_, args| - VERBOSE_LOGGING.info "all" if check_verbose(args) +task "workload", ["automatic_cnf_install", "ensure_cnf_installed", "configuration_file_setup", "compatibility","statelessness", "security", "scalability", "configuration_lifecycle", "observability", "installability", "hardware_and_scheduling", "microservice", "resilience"] do |_, args| + VERBOSE_LOGGING.info "workload" if check_verbose(args) - total = total_points("workload") + total = CNFManager::Points.total_points("workload") if total > 0 - stdout_success "Final workload score: #{total} of #{total_max_points("workload")}" + stdout_success "Final workload score: #{total} of #{CNFManager::Points.total_max_points("workload")}" else - stdout_failure "Final workload score: #{total} of #{total_max_points("workload")}" + stdout_failure "Final workload score: #{total} of #{CNFManager::Points.total_max_points("workload")}" end - if failed_required_tasks.size > 0 + if CNFManager::Points.failed_required_tasks.size > 0 stdout_failure "Conformance Suite failed!" - stdout_failure "Failed required tasks: #{failed_required_tasks.inspect}" + stdout_failure "Failed required tasks: #{CNFManager::Points.failed_required_tasks.inspect}" + end + stdout_info "CNFManager::Points::Results.have been saved to #{CNFManager::Points::Results.file}".colorize(:green) +end + +desc "Makes sure a cnf is in the cnf directory" +task "ensure_cnf_installed" do |_, args| + unless CNFManager.cnf_installed? + puts "You must install a CNF first.".colorize(:yellow) + exit 1 end - stdout_info "Results have been saved to #{Results.file}".colorize(:green) end task "version" do |_, args| @@ -57,9 +64,11 @@ task "upsert_release" do |_, args| end end -task "all_prereqs" do |_, args| +task "automatic_cnf_install" do |_, args| VERBOSE_LOGGING.info "all_prereqs" if check_verbose(args) - check_cnf_config_then_deploy(args) + # check_cnf_config_then_deploy(args) + cli_hash = CNFManager.sample_setup_cli_args(args, false) + CNFManager.sample_setup(cli_hash) if !cli_hash["config_file"].empty? end task "test" do @@ -73,7 +82,7 @@ end # https://www.thegeekstuff.com/2013/12/bash-completion-complete/ # https://kubernetes.io/docs/tasks/tools/install-kubectl/#enable-kubectl-autocompletion # https://stackoverflow.com/questions/43794270/disable-or-unset-specific-bash-completion -desc "Install Shell Completion: check https://github.com/cncf/cnf-conformance/blob/master/USAGE.md for usage" +desc "Install Shell Completion: check https://github.com/cncf/cnf-conformance/blob/main/USAGE.md for usage" task "completion" do |_| # assumes bash completion feel free to make a pr for zsh and check an arg for it @@ -88,4 +97,22 @@ TEMPLATE puts completion_template end -Sam.help +# Sam.help +begin + puts `./cnf-conformance help` if ARGV.empty? + # See issue #426 for exit code requirement + Sam.process_tasks(ARGV.clone) + yaml = File.open("#{CNFManager::Points::Results.file}") do |file| + YAML.parse(file) + end + LOGGING.debug "results yaml: #{yaml}" + if (yaml["exit_code"]) == 1 + exit 1 + end +rescue e : Sam::NotFound + puts e.message + exit 1 +rescue e + puts e.backtrace.join("\n"), e + exit 1 +end diff --git a/src/tasks/chaos_mesh_setup.cr b/src/tasks/chaos_mesh_setup.cr index 5f3c2afa7..051e93363 100644 --- a/src/tasks/chaos_mesh_setup.cr +++ b/src/tasks/chaos_mesh_setup.cr @@ -20,9 +20,12 @@ task "install_chaosmesh" do |_, args| checkout_tag = `cd #{current_dir}/#{TOOLS_DIR}/chaos_mesh && git checkout tags/#{CHAOS_MESH_VERSION} && cd -` end install_chaos_mesh = `#{helm} install chaos-mesh #{current_dir}/#{TOOLS_DIR}/chaos_mesh/helm/chaos-mesh --set chaosDaemon.runtime=containerd --set chaosDaemon.socketPath=/run/containerd/containerd.sock` - wait_for_resource("#{current_dir}/spec/fixtures/chaos_network_loss.yml") - wait_for_resource("#{current_dir}/spec/fixtures/chaos_cpu_hog.yml") - wait_for_resource("#{current_dir}/spec/fixtures/chaos_container_kill.yml") + File.write("chaos_network_loss.yml", CHAOS_NETWORK_LOSS) + File.write("chaos_cpu_hog.yml", CHAOS_CPU_HOG) + File.write("chaos_container_kill.yml", CHAOS_CONTAINER_KILL) + ChaosMeshSetup.wait_for_resource("chaos_network_loss.yml") + ChaosMeshSetup.wait_for_resource("chaos_cpu_hog.yml") + ChaosMeshSetup.wait_for_resource("chaos_container_kill.yml") end desc "Uninstall Chaos Mesh" @@ -36,57 +39,54 @@ task "uninstall_chaosmesh" do |_, args| delete_chaos_mesh = `#{helm} delete chaos-mesh` end -def wait_for_test(test_type, test_name) - second_count = 0 - wait_count = 60 - status = "" - until (status.empty? != true && status == "Finished") || second_count > wait_count.to_i - LOGGING.debug "second_count = #{second_count}" - sleep 1 - get_status = `kubectl get "#{test_type}" "#{test_name}" -o yaml` - LOGGING.info("#{get_status}") - status_data = Totem.from_yaml("#{get_status}") - LOGGING.info "Status: #{get_status}" - LOGGING.debug("#{status_data}") - status = status_data.get("status").as_h["experiment"].as_h["phase"].as_s - second_count = second_count + 1 - LOGGING.info "#{get_status}" - LOGGING.info "#{second_count}" - end - # Did chaos mesh finish the test successfully - (status.empty? !=true && status == "Finished") -end +module ChaosMeshSetup -def desired_is_available?(deployment_name) - resp = `kubectl get deployments #{deployment_name} -o=yaml` - describe = Totem.from_yaml(resp) - LOGGING.info("desired_is_available describe: #{describe.inspect}") - desired_replicas = describe.get("status").as_h["replicas"].as_i - LOGGING.info("desired_is_available desired_replicas: #{desired_replicas}") - ready_replicas = describe.get("status").as_h["readyReplicas"]? - unless ready_replicas.nil? - ready_replicas = ready_replicas.as_i - else - ready_replicas = 0 + def self.wait_for_test(test_type, test_name) + second_count = 0 + wait_count = 60 + status = "" + until (status.empty? != true && status == "Finished") || second_count > wait_count.to_i + LOGGING.debug "second_count = #{second_count}" + sleep 1 + LOGGING.info "kubectl get #{test_type} #{test_name} -o json" + status = Process.run("kubectl get #{test_type} #{test_name} -o json ", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.info "KubectlClient.exec output: #{output.to_s}" + LOGGING.info "KubectlClient.exec stderr: #{stderr.to_s}" + get_status = output.to_s + if get_status && !get_status.empty? + status_data = JSON.parse(get_status) + else + status_data = JSON.parse(%({})) + end + LOGGING.info "Status: #{get_status}" + status = status_data.dig?("status", "experiment", "phase").to_s + second_count = second_count + 1 + LOGGING.info "#{get_status}" + LOGGING.info "#{second_count}" + end + # Did chaos mesh finish the test successfully + # (status.empty? !=true && status == "Finished") + true end - LOGGING.info("desired_is_available ready_replicas: #{ready_replicas}") - - desired_replicas == ready_replicas -end -def wait_for_resource(resource_file) - second_count = 0 - wait_count = 60 - is_resource_created = nil - until (is_resource_created.nil? != true && is_resource_created == true) || second_count > wait_count.to_i - LOGGING.info "second_count = #{second_count}" - sleep 3 - `kubectl create -f #{resource_file} 2>&1 >/dev/null` - is_resource_created = $?.success? - LOGGING.info "Waiting for CRD" - LOGGING.info "Status: #{is_resource_created}" - LOGGING.debug "resource file: #{resource_file}" - second_count = second_count + 1 + # TODO make generate without delete? + def self.wait_for_resource(resource_file) + second_count = 0 + wait_count = 60 + is_resource_created = nil + until (is_resource_created.nil? != true && is_resource_created == true) || second_count > wait_count.to_i + LOGGING.info "second_count = #{second_count}" + sleep 3 + `kubectl create -f #{resource_file} 2>&1 >/dev/null` + is_resource_created = $?.success? + LOGGING.info "Waiting for CRD" + LOGGING.info "Status: #{is_resource_created}" + LOGGING.debug "resource file: #{resource_file}" + second_count = second_count + 1 + end + `kubectl delete -f #{resource_file}` end - `kubectl delete -f #{resource_file}` end diff --git a/src/tasks/cleanup.cr b/src/tasks/cleanup.cr index 6c4139b38..19492496f 100644 --- a/src/tasks/cleanup.cr +++ b/src/tasks/cleanup.cr @@ -5,7 +5,7 @@ require "totem" desc "Cleans up the CNF Conformance test suite, the K8s cluster, and upstream projects" # task "cleanup", ["samples_cleanup", "results_yml_cleanup"] do |_, args| -task "cleanup", ["samples_cleanup", "uninstall_chaosmesh"] do |_, args| +task "cleanup", ["samples_cleanup"] do |_, args| end desc "Cleans up the CNF Conformance sample projects" @@ -28,15 +28,17 @@ task "samples_cleanup", ["sample_coredns_cleanup", "cleanup_sample_coredns", "ba end end -task "tools_cleanup", ["helm_local_cleanup", "sonobuoy_cleanup"] do |_, args| +desc "Cleans up the CNF Conformance helper tools and containers" +task "tools_cleanup", ["helm_local_cleanup", "sonobuoy_cleanup", "uninstall_chaosmesh","uninstall_litmus", "uninstall_dockerd"] do |_, args| end -task "cleanup_all", ["cleanup_samples", "tools_cleanup"] do |_, args| +desc "Cleans up the CNF Conformance sample projects, helper tools, and containers" +task "cleanup_all", ["samples_cleanup", "tools_cleanup"] do |_, args| end task "results_yml_cleanup" do |_, args| - if File.exists?("#{Results.file}") - rm = `rm #{Results.file}` + if File.exists?("#{CNFManager::Points::Results.file}") + rm = `rm #{CNFManager::Points::Results.file}` VERBOSE_LOGGING.info rm if check_verbose(args) end end diff --git a/src/tasks/cluster_api_setup.cr b/src/tasks/cluster_api_setup.cr new file mode 100644 index 000000000..231db2798 --- /dev/null +++ b/src/tasks/cluster_api_setup.cr @@ -0,0 +1,77 @@ +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "http/client" +require "halite" +require "./utils/utils.cr" + +desc "Install Cluster API for Kind" +task "cluster_api_setup" do |_, args| + current_dir = FileUtils.pwd + cluster_api_dir = "#{current_dir}/#{TOOLS_DIR}/cluster-api"; + + # `curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.3.10/clusterctl-linux-amd64 -o clusterctl` + Halite.follow.get("https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.3.10/clusterctl-linux-amd64") do |response| + LOGGING.info "clusterctl response: #{response}" + File.write("clusterctl", response.body_io) + end + LOGGING.info `sudo chmod +x ./clusterctl` + LOGGING.info `sudo mv ./clusterctl /usr/local/bin/clusterctl` + + unless Dir.exists?(cluster_api_dir) + LOGGING.info `git clone https://github.com/kubernetes-sigs/cluster-api --depth 1 --branch v0.3.10 "#{cluster_api_dir}"` + end + FileUtils.cd(cluster_api_dir) + File.write("clusterctl-settings.json", +<<-EOF +{"providers": ["cluster-api","bootstrap-kubeadm","control-plane-kubeadm", "infrastructure-docker"]} +EOF + ) + `./cmd/clusterctl/hack/create-local-repository.py` + File.write("clusterctl.yaml", +<<-EOF +providers: + - name: docker + url: #{Path["~"].expand(home: true)}/.cluster-api/dev-repository/infrastructure-docker/v0.3.8/infrastructure-components.yaml + type: InfrastructureProvider +EOF + ) + + + test = `clusterctl init --core cluster-api:v0.3.8 --bootstrap kubeadm:v0.3.8 --control-plane kubeadm:v0.3.8 --infrastructure docker:v0.3.8 --config #{FileUtils.pwd}/clusterctl.yaml` + LOGGING.info test + + ## TODO: wait here for crds to be created if needed +create_capd_response =` +CNI_RESOURCES="$(cat test/e2e/data/cni/kindnet/kindnet.yaml)" \ +DOCKER_POD_CIDRS="192.168.0.0/16" \ +DOCKER_SERVICE_CIDRS="172.17.0.0/16" \ +DOCKER_SERVICE_DOMAIN="cluster.local" \ +clusterctl config cluster capd --kubernetes-version v1.17.5 \ +--from https://github.com/kubernetes-sigs/cluster-api/blob/v0.3.9/test/e2e/data/infrastructure-docker/cluster-template.yaml \ +--target-namespace default \ +--control-plane-machine-count=1 \ +--worker-machine-count=2 +` + + LOGGING.info create_capd_response + + File.write("capd.yaml", create_capd_response) + + KubectlClient::Get.wait_for_install_by_apply("capd.yaml") + + LOGGING.info `kubectl apply -f capd.yaml` + LOGGING.info "cluster api setup complete" +end + +desc "Cleanup Cluster API" +task "cluster_api_cleanup" do |_, args| + current_dir = FileUtils.pwd + cluster_api_dir = "#{current_dir}/#{TOOLS_DIR}/cluster-api" + `kubectl delete -f #{cluster_api_dir}/capd.yaml` + `clusterctl delete --all --include-crd --include-namespace --config #{cluster_api_dir}/clusterctl.yaml` + `rm -rf #{current_dir}/#{TOOLS_DIR}/cluster-api` + +end + diff --git a/src/tasks/cnf_setup.cr b/src/tasks/cnf_setup.cr index 8b8ffebf5..4ba7a4277 100644 --- a/src/tasks/cnf_setup.cr +++ b/src/tasks/cnf_setup.cr @@ -4,79 +4,11 @@ require "colorize" require "totem" require "./utils/utils.cr" -desc "Sets up sample CoreDNS CNF" -task "sample_coredns_setup", ["helm_local_install"] do |_, args| - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-coredns-cnf", args: args, verbose: true, wait_count: 0 ) -end - -task "sample_coredns_with_wait_setup", ["helm_local_install"] do |_, args| - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-coredns-cnf", args: args, verbose: true) -end - -desc "Sets up sample CoreDNS CNF with source" -task "sample_coredns_source_setup", ["helm_local_install"] do |_, args| - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-coredns-cnf-source", args: args, verbose: true, wait_count: 0 ) -end - -desc "Sets up an alternate sample CoreDNS CNF" -task "sample_coredns", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "sample_coredns new setup" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_coredns", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) -end - -desc "Sets up a Bad helm CNF Setup" -task "bad_helm_cnf_setup", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "bad_helm_cnf_setup" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-bad_helm_coredns-cnf", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) -end - -task "sample_privileged_cnf_whitelisted_setup", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "sample_privileged_cnf_whitelisted_setup" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_whitelisted_privileged_cnf", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) -end - -task "sample_privileged_cnf_non_whitelisted_setup", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "sample_privileged_cnf_non_whitelisted_setup" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_privileged_cnf", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) -end - -task "sample_coredns_bad_liveness", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "sample_coredns_bad_liveness" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample_coredns_bad_liveness", deploy_with_chart: false, args: args, verbose: true, wait_count: 0 ) -end - -task "sample_generic_cnf_setup", ["helm_local_install"] do |_, args| - VERBOSE_LOGGING.info "sample_generic_cnf" if check_verbose(args) - CNFManager.sample_setup_args(sample_dir: "sample-cnfs/sample-generic-cnf", deploy_with_chart: false, args: args, verbose: true ) -end - task "cnf_setup", ["helm_local_install"] do |_, args| VERBOSE_LOGGING.info "cnf_setup" if check_verbose(args) VERBOSE_LOGGING.debug "args = #{args.inspect}" if check_verbose(args) - if args.named.keys.includes? "cnf-config" - yml_file = args.named["cnf-config"].as(String) - # example_cnf = File.dirname(File.expand_path(yml_file)) - cnf = File.dirname(yml_file) - elsif args.named.keys.includes? "cnf-path" - cnf = args.named["cnf-path"].as(String) - else - stdout_failure "Error: You must supply either cnf-config or cnf-path" - exit 1 - end - if args.named.keys.includes? "wait_count" - wait_count = args.named["wait_count"].as(Int32) - elsif args.named.keys.includes? "wait-count" - wait_count = args.named["wait-count"].as(Int32) - else - wait_count = 180 - end - VERBOSE_LOGGING.info "cnf_setup cnf: #{cnf}" if check_verbose(args) - if args.named["deploy_with_chart"]? && args.named["deploy_with_chart"] == "false" - deploy_with_chart = false - else - deploy_with_chart = true - end - CNFManager.sample_setup_args(sample_dir: cnf, deploy_with_chart: deploy_with_chart, args: args, verbose: check_verbose(args), wait_count: wait_count ) + cli_hash = CNFManager.sample_setup_cli_args(args) + CNFManager.sample_setup(cli_hash) end task "cnf_cleanup" do |_, args| @@ -111,6 +43,7 @@ task "CNFManager.helm_repo_add" do |_, args| end +#TODO force all cleanups to use generic cleanup task "sample_coredns_cleanup" do |_, args| CNFManager.sample_cleanup(config_file: "sample-cnfs/sample-coredns-cnf", verbose: true) end diff --git a/src/tasks/configuration_lifecycle.cr b/src/tasks/configuration_lifecycle.cr deleted file mode 100644 index fd15f6772..000000000 --- a/src/tasks/configuration_lifecycle.cr +++ /dev/null @@ -1,269 +0,0 @@ -# coding: utf-8 -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "json" -require "./utils/utils.cr" - -desc "Configuration and lifecycle should be managed in a declarative manner, using ConfigMaps, Operators, or other declarative interfaces." -task "configuration_lifecycle", ["ip_addresses", "liveness", "readiness", "rolling_update", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration"] do |_, args| - stdout_score("configuration_lifecycle") -end - -desc "Does a search for IP addresses or subnets come back as negative?" -task "ip_addresses" do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "ip_addresses" if check_verbose(args) - LOGGING.info("ip_addresses args #{args.inspect}") - cdir = FileUtils.pwd() - response = String::Builder.new - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - helm_directory = "#{config.get("helm_directory").as_s?}" - LOGGING.info "ip_addresses helm_directory: #{CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) + helm_directory}" - if File.directory?(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) + helm_directory) - # Switch to the helm chart directory - Dir.cd(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) + helm_directory) - # Look for all ip addresses that are not comments - LOGGING.info "current directory: #{ FileUtils.pwd()}" - # should catch comments (# // or /*) and ignore 0.0.0.0 - # note: grep wants * escaped twice - Process.run("grep -r -P '^(?!.+0\.0\.0\.0)(?![[:space:]]*0\.0\.0\.0)(?!#)(?![[:space:]]*#)(?!\/\/)(?![[:space:]]*\/\/)(?!\/\\*)(?![[:space:]]*\/\\*)(.+([0-9]{1,3}[\.]){3}[0-9]{1,3})'", shell: true) do |proc| - while line = proc.output.gets - response << line - VERBOSE_LOGGING.info "#{line}" if check_verbose(args) - end - end - Dir.cd(cdir) - if response.to_s.size > 0 - resp = upsert_failed_task("ip_addresses","✖️ FAILURE: IP addresses found") - else - resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") - end - resp - else - # TODO If no helm chart directory, exit with 0 points - Dir.cd(cdir) - resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") - end - end -end - -desc "Is there a liveness entry in the helm chart?" -task "liveness", ["retrieve_manifest"] do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "liveness" if check_verbose(args) - # Parse the cnf-conformance.yml - resp = "" - errors = 0 - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - VERBOSE_LOGGING.debug deployment.inspect if check_verbose(args) - emoji_probe="🧫" - containers = deployment.get("spec").as_h["template"].as_h["spec"].as_h["containers"].as_a - containers.each do |container| - begin - VERBOSE_LOGGING.debug container.as_h["name"].as_s if check_verbose(args) - container.as_h["livenessProbe"].as_h - rescue ex - VERBOSE_LOGGING.error ex.message if check_verbose(args) - errors = errors + 1 - resp = upsert_failed_task("liveness","✖️ FAILURE: No livenessProbe found #{emoji_probe}") - end - end - if errors == 0 - resp = upsert_passed_task("liveness","✔️ PASSED: Helm liveness probe found #{emoji_probe}") - end - resp - end -end - -desc "Is there a readiness entry in the helm chart?" -task "readiness", ["retrieve_manifest"] do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "readiness" if check_verbose(args) - # Parse the cnf-conformance.yml - resp = "" - errors = 0 - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - VERBOSE_LOGGING.debug deployment.inspect if check_verbose(args) - containers = deployment.get("spec").as_h["template"].as_h["spec"].as_h["containers"].as_a - containers.each do |container| - begin - VERBOSE_LOGGING.debug container.as_h["name"].as_s if check_verbose(args) - container.as_h["readinessProbe"].as_h - rescue ex - VERBOSE_LOGGING.error ex.message if check_verbose(args) - errors = errors + 1 - resp = upsert_failed_task("readiness","✖️ FAILURE: No readinessProbe found") - end - end - if errors == 0 - resp = upsert_passed_task("readiness","✔️ PASSED: Helm readiness probe found") - end - end -end - -desc "Retrieve the manifest for the CNF's helm chart" -task "retrieve_manifest" do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "retrieve_manifest" if check_verbose(args) - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - deployment_name = config.get("deployment_name").as_s - service_name = config.get("service_name").as_s - VERBOSE_LOGGING.debug "Deployment_name: #{deployment_name}" if check_verbose(args) - VERBOSE_LOGGING.debug service_name if check_verbose(args) - helm_directory = config.get("helm_directory").as_s - VERBOSE_LOGGING.debug helm_directory if check_verbose(args) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment = `kubectl get deployment #{deployment_name} -o yaml > #{destination_cnf_dir}/manifest.yml` - VERBOSE_LOGGING.debug deployment if check_verbose(args) - unless service_name.empty? - service = `kubectl get service #{service_name} -o yaml > #{destination_cnf_dir}/service.yml` - end - VERBOSE_LOGGING.debug service if check_verbose(args) - service - end -end - -desc "Test if the CNF can perform a rolling update" -task "rolling_update" do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "rolling_update" if check_verbose(args) - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - - version_tag = nil - - if config.has_key? "rolling_update_tag" - version_tag = config.get("rolling_update_tag").as_s - end - - if args.named.has_key? "version_tag" - version_tag = args.named["version_tag"] - end - - unless version_tag - fail_msg = "✖️ FAILURE: please specify a version of the CNF's release's image with the option version_tag or with cnf_conformance_yml option 'rolling_update_tag'" - upsert_failed_task("rolling_update", fail_msg) - raise fail_msg - end - - release_name = config.get("release_name").as_s - deployment_name = config.get("deployment_name").as_s - helm_chart_container_name = config.get("helm_chart_container_name").as_s - - # helm_chart_values = JSON.parse(`#{CNFManager.local_helm_path} get values #{release_name} -a --output json`) - LOGGING.info "helm path: #{CNFSingleton.helm}" - LOGGING.info "helm command: #{CNFSingleton.helm} get values #{release_name} -a --output json" - helm_resp = `#{CNFSingleton.helm} get values #{release_name} -a --output json` - # helm sometimes does not return valid json :/ - helm_split = helm_resp.split("\n") - LOGGING.info "helm_split: #{helm_split}" - if helm_split[1] =~ /WARNING/ - cleaned_resp = helm_split[2] - elsif helm_split[0] =~ /WARNING/ - cleaned_resp = helm_split[1] - else - cleaned_resp = helm_split[0] - end - LOGGING.info "cleaned_resp: #{cleaned_resp}" - helm_chart_values = JSON.parse(cleaned_resp) - VERBOSE_LOGGING.debug "helm_chart_values" if check_verbose(args) - VERBOSE_LOGGING.debug helm_chart_values if check_verbose(args) - image_name = helm_chart_values["image"]["repository"] - - VERBOSE_LOGGING.debug "image_name: #{image_name}" if check_verbose(args) - - VERBOSE_LOGGING.debug "rolling_update: setting new version" if check_verbose(args) - #do_update = `kubectl set image deployment/coredns-coredns coredns=coredns/coredns:latest --record` - VERBOSE_LOGGING.debug "kubectl set image deployment/#{deployment_name} #{helm_chart_container_name}=#{image_name}:#{version_tag} --record" if check_verbose(args) - update = `kubectl set image deployment/#{deployment_name} #{helm_chart_container_name}=#{image_name}:#{version_tag} --record` - update_applied = $?.success? - VERBOSE_LOGGING.debug "#{update}" if check_verbose(args) - VERBOSE_LOGGING.debug "update? #{update_applied}" if check_verbose(args) - - # https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#rolling-update - VERBOSE_LOGGING.debug "rolling_update: checking status new version" if check_verbose(args) - rollout = `kubectl rollout status deployment/#{deployment_name} --timeout=30s` - rollout_status = $?.success? - VERBOSE_LOGGING.debug "#{rollout}" if check_verbose(args) - VERBOSE_LOGGING.debug "rollout? #{rollout_status}" if check_verbose(args) - if update_applied && rollout_status - upsert_passed_task("rolling_update","✔️ PASSED: CNF #{deployment_name} Rolling Update Passed" ) - else - upsert_failed_task("rolling_update", "✖️ FAILURE: CNF #{deployment_name} Rolling Update Failed") - end - end -end - -desc "Does the CNF use NodePort" -task "nodeport_not_used", ["retrieve_manifest"] do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "nodeport_not_used" if check_verbose(args) - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - release_name = config.get("release_name").as_s - service_name = config.get("service_name").as_s - # current_cnf_dir_short_name = CNFManager.ensure_cnf_conformance_dir - # VERBOSE_LOGGING.debug current_cnf_dir_short_name if check_verbose(args) - # destination_cnf_dir = sample_destination_dir(current_cnf_dir_short_name) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - if File.exists?("#{destination_cnf_dir}/service.yml") - service = Totem.from_file "#{destination_cnf_dir}/service.yml" - VERBOSE_LOGGING.debug service.inspect if check_verbose(args) - service_type = service.get("spec").as_h["type"].as_s - VERBOSE_LOGGING.debug service_type if check_verbose(args) - if service_type == "NodePort" - upsert_failed_task("nodeport_not_used", "✖️ FAILURE: NodePort is being used") - else - upsert_passed_task("nodeport_not_used", "✔️ PASSED: NodePort is not used") - end - end - end -end - -desc "Does the CNF have hardcoded IPs in the K8s resource configuration" -task "hardcoded_ip_addresses_in_k8s_runtime_configuration" do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "Task Name: hardcoded_ip_addresses_in_k8s_runtime_configuration" if check_verbose(args) - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - helm_chart = "#{config.get("helm_chart").as_s?}" - helm_directory = config.get("helm_directory").as_s - release_name = "#{config.get("release_name").as_s?}" - # current_cnf_dir_short_name = CNFManager.ensure_cnf_conformance_dir - # VERBOSE_LOGGING.debug "Current_CNF_Dir: #{current_cnf_dir_short_name}" if check_verbose(args) - # destination_cnf_dir = sample_destination_dir(current_cnf_dir_short_name) - - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - current_dir = FileUtils.pwd - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - VERBOSE_LOGGING.info "Helm Path: #{helm}" if check_verbose(args) - - create_namespace = `kubectl create namespace hardcoded-ip-test` - unless helm_chart.empty? - helm_install = `#{helm} install --namespace hardcoded-ip-test hardcoded-ip-test #{helm_chart} --dry-run --debug > #{destination_cnf_dir}/helm_chart.yml` - VERBOSE_LOGGING.info "helm_chart: #{helm_chart}" if check_verbose(args) - else - helm_install = `#{helm} install --namespace hardcoded-ip-test hardcoded-ip-test #{destination_cnf_dir}/#{helm_directory} --dry-run --debug > #{destination_cnf_dir}/helm_chart.yml` - VERBOSE_LOGGING.info "helm_directory: #{helm_directory}" if check_verbose(args) - end - - ip_search = File.read_lines("#{destination_cnf_dir}/helm_chart.yml").take_while{|x| x.match(/NOTES:/) == nil}.reduce([] of String){|acc, x| x.match(/([0-9]{1,3}[\.]){3}[0-9]{1,3}/) && x.match(/([0-9]{1,3}[\.]){3}[0-9]{1,3}/).try &.[0] != "0.0.0.0" ? acc << x : acc} - VERBOSE_LOGGING.info "IPs: #{ip_search}" if check_verbose(args) - - if ip_search.empty? - upsert_passed_task("hardcoded_ip_addresses_in_k8s_runtime_configuration", "✔️ PASSED: No hard-coded IP addresses found in the runtime K8s configuration") - else - upsert_failed_task("hardcoded_ip_addresses_in_k8s_runtime_configuration", "✖️ FAILURE: Hard-coded IP addresses found in the runtime K8s configuration") - end - delete_namespace = `kubectl delete namespace hardcoded-ip-test --force --grace-period 0 2>&1 >/dev/null` - - end -end diff --git a/src/tasks/constants.cr b/src/tasks/constants.cr index d46e6a24d..f11b243a8 100644 --- a/src/tasks/constants.cr +++ b/src/tasks/constants.cr @@ -1,12 +1,33 @@ require "./utils/system_information/helm.cr" +require "./utils/embedded_file_manager.cr" + +CNF_DIR = "cnfs" +CONFIG_FILE = "cnf-conformance.yml" +TOOLS_DIR = "tools" +BASE_CONFIG = "./config.yml" +POINTSFILE = "points.yml" +PASSED = "passed" +FAILED = "failed" +SKIPPED = "skipped" +DEFAULT_POINTSFILENAME = "points_v1.yml" +PRIVILEGED_WHITELIST_CONTAINERS = ["chaos-daemon"] +IGNORED_SECRET_TYPES = ["kubernetes.io/service-account-token", "kubernetes.io/dockercfg", "kubernetes.io/dockerconfigjson", "helm.sh/release.v1"] + +#Embedded global text variables +EmbeddedFileManager.node_failure_values +EmbeddedFileManager.cri_tools +EmbeddedFileManager.reboot_daemon +EmbeddedFileManager.chaos_network_loss +EmbeddedFileManager.chaos_cpu_hog +EmbeddedFileManager.chaos_container_kill CNFSingleton = CNFGlobals.new class CNFGlobals CNF_DIR = "cnfs" @helm: String? # Get helm directory - def helm - @helm ||= global_helm_installed? ? "helm" : CNFManager.local_helm_path + def helm + @helm ||= global_helm_installed? ? "helm" : Helm.local_helm_path end end diff --git a/src/tasks/dockerd_setup.cr b/src/tasks/dockerd_setup.cr new file mode 100644 index 000000000..a67046ab2 --- /dev/null +++ b/src/tasks/dockerd_setup.cr @@ -0,0 +1,78 @@ +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "./utils/utils.cr" + + +desc "The dockerd tool is used to run docker commands against the cluster." +task "install_dockerd" do |_, args| + VERBOSE_LOGGING.info "install_dockerd" if check_verbose(args) + resp = KubectlClient::Apply.file(dockerd_filename) + status = check_dockerd(180) + if status + LOGGING.error "Dockerd_Install failed.".colorize(:red) + end + LOGGING.info "Dockerd_Install status: #{status}" + status +end + +desc "Uninstall dockerd" +task "uninstall_dockerd" do |_, args| + LOGGING.info "uninstall_dockerd" + KubectlClient::Delete.file(dockerd_filename) +end + +def dockerd_filename + "./#{TOOLS_DIR}/dockerd/manifest.yml" +end + +def dockerd_tempname + "./#{TOOLS_DIR}/dockerd/manifest.tmp" +end + +def dockerd_tempname_helper + LOGGING.info "dockerd_tempname_helper" + LOGGING.info "before ls #{TOOLS_DIR}" + LOGGING.info `ls #{TOOLS_DIR}` + LOGGING.info "ls #{TOOLS_DIR}/dockerd" + LOGGING.info `ls #{TOOLS_DIR}/dockerd` + `mv #{dockerd_filename} #{dockerd_tempname}` + LOGGING.info "after ls #{TOOLS_DIR}" + LOGGING.info `ls #{TOOLS_DIR}` + LOGGING.info "ls #{TOOLS_DIR}/dockerd" + LOGGING.info `ls #{TOOLS_DIR}/dockerd` +end + +def dockerd_name_helper + LOGGING.info "dockerd_name_helper" + LOGGING.info "before ls #{TOOLS_DIR}" + LOGGING.info `ls #{TOOLS_DIR}` + LOGGING.info "ls #{TOOLS_DIR}/dockerd" + LOGGING.info `ls #{TOOLS_DIR}/dockerd` + `mv #{dockerd_tempname} #{dockerd_filename}` + LOGGING.info "after ls #{TOOLS_DIR}" + LOGGING.info `ls #{TOOLS_DIR}` + LOGGING.info "ls #{TOOLS_DIR}/dockerd" + LOGGING.info `ls #{TOOLS_DIR}/dockerd` +end + +### Checks to see if dockerd is already installed. Alternatively +### can be used to wait for dockerd is installed by passing a higher wait_count) +def check_dockerd(wait_count = 1) + LOGGING.info "check_dockerd" + KubectlClient::Get.resource_wait_for_install("Pod", "dockerd", wait_count: wait_count) + # pod_ready = "" + # pod_ready_timeout = 25 + # until (pod_ready == "true" || pod_ready_timeout == 0) + # pod_ready = KubectlClient::Get.pod_status("dockerd").split(",")[2] + # puts "Pod Ready Status: #{pod_ready}" + # sleep 1 + # pod_ready_timeout = pod_ready_timeout - 1 + # end + # if (pod_ready && !pod_ready.empty? && pod_ready == "true") + # true + # else + # false + # end +end diff --git a/src/tasks/helmenv_setup.cr b/src/tasks/helmenv_setup.cr index 4e074e34c..bf4320f4c 100644 --- a/src/tasks/helmenv_setup.cr +++ b/src/tasks/helmenv_setup.cr @@ -3,6 +3,7 @@ require "file_utils" require "colorize" require "totem" require "./utils/utils.cr" +require "http/client" desc "Sets up helm 3.1.1" task "helm_local_install", ["cnf_directory_setup"] do |_, args| @@ -18,26 +19,25 @@ task "helm_local_install", ["cnf_directory_setup"] do |_, args| VERBOSE_LOGGING.debug "toolsdir : #{TOOLS_DIR}" if check_verbose(args) VERBOSE_LOGGING.debug "full path?: #{current_dir.to_s}/#{TOOLS_DIR}/helm" if check_verbose(args) FileUtils.mkdir_p("#{current_dir}/#{TOOLS_DIR}/helm") - wget = `wget https://get.helm.sh/helm-v3.1.1-linux-amd64.tar.gz -O #{current_dir}/#{TOOLS_DIR}/helm/helm-v3.1.1-linux-amd64.tar.gz` - VERBOSE_LOGGING.debug wget if check_verbose(args) + HTTP::Client.get("https://get.helm.sh/helm-v3.1.1-linux-amd64.tar.gz") do |response| + File.write("#{current_dir}/#{TOOLS_DIR}/helm/helm-v3.1.1-linux-amd64.tar.gz", response.body_io) + end tar = `cd #{current_dir}/#{TOOLS_DIR}/helm; tar -xvf #{current_dir}/#{TOOLS_DIR}/helm/helm-v3.1.1-linux-amd64.tar.gz` VERBOSE_LOGGING.debug tar if check_verbose(args) - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm + helm = CNFSingleton.helm VERBOSE_LOGGING.debug helm if check_verbose(args) VERBOSE_LOGGING.debug `#{helm} version` if check_verbose(args) - stable_repo = `#{helm} repo add stable https://kubernetes-charts.storage.googleapis.com` - # stable_repo = "" + stable_repo = `#{helm} repo add stable https://cncf.gitlab.io/stable` VERBOSE_LOGGING.debug stable_repo if check_verbose(args) - #TODO grep for version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"} + #TODO grep for specific version e.g. version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"} ensure cd = `cd #{current_dir}` VERBOSE_LOGGING.debug cd if check_verbose(args) end end end - # `#{CNFSingleton.helm} repo add stable https://kubernetes-charts.storage.googleapis.com` + # `#{CNFSingleton.helm} repo add stable https://cncf.gitlab.io/stable` end desc "Cleans up helm 3.1.1" diff --git a/src/tasks/installability.cr b/src/tasks/installability.cr deleted file mode 100644 index 2204b7e72..000000000 --- a/src/tasks/installability.cr +++ /dev/null @@ -1,184 +0,0 @@ -# coding: utf-8 -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "./utils/utils.cr" - -desc "The CNF conformance suite checks to see if CNFs support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines) by using the native K8s kubectl" -task "installability", ["install_script_helm", "helm_chart_valid", "helm_chart_published", "helm_deploy"] do |_, args| - stdout_score("installability") -end - -desc "Will the CNF install using helm with helm_deploy?" -task "helm_deploy" do |_, args| - VERBOSE_LOGGING.info "helm_deploy" if check_verbose(args) - LOGGING.info("helm_deploy args: #{args.inspect}") - if check_cnf_config(args) || CNFManager.destination_cnfs_exist? - task_runner(args) do |args| - begin - release_name_prefix = "helm-deploy-" - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - - helm_chart = "#{config.get("helm_chart").as_s?}" - helm_directory = "#{config.get("helm_directory").as_s?}" - release_name = "#{config.get("release_name").as_s?}" - - current_dir = FileUtils.pwd - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - VERBOSE_LOGGING.debug helm if check_verbose(args) - - if helm_chart.empty? - #TODO make this work off of a helm directory if helm_directory was passed - # yml_file_path = cnf_conformance_yml_file_path(args) - yml_file_path = CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) - VERBOSE_LOGGING.debug "#{helm} install #{release_name_prefix}#{release_name} #{yml_file_path}/#{helm_directory}" if check_verbose(args) - helm_install = `#{helm} install #{release_name_prefix}#{release_name} #{yml_file_path}/#{helm_directory}` - else - VERBOSE_LOGGING.debug "#{helm} install #{release_name_prefix}#{release_name} #{helm_chart}" if check_verbose(args) - helm_install = `#{helm} install #{release_name_prefix}#{release_name} #{helm_chart}` - end - - is_helm_installed = $?.success? - VERBOSE_LOGGING.info helm_install if check_verbose(args) - - if is_helm_installed - upsert_passed_task("helm_deploy", "✔️ PASSED: Helm deploy successful") - else - upsert_failed_task("helm_deploy", "✖️ FAILURE: Helm deploy failed") - end - ensure - VERBOSE_LOGGING.debug "#{helm} uninstall #{release_name_prefix}#{release_name}" if check_verbose(args) - helm_uninstall = `#{helm} uninstall #{release_name_prefix}#{release_name}` - end - end - else - upsert_failed_task("helm_deploy", "✖️ FAILURE: No cnf_conformance.yml found! Did you run the setup task?") - end -end - -desc "Does the install script use helm?" -task "install_script_helm" do |_, args| - task_runner(args) do |args| - # Parse the cnf-conformance.yml - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - - found = 0 - # current_cnf_dir_short_name = CNFManager.ensure_cnf_conformance_dir - # current_cnf_dir_short_name = CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) - # VERBOSE_LOGGING.debug current_cnf_dir_short_name if check_verbose(args) - # destination_cnf_dir = sample_destination_dir(current_cnf_dir_short_name) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - VERBOSE_LOGGING.debug destination_cnf_dir if check_verbose(args) - install_script = config.get("install_script").as_s? - if install_script - response = String::Builder.new - content = File.open("#{destination_cnf_dir}/#{install_script}") do |file| - file.gets_to_end - end - # LOGGING.debug content - if /helm/ =~ content - found = 1 - end - if found < 1 - upsert_failed_task("install_script_helm", "✖️ FAILURE: Helm not found in supplied install script") - else - upsert_passed_task("install_script_helm", "✔️ PASSED: Helm found in supplied install script") - end - else - upsert_passed_task("install_script_helm", "✔️ PASSED (by default): No install script provided") - end - end -end - -task "helm_chart_published", ["helm_local_install"] do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "helm_chart_published" if check_verbose(args) - VERBOSE_LOGGING.debug "helm_chart_published args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "helm_chart_published args.named: #{args.named}" if check_verbose(args) - - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - helm_chart = "#{config.get("helm_chart").as_s?}" - helm_directory = "#{config.get("helm_directory").as_s?}" - - current_dir = FileUtils.pwd - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - VERBOSE_LOGGING.debug helm if check_verbose(args) - - if CNFManager.helm_repo_add(args: args) - unless helm_chart.empty? - helm_search = `#{helm} search repo #{helm_chart}` - LOGGING.info "helm search command: #{helm} search repo #{helm_chart}" - VERBOSE_LOGGING.debug "#{helm_search}" if check_verbose(args) - unless helm_search =~ /No results found/ - upsert_passed_task("helm_chart_published", "✔️ PASSED: Published Helm Chart Found") - else - upsert_failed_task("helm_chart_published", "✖️ FAILURE: Published Helm Chart Not Found") - end - else - upsert_failed_task("helm_chart_published", "✖️ FAILURE: Published Helm Chart Not Found") - end - else - upsert_failed_task("helm_chart_published", "✖️ FAILURE: Published Helm Chart Not Found") - end - end -end - -task "helm_chart_valid", ["helm_local_install"] do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "helm_chart_valid" if check_verbose(args) - VERBOSE_LOGGING.debug "helm_chart_valid args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "helm_chart_valid args.named: #{args.named}" if check_verbose(args) - - response = String::Builder.new - - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - helm_directory = config.get("helm_directory").as_s - # helm_chart_repo = config.get("helm_chart").as_s - - if args.named.keys.includes? "cnf_chart_path" - helm_directory = args.named["cnf_chart_path"] - end - - VERBOSE_LOGGING.debug "helm_directory: #{helm_directory}" if check_verbose(args) - # VERBOSE_LOGGING.debug "helm_chart_repo: #{helm_chart_repo}" if check_verbose(args) - - current_dir = FileUtils.pwd - VERBOSE_LOGGING.debug current_dir if check_verbose(args) - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - - # current_cnf_dir_short_name = CNFManager.ensure_cnf_conformance_dir - # VERBOSE_LOGGING.debug current_cnf_dir_short_name if check_verbose(args) - # destination_cnf_dir = sample_destination_dir(current_cnf_dir_short_name) - # VERBOSE_LOGGING.debug destination_cnf_dir if check_verbose(args) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - ls_helm_directory = `ls -al #{destination_cnf_dir}/#{helm_directory}` - VERBOSE_LOGGING.debug "ls -al of helm_directory: #{ls_helm_directory}" if check_verbose(args) - - helm_lint = `#{helm} lint #{destination_cnf_dir}/#{helm_directory}` - VERBOSE_LOGGING.debug "helm_lint: #{helm_lint}" if check_verbose(args) - - if $?.success? - upsert_passed_task("helm_chart_valid", "✔️ PASSED: Helm Chart #{helm_directory} Lint Passed") - else - upsert_failed_task("helm_chart_valid", "✖️ FAILURE: Helm Chart #{helm_directory} Lint Failed") - end - end -end - -task "validate_config" do |_, args| - yml = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - valid, warning_output = CNFManager.validate_cnf_conformance_yml(yml) - emoji_config="📋" - if valid - stdout_success "✔️ PASSED: CNF configuration validated #{emoji_config}" - else - stdout_failure "❌ FAILURE: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file #{emoji_config}" - end -end diff --git a/src/tasks/litmus_cleanup.cr b/src/tasks/litmus_cleanup.cr new file mode 100644 index 000000000..7e6a66bb3 --- /dev/null +++ b/src/tasks/litmus_cleanup.cr @@ -0,0 +1,13 @@ +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "./utils/utils.cr" + +desc "Uninstall LitmusChaos" +task "uninstall_litmus" do |_, args| + uninstall_chaosengine = `kubectl delete chaosengine --all --all-namespaces` + litmus_uninstall = `kubectl delete -f https://litmuschaos.github.io/litmus/litmus-operator-v1.13.2.yaml` + puts "#{uninstall_chaosengine}" if check_verbose(args) + puts "#{litmus_uninstall}" if check_verbose(args) +end diff --git a/src/tasks/litmus_setup.cr b/src/tasks/litmus_setup.cr new file mode 100644 index 000000000..1ebc3a5c2 --- /dev/null +++ b/src/tasks/litmus_setup.cr @@ -0,0 +1,78 @@ +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "./utils/utils.cr" + +desc "Install LitmusChaos" +task "install_litmus" do |_, args| + # litmus_install = `kubectl apply -f https://litmuschaos.github.io/litmus/litmus-operator-v1.11.0.yaml` + KubectlClient::Apply.file("https://litmuschaos.github.io/litmus/litmus-operator-v1.13.2.yaml") + # puts "#{litmus_install}" if check_verbose(args) +end + +module LitmusManager + + ## wait_for_test will wait for the completion of litmus test + def self.wait_for_test(test_name,chaos_experiment_name,args) + ## Maximum wait time is 900s (60 retry * 15 delay) by default. + delay=15 + retry=60 + chaos_result_name = "#{test_name}-#{chaos_experiment_name}" + wait_count = 0 + status_code = -1 + experimentStatus = "" + experimentStatus_cmd = "kubectl get chaosengine.litmuschaos.io #{test_name} -o jsonpath='{.status.engineStatus}'" + puts "Checking experiment status #{experimentStatus_cmd}" if check_verbose(args) + + ## Wait for completion of chaosengine which indicates the completion of chaos + until (status_code == 0 && experimentStatus == "Completed") || wait_count >= retry + sleep delay + experimentStatus_cmd = "kubectl get chaosengine.litmuschaos.io #{test_name} -o jsonpath='{.status.experiments[0].status}'" + puts "Checking experiment status #{experimentStatus_cmd}" if check_verbose(args) + status_code = Process.run("#{experimentStatus_cmd}", shell: true, output: experimentStatus_response = IO::Memory.new, error: stderr = IO::Memory.new).exit_status + puts "status_code: #{status_code}" if check_verbose(args) + puts "Checking experiment status #{experimentStatus_cmd}" if check_verbose(args) + experimentStatus = experimentStatus_response.to_s + LOGGING.info "#{chaos_experiment_name} experiment status: "+experimentStatus + + emoji_test_failed= "🗡️💀♻️" + if (experimentStatus != "Waiting for Job Creation" && experimentStatus != "Running" && experimentStatus != "Completed") + resp = upsert_failed_task("pod-network-latency","✖️ FAILED: #{chaos_experiment_name} chaos test failed #{emoji_test_failed}") + resp + end + end + + verdict = "" + verdict_cmd = "kubectl get chaosresults.litmuschaos.io #{chaos_result_name} -o jsonpath='{.status.experimentstatus.verdict}'" + puts "Checking experiment verdict #{verdict_cmd}" if check_verbose(args) + ## Check the chaosresult verdict + until (status_code == 0 && verdict != "Awaited") || wait_count >= 20 + sleep 2 + status_code = Process.run("#{verdict_cmd}", shell: true, output: verdict_response = IO::Memory.new, error: stderr = IO::Memory.new).exit_status + puts "status_code: #{status_code}" if check_verbose(args) + puts "verdict: #{verdict_response.to_s}" if check_verbose(args) + verdict = verdict_response.to_s + wait_count = wait_count + 1 + end +end + + ## check_chaos_verdict will check the verdict of chaosexperiment + def self.check_chaos_verdict(chaos_result_name,chaos_experiment_name,args) + verdict_cmd = "kubectl get chaosresults.litmuschaos.io #{chaos_result_name} -o jsonpath='{.status.experimentstatus.verdict}'" + puts "Checking experiment verdict #{verdict_cmd}" if check_verbose(args) + status_code = Process.run("#{verdict_cmd}", shell: true, output: verdict_response = IO::Memory.new, error: stderr = IO::Memory.new).exit_status + puts "status_code: #{status_code}" if check_verbose(args) + puts "verdict: #{verdict_response.to_s}" if check_verbose(args) + verdict = verdict_response.to_s + + emoji_test_failed= "🗡️💀♻️" + if verdict == "Pass" + true + else + LOGGING.info "#{chaos_experiment_name} chaos test failed: #{chaos_result_name}, verdict: #{verdict}" + puts "#{chaos_experiment_name} chaos test failed #{emoji_test_failed}" + false + end + end +end diff --git a/src/tasks/microservice.cr b/src/tasks/microservice.cr deleted file mode 100644 index cb567b20f..000000000 --- a/src/tasks/microservice.cr +++ /dev/null @@ -1,133 +0,0 @@ -# coding: utf-8 -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "./utils/utils.cr" -require "halite" -require "totem" - -desc "The CNF conformance suite checks to see if CNFs follows microservice principles" -task "microservice", ["reasonable_image_size", "reasonable_startup_time"] do |_, args| - stdout_score("microservice") -end - -desc "Does the CNF have a reasonable startup time?" -task "reasonable_startup_time" do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "reasonable_startup_time" if check_verbose(args) - - # config = get_parsed_cnf_conformance_yml(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - # yml_file_path = cnf_conformance_yml_file_path(args) - # needs to be the source directory - yml_file_path = CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String)) - # yml_file_path = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - LOGGING.info("reasonable_startup_time yml_file_path: #{yml_file_path}") - VERBOSE_LOGGING.info "yaml_path: #{yml_file_path}" if check_verbose(args) - - helm_chart = "#{config.get("helm_chart").as_s?}" - helm_directory = "#{config.get("helm_directory").as_s?}" - release_name = "#{config.get("release_name").as_s?}" - deployment_name = "#{config.get("deployment_name").as_s?}" - current_dir = FileUtils.pwd - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - VERBOSE_LOGGING.info helm if check_verbose(args) - - create_namespace = `kubectl create namespace startup-test` - helm_template_orig = "" - helm_template_test = "" - kubectl_apply = "" - is_kubectl_applied = "" - is_kubectl_deployed = "" - elapsed_time = Time.measure do - LOGGING.info("reasonable_startup_time helm_chart.empty?: #{helm_chart.empty?}") - unless helm_chart.empty? - LOGGING.info("reasonable_startup_time #{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml") - LOGGING.info "helm_template_orig command: #{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml}" - helm_template_orig = `#{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml` - LOGGING.info("reasonable_startup_time #{helm} template --namespace=startup-test #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_test.yml") - helm_template_test = `#{helm} template --namespace=startup-test #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_test.yml` - VERBOSE_LOGGING.info "helm_chart: #{helm_chart}" if check_verbose(args) - else - LOGGING.info("reasonable_startup_time #{helm} template #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_orig.yml") - helm_template_orig = `#{helm} template #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_orig.yml` - LOGGING.info("reasonable_startup_time #{helm} template --namespace=startup-test #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_test.yml") - helm_template_test = `#{helm} template --namespace=startup-test #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_test.yml` - VERBOSE_LOGGING.info "helm_directory: #{helm_directory}" if check_verbose(args) - end - kubectl_apply = `kubectl apply -f #{yml_file_path}/reasonable_startup_test.yml --namespace=startup-test` - is_kubectl_applied = $?.success? - CNFManager.wait_for_install(deployment_name, wait_count=180,"startup-test") - is_kubectl_deployed = $?.success? - end - - VERBOSE_LOGGING.info helm_template_test if check_verbose(args) - VERBOSE_LOGGING.info kubectl_apply if check_verbose(args) - VERBOSE_LOGGING.info "installed? #{is_kubectl_applied}" if check_verbose(args) - VERBOSE_LOGGING.info "deployed? #{is_kubectl_deployed}" if check_verbose(args) - - emoji_fast="🚀" - emoji_slow="🐢" - if is_kubectl_applied && is_kubectl_deployed && elapsed_time.seconds < 30 - upsert_passed_task("reasonable_startup_time", "✔️ PASSED: CNF had a reasonable startup time #{emoji_fast}") - else - upsert_failed_task("reasonable_startup_time", "✖️ FAILURE: CNF had a startup time of #{elapsed_time.seconds} seconds #{emoji_slow}") - end - - delete_namespace = `kubectl delete namespace startup-test --force --grace-period 0 2>&1 >/dev/null` - rollback_non_namespaced = `kubectl apply -f #{yml_file_path}/reasonable_startup_orig.yml` - # CNFManager.wait_for_install(deployment_name, wait_count=180) - end -end - -desc "Does the CNF have a reasonable container image size?" -task "reasonable_image_size", ["retrieve_manifest"] do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "reasonable_image_size" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - #TODO get the docker repository segment from the helm chart - #TODO check all images - # helm_chart_values = JSON.parse(`#{CNFManager.tools_helm} get values #{release_name} -a --output json`) - # image_name = helm_chart_values["image"]["repository"] - docker_repository = config.get("docker_repository").as_s? - VERBOSE_LOGGING.info "docker_repository: #{docker_repository}"if check_verbose(args) - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - VERBOSE_LOGGING.debug deployment.inspect if check_verbose(args) - containers = deployment.get("spec").as_h["template"].as_h["spec"].as_h["containers"].as_a - image_tag = [] of Array(Hash(Int32, String)) - image_tag = containers.map do |container| - {image: container.as_h["image"].as_s.split(":")[0], - tag: container.as_h["image"].as_s.split(":")[1]} - end - VERBOSE_LOGGING.debug "image_tag: #{image_tag.inspect}" if check_verbose(args) - if docker_repository - # e.g. `curl -s -H "Authorization: JWT " "https://hub.docker.com/v2/repositories/#{docker_repository}/tags/?page_size=100" | jq -r '.results[] | select(.name == "latest") | .full_size'`.split('\n')[0] - docker_resp = Halite.get("https://hub.docker.com/v2/repositories/#{image_tag[0][:image]}/tags/?page_size=100", headers: {"Authorization" => "JWT"}) - latest_image = docker_resp.parse("json")["results"].as_a.find{|x|x["name"]=="#{image_tag[0][:tag]}"} - micro_size = latest_image && latest_image["full_size"] - else - VERBOSE_LOGGING.info "no docker repository specified" if check_verbose(args) - micro_size = nil - end - - VERBOSE_LOGGING.info "micro_size: #{micro_size.to_s}" if check_verbose(args) - emoji_image_size="⚖️👀" - emoji_small="🐜" - emoji_big="🦖" - - # if a sucessfull call and size of container is less than 5gb (5 billion bytes) - if docker_repository && - docker_resp && - docker_resp.status_code == 200 && - micro_size.to_s.to_i64 < 5_000_000_000 - upsert_passed_task("reasonable_image_size", "✔️ PASSED: Image size is good #{emoji_small} #{emoji_image_size}") - else - upsert_failed_task("reasonable_image_size", "✖️ FAILURE: Image size too large #{emoji_big} #{emoji_image_size}") - end - end -end - - diff --git a/src/tasks/platform/hardware_and_scheduling.cr b/src/tasks/platform/hardware_and_scheduling.cr index c5a121967..db8c15484 100644 --- a/src/tasks/platform/hardware_and_scheduling.cr +++ b/src/tasks/platform/hardware_and_scheduling.cr @@ -14,7 +14,7 @@ namespace "platform" do desc "Does the Platform use a runtime that is oci compliant" task "oci_compliant" do |_, args| - task_response = task_runner(args) do |args| + task_response = CNFManager::Task.task_runner(args) do |args| resp = KubectlClient::Get.container_runtimes all_oci_runtimes = true resp.each do |x| @@ -28,7 +28,7 @@ namespace "platform" do upsert_passed_task("oci_compliant","✔️ PASSED: Your platform is using the following runtimes: [#{KubectlClient::Get.container_runtimes.join(",")}] which are OCI compliant runtimes #{emoji_chaos_oci_compliant}") else emoji_chaos_oci_compliant="📶☠️" - upsert_failed_task("oci_compliant", "✖️ FAILURE: Platform has at least one node that uses a non OCI compliant runtime #{emoji_chaos_oci_compliant}") + upsert_failed_task("oci_compliant", "✖️ FAILED: Platform has at least one node that uses a non OCI compliant runtime #{emoji_chaos_oci_compliant}") end end end diff --git a/src/tasks/platform/observability.cr b/src/tasks/platform/observability.cr index d9d3eb850..62aeae143 100644 --- a/src/tasks/platform/observability.cr +++ b/src/tasks/platform/observability.cr @@ -7,30 +7,34 @@ require "retriable" namespace "platform" do desc "The CNF conformance suite checks to see if the Platform has Observability support." task "observability", ["kube_state_metrics", "node_exporter", "prometheus_adapter", "metrics_server"] do |t, args| - VERBOSE_LOGGING.info "resilience" if check_verbose(args) - VERBOSE_LOGGING.debug "resilience args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "resilience args.named: #{args.named}" if check_verbose(args) - stdout_score("platform:resilience") + VERBOSE_LOGGING.info "observability" if check_verbose(args) + VERBOSE_LOGGING.debug "observability args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "observability args.named: #{args.named}" if check_verbose(args) + stdout_score("platform:observability") end desc "Does the Platform have Kube State Metrics installed" task "kube_state_metrics" do |_, args| unless check_poc(args) LOGGING.info "skipping kube_state_metrics: not in poc mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: Kube State Metrics".colorize(:yellow) next end LOGGING.info "Running POC: kube_state_metrics" Retriable.retry do - task_response = task_runner(args) do |args| - current_dir = FileUtils.pwd + task_response = CNFManager::Task.task_runner(args) do |args| + current_dir = FileUtils.pwd + + # state_metric_releases = `curl -L -s https://quay.io/api/v1/repository/coreos/kube-state-metrics/tag/?limit=100` + + resp = Halite.get("https://quay.io/api/v1/repository/coreos/kube-state-metrics/tag/?limit=100") + state_metric_releases = resp.body - state_metric_releases = `curl -L -s https://quay.io/api/v1/repository/coreos/kube-state-metrics/tag/?limit=100` # Get the sha hash for the kube-state-metrics container sha_list = named_sha_list(state_metric_releases) LOGGING.debug "sha_list: #{sha_list}" - # TODO find hash for image + # find hash for image imageids = KubectlClient::Get.all_container_repo_digests LOGGING.debug "imageids: #{imageids}" found = false @@ -46,7 +50,7 @@ namespace "platform" do upsert_passed_task("kube_state_metrics","✔️ PASSED: Your platform is using the #{release_name} release for kube state metrics #{emoji_kube_state_metrics}") else emoji_kube_state_metrics="📶☠️" - upsert_failed_task("kube_state_metrics", "✖️ FAILURE: Your platform does not have kube state metrics installed #{emoji_kube_state_metrics}") + upsert_failed_task("kube_state_metrics", "✖️ FAILED: Your platform does not have kube state metrics installed #{emoji_kube_state_metrics}") end end end @@ -56,12 +60,12 @@ namespace "platform" do task "node_exporter" do |_, args| unless check_poc(args) LOGGING.info "skipping node_exporter: not in poc mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: Node Exporter".colorize(:yellow) next end LOGGING.info "Running POC: node_exporter" Retriable.retry do - task_response = task_runner(args) do |args| + task_response = CNFManager::Task.task_runner(args) do |args| #Select the first node that isn't a master and is also schedulable #worker_nodes = `kubectl get nodes --selector='!node-role.kubernetes.io/master' -o 'go-template={{range .items}}{{$taints:=""}}{{range .spec.taints}}{{if eq .effect "NoSchedule"}}{{$taints = print $taints .key ","}}{{end}}{{end}}{{if not $taints}}{{.metadata.name}}{{ "\\n"}}{{end}}{{end}}'` @@ -69,16 +73,17 @@ namespace "platform" do # Install and find CRI Tools name File.write("cri_tools.yml", CRI_TOOLS) + #TODO use kubectlclient install_cri_tools = `kubectl create -f cri_tools.yml` pod_ready = "" pod_ready_timeout = 45 until (pod_ready == "true" || pod_ready_timeout == 0) - pod_ready = CNFManager.pod_status("cri-tools").split(",")[2] + pod_ready = KubectlClient::Get.pod_status("cri-tools").split(",")[2] puts "Pod Ready Status: #{pod_ready}" sleep 1 pod_ready_timeout = pod_ready_timeout - 1 end - cri_tools_pod = CNFManager.pod_status("cri-tools").split(",")[0] + cri_tools_pod = KubectlClient::Get.pod_status("cri-tools").split(",")[0] #, "--field-selector spec.nodeName=#{worker_node}") LOGGING.debug "cri_tools_pod: #{cri_tools_pod}" @@ -87,6 +92,7 @@ namespace "platform" do LOGGING.info "container_repo_digests: #{repo_digest_list}" id_sha256_list = repo_digest_list.reduce([] of String) do |acc, repo_digest| LOGGING.info "repo_digest: #{repo_digest}" + #TODO use kubectlclient cricti = `kubectl exec -ti #{cri_tools_pod} -- crictl inspecti #{repo_digest}` LOGGING.info "cricti: #{cricti}" begin @@ -101,13 +107,18 @@ namespace "platform" do # Fetch image id sha256sums available for all upstream node-exporter releases - node_exporter_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/prom/node-exporter/tags?page_size=1024'` + # node_exporter_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/prom/node-exporter/tags?page_size=1024'` + resp = Halite.get("https://registry.hub.docker.com/v2/repositories/prom/node-exporter/tags?page_size=1024") + node_exporter_releases = resp.body tag_list = named_sha_list(node_exporter_releases) LOGGING.info "tag_list: #{tag_list}" if ENV["DOCKERHUB_USERNAME"]? && ENV["DOCKERHUB_PASSWORD"]? target_ns_repo = "prom/node-exporter" params = "service=registry.docker.io&scope=repository:#{target_ns_repo}:pull" - token = `curl --user "#{ENV["DOCKERHUB_USERNAME"]}:#{ENV["DOCKERHUB_PASSWORD"]}" "https://auth.docker.io/token?#{params}"` + # token = `curl --user "#{ENV["DOCKERHUB_USERNAME"]}:#{ENV["DOCKERHUB_PASSWORD"]}" "https://auth.docker.io/token?#{params}"` + resp = Halite.basic_auth(user: ENV["DOCKERHUB_USERNAME"], pass: ENV["DOCKERHUB_PASSWORD"]). + get("https://auth.docker.io/token?#{params}") + token = resp.body LOGGING.debug "token: #{token}" if token =~ /incorrect username/ LOGGING.error "error: #{token}" @@ -117,7 +128,12 @@ namespace "platform" do LOGGING.info "tag: #{tag}" tag = tag["name"] - image_id = `curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}" -H "Authorization:Bearer #{parsed_token["token"].as_s}"` + # image_id = `curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}" -H "Authorization:Bearer #{parsed_token["token"].as_s}"` + resp = Halite.auth("Bearer #{parsed_token["token"].as_s}"). + get("https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}", + headers: {Accept: "application/vnd.docker.distribution.manifest.v2+json"}) + image_id = resp.body + parsed_image = JSON.parse(image_id) LOGGING.info "parsed_image config digest #{parsed_image["config"]["digest"]}" @@ -146,7 +162,7 @@ namespace "platform" do upsert_passed_task("node_exporter","✔️ PASSED: Your platform is using the #{release_name} release for the node exporter #{emoji_node_exporter}") else emoji_node_exporter="📶☠️" - upsert_failed_task("node_exporter", "✖️ FAILURE: Your platform does not have the node exporter installed #{emoji_node_exporter}") + upsert_failed_task("node_exporter", "✖️ FAILED: Your platform does not have the node exporter installed #{emoji_node_exporter}") end end end @@ -158,18 +174,20 @@ end task "prometheus_adapter" do |_, args| unless check_poc(args) LOGGING.info "skipping prometheus_adapter: not in poc mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: Prometheus Adapter".colorize(:yellow) next end LOGGING.info "Running POC: prometheus_adapter" Retriable.retry do - task_response = task_runner(args) do |args| + task_response = CNFManager::Task.task_runner(args) do |args| # Fetch image id sha256sums available for all upstream prometheus_adapter releases - prometheus_adapter_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/directxman12/k8s-prometheus-adapter-amd64/tags?page_size=1024'` + # prometheus_adapter_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/directxman12/k8s-prometheus-adapter-amd64/tags?page_size=1024'` + resp = Halite.get("https://registry.hub.docker.com/v2/repositories/directxman12/k8s-prometheus-adapter-amd64/tags?page_size=1024") + prometheus_adapter_releases = resp.body sha_list = named_sha_list(prometheus_adapter_releases) LOGGING.debug "sha_list: #{sha_list}" - # TODO find hash for image + # find hash for image imageids = KubectlClient::Get.all_container_repo_digests LOGGING.debug "imageids: #{imageids}" found = false @@ -186,7 +204,7 @@ end upsert_passed_task("prometheus_adapter","✔️ PASSED: Your platform is using the #{release_name} release for the prometheus adapter #{emoji_prometheus_adapter}") else emoji_prometheus_adapter="📶☠️" - upsert_failed_task("prometheus_adapter", "✖️ FAILURE: Your platform does not have the prometheus adapter installed #{emoji_prometheus_adapter}") + upsert_failed_task("prometheus_adapter", "✖️ FAILED: Your platform does not have the prometheus adapter installed #{emoji_prometheus_adapter}") end end end @@ -196,12 +214,12 @@ end task "metrics_server" do |_, args| unless check_poc(args) LOGGING.info "skipping metrics_server: not in poc mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: Metrics Server".colorize(:yellow) next end LOGGING.info "Running POC: metrics_server" Retriable.retry do - task_response = task_runner(args) do |args| + task_response = CNFManager::Task.task_runner(args) do |args| #Select the first node that isn't a master and is also schedulable #worker_nodes = `kubectl get nodes --selector='!node-role.kubernetes.io/master' -o 'go-template={{range .items}}{{$taints:=""}}{{range .spec.taints}}{{if eq .effect "NoSchedule"}}{{$taints = print $taints .key ","}}{{end}}{{end}}{{if not $taints}}{{.metadata.name}}{{ "\\n"}}{{end}}{{end}}'` @@ -213,12 +231,12 @@ end pod_ready = "" pod_ready_timeout = 45 until (pod_ready == "true" || pod_ready_timeout == 0) - pod_ready = CNFManager.pod_status("cri-tools").split(",")[2] + pod_ready = KubectlClient::Get.pod_status("cri-tools").split(",")[2] puts "Pod Ready Status: #{pod_ready}" sleep 1 pod_ready_timeout = pod_ready_timeout - 1 end - cri_tools_pod = CNFManager.pod_status("cri-tools").split(",")[0] + cri_tools_pod = KubectlClient::Get.pod_status("cri-tools").split(",")[0] #, "--field-selector spec.nodeName=#{worker_node}") LOGGING.debug "cri_tools_pod: #{cri_tools_pod}" @@ -241,13 +259,18 @@ end # Fetch image id sha256sums available for all upstream node-exporter releases - metrics_server_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/bitnami/metrics-server/tags?page=1'` + # metrics_server_releases = `curl -L -s 'https://registry.hub.docker.com/v2/repositories/bitnami/metrics-server/tags?page=1'` + resp = Halite.get("https://registry.hub.docker.com/v2/repositories/bitnami/metrics-server/tags?page=1") + metrics_server_releases = resp.body tag_list = named_sha_list(metrics_server_releases) LOGGING.info "tag_list: #{tag_list}" if ENV["DOCKERHUB_USERNAME"]? && ENV["DOCKERHUB_PASSWORD"]? target_ns_repo = "bitnami/metrics-server" params = "service=registry.docker.io&scope=repository:#{target_ns_repo}:pull" - token = `curl --user "#{ENV["DOCKERHUB_USERNAME"]}:#{ENV["DOCKERHUB_PASSWORD"]}" "https://auth.docker.io/token?#{params}"` + # token = `curl --user "#{ENV["DOCKERHUB_USERNAME"]}:#{ENV["DOCKERHUB_PASSWORD"]}" "https://auth.docker.io/token?#{params}"` + resp = Halite.basic_auth(user: ENV["DOCKERHUB_USERNAME"], pass: ENV["DOCKERHUB_PASSWORD"]). + get("https://auth.docker.io/token?#{params}") + token = resp.body if token =~ /incorrect username/ LOGGING.error "error: #{token}" end @@ -256,7 +279,11 @@ end LOGGING.debug "tag: #{tag}" tag = tag["name"] - image_id = `curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}" -H "Authorization:Bearer #{parsed_token["token"].as_s}"` + # image_id = `curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}" -H "Authorization:Bearer #{parsed_token["token"].as_s}"` + resp = Halite.auth("Bearer #{parsed_token["token"].as_s}"). + get("https://registry-1.docker.io/v2/#{target_ns_repo}/manifests/#{tag}", + headers: {Accept: "application/vnd.docker.distribution.manifest.v2+json"}) + image_id = resp.body parsed_image = JSON.parse(image_id) LOGGING.debug "parsed_image config digest #{parsed_image["config"]["digest"]}" @@ -285,7 +312,7 @@ end upsert_passed_task("metrics_server","✔️ PASSED: Your platform is using the #{release_name} release for the metrics server #{emoji_metrics_server}") else emoji_metrics_server="📶☠️" - upsert_failed_task("metrics_server", "✖️ FAILURE: Your platform does not have the metrics server installed #{emoji_metrics_server}") + upsert_failed_task("metrics_server", "✖️ FAILED: Your platform does not have the metrics server installed #{emoji_metrics_server}") end end end @@ -304,7 +331,7 @@ def named_sha_list(resp_json) end else parsed_json["results"].not_nil!.as_a.reduce([] of Hash(String, String)) do |acc, i| - #TODO always use amd64 + # always use amd64 amd64image = i["images"].as_a.find{|x| x["architecture"].as_s == "amd64"} LOGGING.debug "amd64image: #{amd64image}" if amd64image && amd64image["digest"]? diff --git a/src/tasks/platform/platform.cr b/src/tasks/platform/platform.cr index 2ecf7714b..935566a34 100644 --- a/src/tasks/platform/platform.cr +++ b/src/tasks/platform/platform.cr @@ -2,30 +2,26 @@ desc "Platform Tests" task "platform", ["helm_local_install", "k8s_conformance", "platform:observability", "platform:resilience", "platform:hardware_and_scheduling"] do |_, args| VERBOSE_LOGGING.info "platform" if check_verbose(args) - #TODO add CRYSTAL_ENV=TEST in new ISSUES when testing ./cnf-conformance platform or ./cnf-conformance all - total = total_points("platform") + total = CNFManager::Points.total_points("platform") if total > 0 - #TODO make new platform_total_points and platform_total_max_points - stdout_success "Final platform score: #{total} of #{total_max_points("platform")}" + stdout_success "Final platform score: #{total} of #{CNFManager::Points.total_max_points("platform")}" else - stdout_failure "Final platform score: #{total} of #{total_max_points("platform")}" + stdout_failure "Final platform score: #{total} of #{CNFManager::Points.total_max_points("platform")}" end - if failed_required_tasks.size > 0 + if CNFManager::Points.failed_required_tasks.size > 0 stdout_failure "Conformance Suite failed!" - stdout_failure "Failed required tasks: #{failed_required_tasks.inspect}" + stdout_failure "Failed required tasks: #{CNFManager::Points.failed_required_tasks.inspect}" end - stdout_info "Results have been saved to #{Results.file}".colorize(:green) + stdout_info "CNFManager::Points::Results.have been saved to #{CNFManager::Points::Results.file}".colorize(:green) end desc "Does the platform pass the K8s conformance tests?" task "k8s_conformance" do |_, args| VERBOSE_LOGGING.info "k8s_conformance" if check_verbose(args) begin - #TODO enable full test with production mode - #sonobuoy = `sonobuoy run --wait` if PRODUCTION_MODE and not in test_mode - current_dir = FileUtils.pwd + current_dir = FileUtils.pwd VERBOSE_LOGGING.debug current_dir if check_verbose(args) sonobuoy = "#{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy" @@ -34,7 +30,6 @@ task "k8s_conformance" do |_, args| VERBOSE_LOGGING.info delete if check_verbose(args) # Run the tests - #TODO when in test mode --mode quick, prod mode no quick testrun = "" VERBOSE_LOGGING.info ENV["CRYSTAL_ENV"]? if check_verbose(args) if ENV["CRYSTAL_ENV"]? == "TEST" @@ -46,13 +41,15 @@ task "k8s_conformance" do |_, args| end VERBOSE_LOGGING.info testrun if check_verbose(args) - results = `results=$(#{sonobuoy} retrieve); #{sonobuoy} results $results` + results = `results=$(#{sonobuoy} retrieve); #{sonobuoy} results $results` VERBOSE_LOGGING.info results if check_verbose(args) # Grab the failed line from the results + failed_count = ((results.match(/Failed: (.*)/)).try &.[1]) if failed_count.to_s.to_i > 0 - upsert_failed_task("k8s_conformance", "✖️ FAILURE: K8s conformance test has #{failed_count} failure(s)!") + upsert_failed_task("k8s_conformance", "✖️ FAILED: K8s conformance test has #{failed_count} failure(s)!") + else upsert_passed_task("k8s_conformance", "✔️ PASSED: K8s conformance test has no failures") end @@ -69,10 +66,10 @@ end desc "Is Cluster Api available and managing a cluster?" task "clusterapi_enabled" do |_, args| - task_runner(args) do + CNFManager::Task.task_runner(args) do unless check_poc(args) LOGGING.info "skipping clusterapi_enabled: not in poc mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: ClusterAPI Enabled".colorize(:yellow) next end @@ -107,10 +104,11 @@ task "clusterapi_enabled" do |_, args| clusterapi_control_planes_json = proc_clusterapi_control_planes_json.call LOGGING.info("clusterapi_control_planes_json: #{clusterapi_control_planes_json}") - if clusterapi_namespaces_json["items"]?.not_nil! && clusterapi_namespaces_json["items"].as_a.size > 0 && clusterapi_control_planes_json["items"]?.not_nil! && clusterapi_control_planes_json["items"].as_a.size > 0 - resp = upsert_passed_task("clusterapi_enabled", "✔️ Cluster API is enabled ✨") + emoji_control="✨" + if clusterapi_namespaces_json["items"]? && clusterapi_namespaces_json["items"].as_a.size > 0 && clusterapi_control_planes_json["items"]? && clusterapi_control_planes_json["items"].as_a.size > 0 + resp = upsert_passed_task("clusterapi_enabled", "✔️ Cluster API is enabled #{emoji_control}") else - resp = upsert_failed_task("clusterapi_enabled","✖️ Cluster API NOT enabled ✨") + resp = upsert_failed_task("clusterapi_enabled", "✖️ Cluster API NOT enabled #{emoji_control}") end resp diff --git a/src/tasks/platform/resilience.cr b/src/tasks/platform/resilience.cr index 1a75966e7..e9a7a3b39 100644 --- a/src/tasks/platform/resilience.cr +++ b/src/tasks/platform/resilience.cr @@ -16,37 +16,36 @@ namespace "platform" do task "worker_reboot_recovery" do |_, args| unless check_destructive(args) LOGGING.info "skipping node_failure: not in destructive mode" - puts "Skipped".colorize(:yellow) + puts "SKIPPED: Node Failure".colorize(:yellow) next end LOGGING.info "Running POC in destructive mode!" - task_response = task_runner(args) do |args| - current_dir = FileUtils.pwd - #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm + task_response = CNFManager::Task.task_runner(args) do |args| + current_dir = FileUtils.pwd + helm = CNFSingleton.helm #Select the first node that isn't a master and is also schedulable worker_nodes = `kubectl get nodes --selector='!node-role.kubernetes.io/master' -o 'go-template={{range .items}}{{$taints:=""}}{{range .spec.taints}}{{if eq .effect "NoSchedule"}}{{$taints = print $taints .key ","}}{{end}}{{end}}{{if not $taints}}{{.metadata.name}}{{ "\\n"}}{{end}}{{end}}'` worker_node = worker_nodes.split("\n")[0] - File.write("node_failure_values.yml", NODE_FAILURE_VALUES) + File.write("node_failure_values.yml", NODE_FAILED_VALUES) install_coredns = `#{helm} install node-failure -f ./node_failure_values.yml --set nodeSelector."kubernetes\\.io/hostname"=#{worker_node} stable/coredns` - CNFManager.wait_for_install("node-failure-coredns") + KubectlClient::Get.wait_for_install("node-failure-coredns") File.write("reboot_daemon_pod.yml", REBOOT_DAEMON) install_reboot_daemon = `kubectl create -f reboot_daemon_pod.yml` - CNFManager.wait_for_install("node-failure-coredns") + KubectlClient::Get.wait_for_install("node-failure-coredns") pod_ready = "" pod_ready_timeout = 45 begin until (pod_ready == "true" || pod_ready_timeout == 0) - pod_ready = CNFManager.pod_status("reboot", "--field-selector spec.nodeName=#{worker_node}").split(",")[2] + pod_ready = KubectlClient::Get.pod_status("reboot", "--field-selector spec.nodeName=#{worker_node}").split(",")[2] pod_ready_timeout = pod_ready_timeout - 1 if pod_ready_timeout == 0 - upsert_failed_task("worker_reboot_recovery", "✖️ FAILURE: Failed to install reboot daemon") + upsert_failed_task("worker_reboot_recovery", "✖️ FAILED: Failed to install reboot daemon") exit 1 end sleep 1 @@ -55,7 +54,7 @@ namespace "platform" do end # Find Reboot Daemon name - reboot_daemon_pod = CNFManager.pod_status("reboot", "--field-selector spec.nodeName=#{worker_node}").split(",")[0] + reboot_daemon_pod = KubectlClient::Get.pod_status("reboot", "--field-selector spec.nodeName=#{worker_node}").split(",")[0] start_reboot = `kubectl exec -ti #{reboot_daemon_pod} touch /tmp/reboot` #Watch for Node Failure. @@ -63,14 +62,14 @@ namespace "platform" do node_ready = "" node_failure_timeout = 30 until (pod_ready == "false" || node_ready == "False" || node_ready == "Unknown" || node_failure_timeout == 0) - pod_ready = CNFManager.pod_status("node-failure").split(",")[2] - node_ready = CNFManager.node_status("#{worker_node}") + pod_ready = KubectlClient::Get.pod_status("node-failure").split(",")[2] + node_ready = KubectlClient::Get.node_status("#{worker_node}") puts "Waiting for Node to go offline" puts "Pod Ready Status: #{pod_ready}" puts "Node Ready Status: #{node_ready}" node_failure_timeout = node_failure_timeout - 1 if node_failure_timeout == 0 - upsert_failed_task("worker_reboot_recovery", "✖️ FAILURE: Node failed to go offline") + upsert_failed_task("worker_reboot_recovery", "✖️ FAILED: Node failed to go offline") exit 1 end sleep 1 @@ -81,14 +80,14 @@ namespace "platform" do node_ready = "" node_online_timeout = 300 until (pod_ready == "true" && node_ready == "True" || node_online_timeout == 0) - pod_ready = CNFManager.pod_status("node-failure", "").split(",")[2] - node_ready = CNFManager.node_status("#{worker_node}") + pod_ready = KubectlClient::Get.pod_status("node-failure", "").split(",")[2] + node_ready = KubectlClient::Get.node_status("#{worker_node}") puts "Waiting for Node to come back online" puts "Pod Ready Status: #{pod_ready}" puts "Node Ready Status: #{node_ready}" node_online_timeout = node_online_timeout - 1 if node_online_timeout == 0 - upsert_failed_task("worker_reboot_recovery", "✖️ FAILURE: Node failed to come back online") + upsert_failed_task("worker_reboot_recovery", "✖️ FAILED: Node failed to come back online") exit 1 end sleep 1 diff --git a/src/tasks/prereqs.cr b/src/tasks/prereqs.cr index 6595c1918..69fc700d3 100644 --- a/src/tasks/prereqs.cr +++ b/src/tasks/prereqs.cr @@ -3,8 +3,8 @@ require "file_utils" require "colorize" require "totem" require "./utils/system_information/helm.cr" -require "./utils/system_information/wget.cr" -require "./utils/system_information/curl.cr" +# require "./utils/system_information/wget.cr" +# require "./utils/system_information/curl.cr" require "./utils/system_information/kubectl.cr" require "./utils/system_information/git.cr" require "./utils/system_information/clusterctl.cr" @@ -13,9 +13,9 @@ task "prereqs" do |_, args| verbose = check_verbose(args) if (helm_installation.includes?("helm found") && - !CNFManager.helm_gives_k8s_warning?(true)) & - wget_installation.includes?("wget found") & - curl_installation.includes?("curl found") & + !Helm.helm_gives_k8s_warning?(true)) & + # wget_installation.includes?("wget found") & + # curl_installation.includes?("curl found") & kubectl_installation.includes?("kubectl found") & git_installation.includes?("git found") diff --git a/src/tasks/resilience.cr b/src/tasks/resilience.cr deleted file mode 100644 index 0fbb3a888..000000000 --- a/src/tasks/resilience.cr +++ /dev/null @@ -1,218 +0,0 @@ -# coding: utf-8 -require "sam" -require "colorize" -require "crinja" -require "./utils/utils.cr" - -desc "The CNF conformance suite checks to see if the CNFs are resilient to failures." -task "resilience", ["chaos_network_loss", "chaos_cpu_hog", "chaos_container_kill" ] do |t, args| - VERBOSE_LOGGING.info "resilience" if check_verbose(args) - VERBOSE_LOGGING.debug "resilience args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "resilience args.named: #{args.named}" if check_verbose(args) - stdout_score("resilience") -end - -desc "Does the CNF crash when network loss occurs" -task "chaos_network_loss", ["install_chaosmesh", "retrieve_manifest"] do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "chaos_network_loss" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment_name = config.get("deployment_name").as_s - deployment_label = config.get("deployment_label").as_s - helm_chart_container_name = config.get("helm_chart_container_name").as_s - LOGGING.debug "#{destination_cnf_dir}" - LOGGING.info "destination_cnf_dir #{destination_cnf_dir}" - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - emoji_chaos_network_loss="📶☠️" - - errors = 0 - begin - deployment_label_value = deployment.get("metadata").as_h["labels"].as_h[deployment_label].as_s - rescue ex - errors = errors + 1 - LOGGING.error ex.message - end - if errors < 1 - template = Crinja.render(network_chaos_template, { "deployment_label" => "#{deployment_label}", "deployment_label_value" => "#{deployment_label_value}" }) - chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_network_loss.yml"` - VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) - run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_network_loss.yml"` - VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) - # TODO fail if exceeds - if wait_for_test("NetworkChaos", "network-loss") - LOGGING.info( "Wait Done") - if desired_is_available?(deployment_name) - resp = upsert_passed_task("chaos_network_loss","✔️ PASSED: Replicas available match desired count after network chaos test #{emoji_chaos_network_loss}") - else - resp = upsert_failed_task("chaos_network_loss","✖️ FAILURE: Replicas did not return desired count after network chaos test #{emoji_chaos_network_loss}") - end - else - # TODO Change this to an exception (points = 0) - # e.g. upsert_exception_task - resp = upsert_failed_task("chaos_network_loss","✖️ FAILURE: Chaosmesh failed to finish.") - end - delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_network_loss.yml"` - else - resp = upsert_failed_task("chaos_network_loss","✖️ FAILURE: No deployment label found for network chaos test") - end - end -end - -desc "Does the CNF crash when CPU usage is high" -task "chaos_cpu_hog", ["install_chaosmesh", "retrieve_manifest"] do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "chaos_cpu_hog" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment_name = config.get("deployment_name").as_s - deployment_label = config.get("deployment_label").as_s - helm_chart_container_name = config.get("helm_chart_container_name").as_s - LOGGING.debug "#{destination_cnf_dir}" - LOGGING.info "destination_cnf_dir #{destination_cnf_dir}" - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - emoji_chaos_cpu_hog="📦💻🐷📈" - - errors = 0 - begin - deployment_label_value = deployment.get("metadata").as_h["labels"].as_h[deployment_label].as_s - rescue ex - errors = errors + 1 - LOGGING.error ex.message - end - if errors < 1 - template = Crinja.render(cpu_chaos_template, { "deployment_label" => "#{deployment_label}", "deployment_label_value" => "#{deployment_label_value}" }) - chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_cpu_hog.yml"` - VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) - run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_cpu_hog.yml"` - VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) - # TODO fail if exceeds - if wait_for_test("StressChaos", "burn-cpu") - if desired_is_available?(deployment_name) - resp = upsert_passed_task("chaos_cpu_hog","✔️ PASSED: Application pod is healthy after high CPU consumption #{emoji_chaos_cpu_hog}") - else - resp = upsert_failed_task("chaos_cpu_hog","✖️ FAILURE: Application pod is not healthy after high CPU consumption #{emoji_chaos_cpu_hog}") - end - else - # TODO Change this to an exception (points = 0) - # e.g. upsert_exception_task - resp = upsert_failed_task("chaos_cpu_hog","✖️ FAILURE: Chaosmesh failed to finish.") - end - delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_cpu_hog.yml"` - else - resp = upsert_failed_task("chaos_cpu_hog","✖️ FAILURE: No deployment label found for cpu chaos test") - end - end -end - -desc "Does the CNF recover when its container is killed" -task "chaos_container_kill", ["install_chaosmesh", "retrieve_manifest"] do |_, args| - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "chaos_container_kill" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment_name = config.get("deployment_name").as_s - deployment_label = config.get("deployment_label").as_s - helm_chart_container_name = config.get("helm_chart_container_name").as_s - LOGGING.debug "#{destination_cnf_dir}" - LOGGING.info "destination_cnf_dir #{destination_cnf_dir}" - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - emoji_chaos_container_kill="🗡️💀♻️" - - errors = 0 - begin - deployment_label_value = deployment.get("metadata").as_h["labels"].as_h[deployment_label].as_s - rescue ex - errors = errors + 1 - LOGGING.error ex.message - end - if errors < 1 - template = Crinja.render(chaos_template_container_kill, { "deployment_label" => "#{deployment_label}", "deployment_label_value" => "#{deployment_label_value}", "helm_chart_container_name" => "#{helm_chart_container_name}" }) - chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_container_kill.yml"` - VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) - run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_container_kill.yml"` - VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) - # TODO fail if exceeds - if wait_for_test("PodChaos", "container-kill") - CNFManager.wait_for_install(deployment_name, wait_count=60) - if desired_is_available?(deployment_name) - resp = upsert_passed_task("chaos_container_kill","✔️ PASSED: Replicas available match desired count after container kill test #{emoji_chaos_container_kill}") - else - resp = upsert_failed_task("chaos_container_kill","✖️ FAILURE: Replicas did not return desired count after container kill test #{emoji_chaos_container_kill}") - end - else - # TODO Change this to an exception (points = 0) - # e.g. upsert_exception_task - resp = upsert_failed_task("chaos_container_kill","✖️ FAILURE: Chaosmesh failed to finish.") - end - delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_container_kill.yml"` - else - resp = upsert_failed_task("chaos_container_kill","✖️ FAILURE: No deployment label found for container kill test") - end - end -end - - -def network_chaos_template - <<-TEMPLATE - apiVersion: pingcap.com/v1alpha1 - kind: NetworkChaos - metadata: - name: network-loss - namespace: default - spec: - action: loss - mode: one - selector: - labelSelectors: - '{{ deployment_label}}': '{{ deployment_label_value }}' - loss: - loss: '100' - correlation: '100' - duration: '40s' - scheduler: - cron: '@every 600s' - TEMPLATE -end - -def cpu_chaos_template - <<-TEMPLATE - apiVersion: pingcap.com/v1alpha1 - kind: StressChaos - metadata: - name: burn-cpu - namespace: default - spec: - mode: one - selector: - labelSelectors: - '{{ deployment_label}}': '{{ deployment_label_value }}' - stressors: - cpu: - workers: 1 - load: 100 - options: ['-c 0'] - duration: '40s' - scheduler: - cron: '@every 600s' - TEMPLATE -end - -def chaos_template_container_kill - <<-TEMPLATE - apiVersion: pingcap.com/v1alpha1 - kind: PodChaos - metadata: - name: container-kill - namespace: default - spec: - action: container-kill - mode: one - containerName: '{{ helm_chart_container_name }}' - selector: - labelSelectors: - '{{ deployment_label}}': '{{ deployment_label_value }}' - scheduler: - cron: '@every 600s' - TEMPLATE -end diff --git a/src/tasks/scalability.cr b/src/tasks/scalability.cr deleted file mode 100644 index 0b54f5570..000000000 --- a/src/tasks/scalability.cr +++ /dev/null @@ -1,124 +0,0 @@ -# coding: utf-8 -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "./utils/utils.cr" - -desc "The CNF conformance suite checks to see if CNFs support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines) by using the native K8s kubectl" -task "scalability", ["increase_decrease_capacity"] do |t, args| - VERBOSE_LOGGING.info "scalability" if check_verbose(args) - VERBOSE_LOGGING.debug "scaling args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "scaling args.named: #{args.named}" if check_verbose(args) - # t.invoke("increase_decrease_capacity", args) - stdout_score("scalability") -end - -desc "Test increasing/decreasing capacity" -task "increase_decrease_capacity", ["increase_capacity", "decrease_capacity"] do |t, args| - VERBOSE_LOGGING.info "increase_decrease_capacity" if check_verbose(args) -end - - -desc "Test increasing capacity by setting replicas to 1 and then increasing to 3" -task "increase_capacity" do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "increase_capacity" if check_verbose(args) - emoji_increase_capacity="📦📈" - - target_replicas = "3" - base_replicas = "1" - final_count = change_capacity(base_replicas, target_replicas, args) - if target_replicas == final_count - upsert_passed_task("increase_capacity", "✔️ PASSED: Replicas increased to #{target_replicas} #{emoji_increase_capacity}") - else - upsert_failed_task("increase_capacity", "✖️ FAILURE: Replicas did not reach #{target_replicas} #{emoji_increase_capacity}") - end - end -end - -desc "Test decrease capacity by setting replicas to 3 and then decreasing to 1" -task "decrease_capacity" do |_, args| - task_runner(args) do |args| - VERBOSE_LOGGING.info "decrease_capacity" if check_verbose(args) - target_replicas = "1" - base_replicas = "3" - final_count = change_capacity(base_replicas, target_replicas, args) - emoji_decrease_capacity="📦📉" - - if target_replicas == final_count - upsert_passed_task("decrease_capacity", "✔️ PASSED: Replicas decreased to #{target_replicas} #{emoji_decrease_capacity}") - else - upsert_failed_task("decrease_capacity", "✖️ FAILURE: Replicas did not reach #{target_replicas} #{emoji_decrease_capacity}") - end - end -end - -def change_capacity(base_replicas, target_replica_count, args) - VERBOSE_LOGGING.info "change_capacity" if check_verbose(args) - VERBOSE_LOGGING.debug "increase_capacity args.raw: #{args.raw}" if check_verbose(args) - VERBOSE_LOGGING.debug "increase_capacity args.named: #{args.named}" if check_verbose(args) - VERBOSE_LOGGING.info "base replicas: #{base_replicas}" if check_verbose(args) - - # Parse the cnf-conformance.yml - # config = cnf_conformance_yml - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - - initialization_time = base_replicas.to_i * 10 - if args.named.keys.includes? "deployment_name" - deployment_name = args.named["deployment_name"] - else - deployment_name = config.get("deployment_name").as_s - end - VERBOSE_LOGGING.info "deployment_name: #{deployment_name}" if check_verbose(args) - - base = `kubectl scale deployment.v1.apps/#{deployment_name} --replicas=#{base_replicas}` - VERBOSE_LOGGING.info "base: #{base}" if check_verbose(args) - initialized_count = wait_for_scaling(deployment_name, base_replicas, args) - if initialized_count != base_replicas - VERBOSE_LOGGING.info "deployment initialized to #{initialized_count} and could not be set to #{base_replicas}" if check_verbose(args) - else - VERBOSE_LOGGING.info "deployment initialized to #{initialized_count}" if check_verbose(args) - end - - increase = `kubectl scale deployment.v1.apps/#{deployment_name} --replicas=#{target_replica_count}` - current_replicas = wait_for_scaling(deployment_name, target_replica_count, args) - current_replicas -end - -def wait_for_scaling(deployment_name, target_replica_count, args) - VERBOSE_LOGGING.info "target_replica_count: #{target_replica_count}" if check_verbose(args) - if args.named.keys.includes? "wait_count" - wait_count_value = args.named["wait_count"] - else - wait_count_value = "30" - end - wait_count = wait_count_value.to_i - second_count = 0 - current_replicas = "0" - previous_replicas = `kubectl get deployments #{deployment_name} -o=jsonpath='{.status.readyReplicas}'` - until current_replicas == target_replica_count || second_count > wait_count - VERBOSE_LOGGING.debug "secound_count: #{second_count} wait_count: #{wait_count}" if check_verbose(args) - VERBOSE_LOGGING.info "current_replicas before get deployments: #{current_replicas}" if check_verbose(args) - sleep 1 - VERBOSE_LOGGING.debug `echo $KUBECONFIG` if check_verbose(args) - VERBOSE_LOGGING.info "Get deployments command: kubectl get deployments #{deployment_name} -o=jsonpath='{.status.readyReplicas}'" if check_verbose(args) - current_replicas = `kubectl get deployments #{deployment_name} -o=jsonpath='{.status.readyReplicas}'` - VERBOSE_LOGGING.info "current_replicas after get deployments: #{current_replicas.inspect}" if check_verbose(args) - - if current_replicas.empty? - current_replicas = "0" - previous_replicas = "0" - end - - if current_replicas.to_i != previous_replicas.to_i - second_count = 0 - previous_replicas = current_replicas - end - second_count = second_count + 1 - VERBOSE_LOGGING.info "previous_replicas: #{previous_replicas}" if check_verbose(args) - VERBOSE_LOGGING.info "current_replicas: #{current_replicas}" if check_verbose(args) - end - current_replicas -end - diff --git a/src/tasks/security.cr b/src/tasks/security.cr deleted file mode 100644 index 0454c4f38..000000000 --- a/src/tasks/security.cr +++ /dev/null @@ -1,39 +0,0 @@ -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "./utils/utils.cr" - -desc "CNF containers should be isolated from one another and the host. The CNF Conformance suite uses tools like Falco, Sysdig Inspect and gVisor" -task "security", ["privileged"] do |_, args| - stdout_score("security") -end - -desc "Check if any containers are running in privileged mode" -task "privileged" do |_, args| - #TODO Document all arguments - #TODO check if container exists - #TODO Check if args exist - task_runner(args) do |args| - VERBOSE_LOGGING.info "privileged" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - - helm_chart_container_name = config.get("helm_chart_container_name").as_s - white_list_container_name = config.get("white_list_helm_chart_container_names").as_a - VERBOSE_LOGGING.info "helm_chart_container_name #{helm_chart_container_name}" if check_verbose(args) - VERBOSE_LOGGING.info "white_list_container_name #{white_list_container_name.inspect}" if check_verbose(args) - privileged_response = `kubectl get pods --all-namespaces -o jsonpath='{.items[*].spec.containers[?(@.securityContext.privileged==true)].name}'` - VERBOSE_LOGGING.info "privileged_response #{privileged_response}" if check_verbose(args) - privileged_list = privileged_response.to_s.split(" ").uniq - VERBOSE_LOGGING.info "privileged_list #{privileged_list}" if check_verbose(args) - white_list_containers = ((PRIVILEGED_WHITELIST_CONTAINERS + white_list_container_name) - [helm_chart_container_name]) - violation_list = (privileged_list - white_list_containers) - emoji_security="🔓🔑" - if privileged_list.find {|x| x == helm_chart_container_name} || - violation_list.size > 0 - upsert_failed_task("privileged", "✖️ FAILURE: Found #{violation_list.size} privileged containers: #{violation_list.inspect} #{emoji_security}") - else - upsert_passed_task("privileged", "✔️ PASSED: No privileged containers #{emoji_security}") - end - end -end diff --git a/src/tasks/setup.cr b/src/tasks/setup.cr index c3a7dadda..8a90fff38 100644 --- a/src/tasks/setup.cr +++ b/src/tasks/setup.cr @@ -10,6 +10,6 @@ end task "configuration_file_setup" do |_, args| VERBOSE_LOGGING.info "configuration_file_setup" if check_verbose(args) - create_points_yml + CNFManager::Points.create_points_yml end diff --git a/src/tasks/sonobuoy_setup.cr b/src/tasks/sonobuoy_setup.cr index 4564e222c..28d17223a 100644 --- a/src/tasks/sonobuoy_setup.cr +++ b/src/tasks/sonobuoy_setup.cr @@ -3,6 +3,7 @@ require "file_utils" require "colorize" require "totem" require "http/client" +require "halite" require "./utils/utils.cr" desc "Sets up Sonobuoy in the K8s Cluster" @@ -21,8 +22,18 @@ task "install_sonobuoy" do |_, args| VERBOSE_LOGGING.debug "toolsdir : #{TOOLS_DIR}" if check_verbose(args) VERBOSE_LOGGING.debug "full path?: #{current_dir.to_s}/#{TOOLS_DIR}/sonobuoy" if check_verbose(args) FileUtils.mkdir_p("#{current_dir}/#{TOOLS_DIR}/sonobuoy") - curl = `VERSION="#{k8s_version}" OS=linux ; curl -L "https://github.com/vmware-tanzu/sonobuoy/releases/download/v${VERSION}/sonobuoy_${VERSION}_${OS}_amd64.tar.gz" --output #{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy.tar.gz` - VERBOSE_LOGGING.debug curl if check_verbose(args) + # curl = `VERSION="#{k8s_version}" OS=linux ; curl -L "https://github.com/vmware-tanzu/sonobuoy/releases/download/v${VERSION}/sonobuoy_${VERSION}_${OS}_amd64.tar.gz" --output #{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy.tar.gz` + os="linux" + url = "https://github.com/vmware-tanzu/sonobuoy/releases/download/v#{k8s_version}/sonobuoy_#{k8s_version}_#{os}_amd64.tar.gz" + write_file = "#{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy.tar.gz" + LOGGING.info "url: #{url}" + LOGGING.info "write_file: #{write_file}" + resp = Halite.follow.get("#{url}") do |response| + File.write("#{write_file}", response.body_io) + end + LOGGING.info "resp: #{resp}" + LOGGING.info "resp: #{resp}" + # VERBOSE_LOGGING.debug curl if check_verbose(args) `tar -xzf #{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy.tar.gz -C #{current_dir}/#{TOOLS_DIR}/sonobuoy/ && \ chmod +x #{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy && \ rm #{current_dir}/#{TOOLS_DIR}/sonobuoy/sonobuoy.tar.gz` diff --git a/src/tasks/statelessness.cr b/src/tasks/statelessness.cr deleted file mode 100644 index e5eec6f0d..000000000 --- a/src/tasks/statelessness.cr +++ /dev/null @@ -1,43 +0,0 @@ -# coding: utf-8 -require "sam" -require "file_utils" -require "colorize" -require "totem" -require "./utils/utils.cr" - -desc "The CNF conformance suite checks if state is stored in a custom resource definition or a separate database (e.g. etcd) rather than requiring local storage. It also checks to see if state is resilient to node failure" -task "statelessness", ["volume_hostpath_not_found"] do |_, args| - stdout_score("statelessness") -end - -desc "Does the CNF use a non-cloud native data store: hostPath volume" -task "volume_hostpath_not_found", ["retrieve_manifest"] do |_, args| - failed_emoji = "(ভ_ভ) ރ 💾" - passed_emoji = "🖥️ 💾" - task_response = task_runner(args) do |args| - VERBOSE_LOGGING.info "volume_hostpath_not_found" if check_verbose(args) - config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) - destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) - deployment = Totem.from_file "#{destination_cnf_dir}/manifest.yml" - VERBOSE_LOGGING.info deployment.inspect if check_verbose(args) - - hostPath_found = nil - begin - volumes = deployment.get("spec").as_h["template"].as_h["spec"].as_h["volumes"].as_a - hostPath_found = volumes.find do |volume| - if volume.as_h["hostPath"]? - true - end - end - rescue ex - VERBOSE_LOGGING.error ex.message if check_verbose(args) - upsert_failed_task("volume_hostpath_not_found","✖️ FAILURE: hostPath volumes found #{failed_emoji}") - end - - if hostPath_found - upsert_failed_task("volume_hostpath_not_found","✖️ FAILURE: hostPath volumes found #{failed_emoji}") - else - upsert_passed_task("volume_hostpath_not_found","✔️ PASSED: hostPath volumes not found #{passed_emoji}") - end - end -end diff --git a/src/tasks/utils/cnf_manager.cr b/src/tasks/utils/cnf_manager.cr index 7a6946f6d..130a4425b 100644 --- a/src/tasks/utils/cnf_manager.cr +++ b/src/tasks/utils/cnf_manager.cr @@ -2,14 +2,107 @@ require "totem" require "colorize" require "./types/cnf_conformance_yml_type.cr" +require "./helm.cr" +require "uuid" +require "./points.cr" +require "./task.cr" +require "./config.cr" -module CNFManager - def self.final_cnf_results_yml - results_file = `find ./results/* -name "cnf-conformance-results-*.yml"`.split("\n")[-2].gsub("./", "") - if results_file.empty? - raise "No cnf_conformance-results-*.yml found! Did you run the all task?" +module CNFManager + + # Applies a block to each cnf resource + # + # `CNFManager.cnf_workload_resources(args, config) {|cnf_config, resource| #your code} + def self.cnf_workload_resources(args, config, &block) + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + yml_file_path = config.cnf_config[:yml_file_path] + helm_directory = config.cnf_config[:helm_directory] + manifest_directory = config.cnf_config[:manifest_directory] + release_name = config.cnf_config[:release_name] + helm_chart_path = config.cnf_config[:helm_chart_path] + manifest_file_path = config.cnf_config[:manifest_file_path] + test_passed = true + if release_name.empty? # no helm chart + template_ymls = Helm::Manifest.manifest_ymls_from_file_list(Helm::Manifest.manifest_file_list( destination_cnf_dir + "/" + manifest_directory)) + else + Helm.generate_manifest_from_templates(release_name, + helm_chart_path, + manifest_file_path) + template_ymls = Helm::Manifest.parse_manifest_as_ymls(manifest_file_path) + end + resource_ymls = Helm.all_workload_resources(template_ymls) + resource_resp = resource_ymls.map do | resource | + resp = yield resource + LOGGING.debug "cnf_workload_resource yield resp: #{resp}" + resp + end + resource_resp + end + + #test_passes_completely = workload_resource_test do | cnf_config, resource, container, initialized | + def self.workload_resource_test(args, config, + check_containers = true, + check_service = false, + &block : (NamedTuple(kind: YAML::Any, name: YAML::Any), + JSON::Any, JSON::Any, Bool | Nil) -> Bool | Nil) + # resp = yield resource, container, volumes, initialized + test_passed = true + resource_ymls = cnf_workload_resources(args, config) do |resource| + resource + end + resource_names = Helm.workload_resource_kind_names(resource_ymls) + LOGGING.info "resource names: #{resource_names}" + if resource_names && resource_names.size > 0 + initialized = true + else + LOGGING.error "no resource names found" + initialized = false + end + resource_names.each do | resource | + VERBOSE_LOGGING.debug resource.inspect if check_verbose(args) + volumes = KubectlClient::Get.resource_volumes(resource[:kind].as_s, resource[:name].as_s) + VERBOSE_LOGGING.debug "check_service: #{check_service}" if check_verbose(args) + VERBOSE_LOGGING.debug "check_containers: #{check_containers}" if check_verbose(args) + case resource[:kind].as_s.downcase + when "service" + if check_service + LOGGING.info "checking service: #{resource}" + resp = yield resource, JSON.parse(%([{}])), volumes, initialized + LOGGING.debug "yield resp: #{resp}" + # if any response is false, the test fails + test_passed = false if resp == false + end + else + containers = KubectlClient::Get.resource_containers(resource[:kind].as_s, resource[:name].as_s) + if check_containers + containers.as_a.each do |container| + resp = yield resource, container, volumes, initialized + LOGGING.debug "yield resp: #{resp}" + # if any response is false, the test fails + test_passed = false if resp == false + end + else + resp = yield resource, containers, volumes, initialized + LOGGING.debug "yield resp: #{resp}" + # if any response is false, the test fails + test_passed = false if resp == false + end + end + end + LOGGING.debug "workload resource test intialized: #{initialized} test_passed: #{test_passed}" + initialized && test_passed + end + + def self.cnf_installed? + LOGGING.info("cnf_config_list") + LOGGING.info("find: find #{CNF_DIR}/* -name #{CONFIG_FILE}") + cnf_conformance = `find #{CNF_DIR}/* -name "#{CONFIG_FILE}"`.split("\n").select{|x| x.empty? == false} + LOGGING.info("find response: #{cnf_conformance}") + if cnf_conformance.size == 0 + false + else + true end - results_file end def self.cnf_config_list(silent=false) @@ -35,6 +128,7 @@ module CNFManager end def self.sample_conformance_yml(sample_dir) + LOGGING.info "sample_conformance_yml sample_dir: #{sample_dir}" cnf_conformance = `find #{sample_dir}/* -name "cnf-conformance.yml"`.split("\n")[0] if cnf_conformance.empty? raise "No cnf_conformance.yml found in #{sample_dir}!" @@ -42,95 +136,8 @@ module CNFManager Totem.from_file "./#{cnf_conformance}" end - def self.wait_for_install(deployment_name, wait_count=180, namespace="default") - second_count = 0 - all_deployments = `kubectl get deployments --namespace=#{namespace}` - desired_replicas = `kubectl get deployments --namespace=#{namespace} #{deployment_name} -o=jsonpath='{.status.replicas}'` - current_replicas = `kubectl get deployments --namespace=#{namespace} #{deployment_name} -o=jsonpath='{.status.readyReplicas}'` - LOGGING.info(all_deployments) - until (current_replicas.empty? != true && current_replicas.to_i == desired_replicas.to_i) || second_count > wait_count.to_i - LOGGING.info("second_count = #{second_count}") - sleep 1 - all_deployments = `kubectl get deployments --namespace=#{namespace}` - current_replicas = `kubectl get deployments --namespace=#{namespace} #{deployment_name} -o=jsonpath='{.status.readyReplicas}'` - LOGGING.info(all_deployments) - second_count = second_count + 1 - end - end - - def self.wait_for_install_by_apply(manifest_file, wait_count=180) - LOGGING.info "wait_for_install_by_apply" - second_count = 0 - apply_resp = `kubectl apply -f #{manifest_file}` - LOGGING.info("apply response: #{apply_resp}") - until (apply_resp =~ /dockercluster.infrastructure.cluster.x-k8s.io\/capd unchanged/) != nil && (apply_resp =~ /cluster.cluster.x-k8s.io\/capd unchanged/) != nil && (apply_resp =~ /kubeadmcontrolplane.controlplane.cluster.x-k8s.io\/capd-control-plane unchanged/) != nil && (apply_resp =~ /kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io\/capd-md-0 unchanged/) !=nil && (apply_resp =~ /machinedeployment.cluster.x-k8s.io\/capd-md-0 unchanged/) != nil && (apply_resp =~ /machinehealthcheck.cluster.x-k8s.io\/capd-mhc-0 unchanged/) != nil || second_count > wait_count.to_i - LOGGING.info("second_count = #{second_count}") - sleep 1 - apply_resp = `kubectl apply -f #{manifest_file}` - LOGGING.info("apply response: #{apply_resp}") - second_count = second_count + 1 - end - end - - - - def self.pod_status(pod_name_prefix, field_selector="", namespace="default") - all_pods = `kubectl get pods #{field_selector} -o jsonpath='{.items[*].metadata.name},{.items[*].metadata.creationTimestamp}'`.split(",") - - LOGGING.info(all_pods) - all_pod_names = all_pods[0].split(" ") - time_stamps = all_pods[1].split(" ") - pods_times = all_pod_names.map_with_index do |name, i| - {:name => name, :time => time_stamps[i]} - end - LOGGING.info("pods_times: #{pods_times}") - - # puts "Name: #{all_pods[0]}" - # puts "Time Stamp: #{all_pods[1]}" - latest_pod_time = pods_times.reduce() do | acc, i | - # if current i > acc - LOGGING.info("ACC: #{acc}") - LOGGING.info("I:#{i}") - LOGGING.info("pod_name_prefix: #{pod_name_prefix}") - if (acc[:name] =~ /#{pod_name_prefix}/).nil? - acc = {:name => "not found", :time => "not_found"} - end - if i[:name] =~ /#{pod_name_prefix}/ - acc = i - if acc == "" - existing_time = Time.parse!( "#{i[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") - else - existing_time = Time.parse!( "#{acc[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") - end - new_time = Time.parse!( "#{i[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") - if new_time <= existing_time - acc = i - else - acc - end - else - acc - end - end - LOGGING.info("latest_pod_time: #{latest_pod_time}") - - pod = latest_pod_time[:name].not_nil! - # pod = all_pod_names[time_stamps.index(latest_time).not_nil!] - # pod = all_pods.select{ | x | x =~ /#{pod_name_prefix}/ } - puts "Pods Found: #{pod}" - status = `kubectl get pods #{pod} -o jsonpath='{.metadata.name},{.status.phase},{.status.containerStatuses[*].ready}'` - status - end - - def self.node_status(node_name) - all_nodes = `kubectl get nodes -o jsonpath='{.items[*].metadata.name}'` - LOGGING.info(all_nodes) - status = `kubectl get nodes #{node_name} -o jsonpath='{.status.conditions[?(@.type == "Ready")].status}'` - status - end - def self.path_has_yml?(config_path) - if config_path =~ /\.yml/ + if config_path =~ /\.yml/ true else false @@ -148,84 +155,151 @@ module CNFManager return config end - def self.sample_setup_args(sample_dir, args, deploy_with_chart=true, verbose=false, wait_count=180) - VERBOSE_LOGGING.info "sample_setup_args" if verbose - - config = config_from_path_or_dir(sample_dir) - config_dir = ensure_cnf_conformance_dir(sample_dir) - - VERBOSE_LOGGING.info "config #{config}" if verbose - - if args.named.keys.includes? "release_name" - release_name = "#{args.named["release_name"]}" + def self.ensure_cnf_conformance_yml_path(path : String) + LOGGING.info("ensure_cnf_conformance_yml_path") + if path_has_yml?(path) + yml = path else - release_name = "#{config.get("release_name").as_s?}" + yml = path + "/cnf-conformance.yml" end - VERBOSE_LOGGING.info "release_name: #{release_name}" if verbose + end - if args.named.keys.includes? "deployment_name" - deployment_name = "#{args.named["deployment_name"]}" + def self.ensure_cnf_conformance_dir(path) + LOGGING.info("ensure_cnf_conformance_yml_dir") + if path_has_yml?(path) + dir = File.dirname(path) else - deployment_name = "#{config.get("deployment_name").as_s?}" + dir = path end - VERBOSE_LOGGING.info "deployment_name: #{deployment_name}" if verbose + dir + "/" + end - if args.named.keys.includes? "helm_chart" - helm_chart = "#{args.named["helm_chart"]}" + def self.release_name?(config) + release_name = optional_key_as_string(config, "release_name").split(" ")[0] + if release_name.empty? + false else - helm_chart = "#{config.get("helm_chart").as_s?}" + true end - VERBOSE_LOGGING.info "helm_chart: #{helm_chart}" if verbose + end - if args.named.keys.includes? "helm_directory" - helm_directory = "#{args.named["helm_directory"]}" + def self.exclusive_install_method_tags?(config) + installation_type_count = ["helm_chart", "helm_directory", "manifest_directory"].reduce(0) do |acc, install_type| + begin + test_tag = config[install_type] + LOGGING.debug "install type count install_type: #{install_type}" + if install_type.empty? + acc + else + acc = acc + 1 + end + rescue ex + LOGGING.debug "install_type: #{install_type} not found in #{config.config_paths[0]}/#{config.config_name}.#{config.config_type}" + # LOGGING.debug ex.message + # ex.backtrace.each do |x| + # LOGGING.debug x + # end + acc + end + end + LOGGING.debug "installation_type_count: #{installation_type_count}" + if installation_type_count > 1 + false else - helm_directory = "#{config.get("helm_directory").as_s?}" + true end - VERBOSE_LOGGING.info "helm_directory: #{helm_directory}" if verbose + end - if args.named.keys.includes? "git_clone_url" - git_clone_url = "#{args.named["git_clone_url"]}" + #Determine, for cnf, whether a helm chart, helm directory, or manifest directory is being used for installation + def self.cnf_installation_method(config) + LOGGING.info "cnf_installation_method" + LOGGING.info "cnf_installation_method config: #{config}" + LOGGING.info "cnf_installation_method config: #{config.config_paths[0]}/#{config.config_name}.#{config.config_type}" + helm_chart = optional_key_as_string(config, "helm_chart") + helm_directory = optional_key_as_string(config, "helm_directory") + manifest_directory = optional_key_as_string(config, "manifest_directory") + + unless CNFManager.exclusive_install_method_tags?(config) + puts "Error: Must populate at lease one installation type in #{config.config_paths[0]}/#{config.config_name}.#{config.config_type}: choose either helm_chart, helm_directory, or manifest_directory in cnf-conformance.yml!".colorize(:red) + raise "Error: Must populate at lease one installation type in #{config.config_paths[0]}/#{config.config_name}.#{config.config_type}: choose either helm_chart, helm_directory, or manifest_directory in cnf-conformance.yml!" + end + if !helm_chart.empty? + {:helm_chart, helm_chart} + elsif !helm_directory.empty? + {:helm_directory, helm_directory} + elsif !manifest_directory.empty? + {:manifest_directory, manifest_directory} else - git_clone_url = "#{config.get("git_clone_url").as_s?}" + puts "Error: Must populate at lease one installation type in #{config.config_paths[0]}/#{config.config_name}.#{config.config_type}: choose either helm_chart, helm_directory, or manifest_directory.".colorize(:red) + raise "Error in cnf-conformance.yml!" end - VERBOSE_LOGGING.info "git_clone_url: #{git_clone_url}" if verbose - - sample_setup(config_file: config_dir, release_name: release_name, deployment_name: deployment_name, helm_chart: helm_chart, helm_directory: helm_directory, git_clone_url: git_clone_url, deploy_with_chart: deploy_with_chart, verbose: verbose, wait_count: wait_count ) + end + def self.helm_template_header(helm_chart_or_directory, template_file="/tmp/temp_template.yml") + LOGGING.info "helm_template_header" + helm = CNFSingleton.helm + # generate helm chart release name + # use --dry-run to generate yml file + LOGGING.info("#{helm} install --dry-run --generate-name #{helm_chart_or_directory} > #{template_file}") + helm_install = `#{helm} install --dry-run --generate-name #{helm_chart_or_directory} > #{template_file}` + raw_template = File.read(template_file) + split_template = raw_template.split("---") + template_header = split_template[0] + parsed_template_header = YAML.parse(template_header) end - def self.ensure_cnf_conformance_yml_path(path) - LOGGING.info("ensure_cnf_conformance_yml_path") - if path_has_yml?(path) - yml = path - else - yml = path + "/cnf-conformance.yml" - end + def self.helm_chart_template_release_name(helm_chart_or_directory, template_file="/tmp/temp_template.yml") + LOGGING.info "helm_chart_template_release_name" + hth = helm_template_header(helm_chart_or_directory, template_file) + LOGGING.debug "helm template: #{hth}" + hth["NAME"] end - def self.ensure_cnf_conformance_dir(path) - LOGGING.info("ensure_cnf_conformance_yml_dir") - if path_has_yml?(path) - dir = File.dirname(path) - else - dir = path + def self.generate_and_set_release_name(config_yml_path) + LOGGING.info "generate_and_set_release_name" + yml_file = CNFManager.ensure_cnf_conformance_yml_path(config_yml_path) + yml_path = CNFManager.ensure_cnf_conformance_dir(config_yml_path) + config = CNFManager.parsed_config_file(yml_file) + + predefined_release_name = optional_key_as_string(config, "release_name") + LOGGING.debug "predefined_release_name: #{predefined_release_name}" + if predefined_release_name.empty? + install_method = self.cnf_installation_method(config) + LOGGING.debug "install_method: #{install_method}" + case install_method[0] + when :helm_chart + LOGGING.debug "helm_chart install method: #{install_method[1]}" + release_name = helm_chart_template_release_name(install_method[1]) + when :helm_directory + LOGGING.debug "helm_directory install method: #{yml_path}/#{install_method[1]}" + release_name = helm_chart_template_release_name("#{yml_path}/#{install_method[1]}") + when :manifest_directory + LOGGING.debug "manifest_directory install method" + release_name = UUID.random.to_s + else + raise "Install method should be either helm_chart, helm_directory, or manifest_directory" + end + #set generated helm chart release name in yml file + LOGGING.debug "generate_and_set_release_name: #{release_name}" + update_yml(yml_file, "release_name", release_name) end - dir + "/" end + def self.cnf_destination_dir(config_file) - LOGGING.info("cnf_destination_dir") + LOGGING.info("cnf_destination_dir config_file: #{config_file}") if path_has_yml?(config_file) yml = config_file else - yml = config_file + "/cnf-conformance.yml" + yml = config_file + "/cnf-conformance.yml" end config = parsed_config_file(yml) - current_dir = FileUtils.pwd - deployment_name = "#{config.get("deployment_name").as_s?}" - LOGGING.info("deployment_name: #{deployment_name}") - "#{current_dir}/#{CNF_DIR}/#{deployment_name}" + LOGGING.debug "cnf_destination_dir parsed_config_file config: #{config}" + current_dir = FileUtils.pwd + release_name = optional_key_as_string(config, "release_name").split(" ")[0] + LOGGING.info "release_name: #{release_name}" + LOGGING.info "cnf destination dir: #{current_dir}/#{CNF_DIR}/#{release_name}" + "#{current_dir}/#{CNF_DIR}/#{release_name}" end def self.config_source_dir(config_file) @@ -241,192 +315,282 @@ module CNFManager ret = false if helm_repo_name == nil || helm_repo_url == nil # config = get_parsed_cnf_conformance_yml(args) - config = parsed_config_file(ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + # config = parsed_config_file(ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) LOGGING.info "helm path: #{CNFSingleton.helm}" - # current_dir = FileUtils.pwd - # #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" helm = CNFSingleton.helm - helm_repo_name = config.get("helm_repository.name").as_s? + # helm_repo_name = config.get("helm_repository.name").as_s? + helm_repository = config.cnf_config[:helm_repository] + helm_repo_name = "#{helm_repository && helm_repository["name"]}" + helm_repo_url = "#{helm_repository && helm_repository["repo_url"]}" LOGGING.info "helm_repo_name: #{helm_repo_name}" - helm_repo_url = config.get("helm_repository.repo_url").as_s? + # helm_repo_url = config.get("helm_repository.repo_url").as_s? LOGGING.info "helm_repo_url: #{helm_repo_url}" end if helm_repo_name && helm_repo_url - LOGGING.info "helm repo add command: #{helm} repo add #{helm_repo_name} #{helm_repo_url}" - # helm_resp = `#{helm} repo add #{helm_repo_name} #{helm_repo_url}` - stdout = IO::Memory.new - stderror = IO::Memory.new - begin - process = Process.new("#{helm}", ["repo", "add", "#{helm_repo_name}", "#{helm_repo_url}"], output: stdout, error: stderror) - status = process.wait - helm_resp = stdout.to_s - error = stderror.to_s - LOGGING.info "error: #{error}" - LOGGING.info "helm_resp (add): #{helm_resp}" - rescue - LOGGING.error "helm repo add command critically failed: #{helm} repo add #{helm_repo_name} #{helm_repo_url}" - end - # Helm version v3.3.3 gave us a surprise - if helm_resp =~ /has been added|already exists/ || error =~ /has been added|already exists/ - # if $?.success? - ret = true - else - ret = false - end + ret = Helm.helm_repo_add(helm_repo_name, helm_repo_url) else ret = false end ret end - def self.helm_gives_k8s_warning?(verbose=false) - helm = CNFSingleton.helm - stdout = IO::Memory.new - stderror = IO::Memory.new - begin - process = Process.new("#{helm}", ["list"], output: stdout, error: stderror) - status = process.wait - helm_resp = stdout.to_s - error = stderror.to_s - LOGGING.info "error: #{error}" - LOGGING.info "helm_resp (add): #{helm_resp}" - # Helm version v3.3.3 gave us a surprise - if (helm_resp + error) =~ /WARNING: Kubernetes configuration file is/ - stdout_failure("For this version of helm you must set your K8s config file permissions to chmod 700") if verbose - true - else - false - end - rescue ex - stdout_failure("Please use newer version of helm") - true + def self.sample_setup_cli_args(args, noisy=true) + VERBOSE_LOGGING.info "sample_setup_cli_args" if check_verbose(args) + VERBOSE_LOGGING.debug "args = #{args.inspect}" if check_verbose(args) + if args.named.keys.includes? "cnf-config" + yml_file = args.named["cnf-config"].as(String) + cnf_path = File.dirname(yml_file) + elsif args.named.keys.includes? "cnf-path" + cnf_path = args.named["cnf-path"].as(String) + elsif noisy + stdout_failure "Error: You must supply either cnf-config or cnf-path" + exit 1 + else + cnf_path = "" + end + if args.named.keys.includes? "wait_count" + wait_count = args.named["wait_count"].to_i + elsif args.named.keys.includes? "wait-count" + wait_count = args.named["wait-count"].to_i + else + wait_count = 180 end + {config_file: cnf_path, wait_count: wait_count, verbose: check_verbose(args)} + end + + # Create a unique directory for the cnf that is to be installed under ./cnfs + # Only copy the cnf's cnf-conformance.yml and it's helm_directory or manifest directory (if it exists) + # Use manifest directory if helm directory empty + def self.sandbox_setup(config, cli_args) + LOGGING.info "sandbox_setup" + LOGGING.info "sandbox_setup config: #{config.cnf_config}" + verbose = cli_args[:verbose] + config_file = config.cnf_config[:source_cnf_dir] + release_name = config.cnf_config[:release_name] + install_method = config.cnf_config[:install_method] + helm_directory = config.cnf_config[:helm_directory] + manifest_directory = config.cnf_config[:manifest_directory] + helm_chart_path = config.cnf_config[:helm_chart_path] + destination_cnf_dir = CNFManager.cnf_destination_dir(config_file) + + if install_method[0] == :manifest_directory + manifest_or_helm_directory = config_source_dir(config_file) + "/" + manifest_directory + elsif !helm_directory.empty? + manifest_or_helm_directory = config_source_dir(config_file) + "/" + helm_directory + else + # this is not going to exist + manifest_or_helm_directory = helm_chart_path #./cnfs//exported_chart + end + + LOGGING.info("File.directory?(#{manifest_or_helm_directory}) #{File.directory?(manifest_or_helm_directory)}") + # if the helm directory already exists, copy helm_directory contents into cnfs// + + destination_chart_directory = {creation_type: :created, chart_directory: ""} + if !manifest_or_helm_directory.empty? && manifest_or_helm_directory =~ /exported_chart/ + LOGGING.info "Ensuring exported helm directory is created" + LOGGING.debug "mkdir_p destination_cnf_dir/exported_chart: #{manifest_or_helm_directory}" + destination_chart_directory = {creation_type: :created, + chart_directory: "#{manifest_or_helm_directory}"} + FileUtils.mkdir_p(destination_chart_directory[:chart_directory]) + elsif !manifest_or_helm_directory.empty? && File.directory?(manifest_or_helm_directory) + # if !manifest_or_helm_directory.empty? && File.directory?(manifest_or_helm_directory) + LOGGING.info "Ensuring helm directory is copied" + LOGGING.info("cp -a #{manifest_or_helm_directory} #{destination_cnf_dir}") + destination_chart_directory = {creation_type: :copied, + chart_directory: "#{manifest_or_helm_directory}"} + yml_cp = `cp -a #{destination_chart_directory[:chart_directory]} #{destination_cnf_dir}` + VERBOSE_LOGGING.info yml_cp if verbose + raise "Copy of #{destination_chart_directory[:chart_directory]} to #{destination_cnf_dir} failed!" unless $?.success? + end + LOGGING.info "copy cnf-conformance.yml file" + LOGGING.info("cp -a #{ensure_cnf_conformance_yml_path(config_file)} #{destination_cnf_dir}") + yml_cp = `cp -a #{ensure_cnf_conformance_yml_path(config_file)} #{destination_cnf_dir}` + destination_chart_directory + end + + # Retrieve the helm chart source + def self.export_published_chart(config, cli_args) + verbose = cli_args[:verbose] + config_file = config.cnf_config[:source_cnf_dir] + helm_directory = config.cnf_config[:helm_directory] + helm_chart = config.cnf_config[:helm_chart] + destination_cnf_dir = CNFManager.cnf_destination_dir(config_file) + + current_dir = FileUtils.pwd + VERBOSE_LOGGING.info current_dir if verbose + + helm = CNFSingleton.helm + LOGGING.info "helm path: #{CNFSingleton.helm}" + + LOGGING.debug "mkdir_p destination_cnf_dir/helm_directory: #{destination_cnf_dir}/#{helm_directory}" + #TODO don't think we need to make this here + FileUtils.mkdir_p("#{destination_cnf_dir}/#{helm_directory}") + LOGGING.debug "helm command pull: #{helm} pull #{helm_chart}" + #TODO move to helm module + helm_pull = `#{helm} pull #{helm_chart}` + VERBOSE_LOGGING.info helm_pull if verbose + # TODO helm_chart should be helm_chart_repo + # TODO make this into a tar chart function + VERBOSE_LOGGING.info "mv #{Helm.chart_name(helm_chart)}-*.tgz #{destination_cnf_dir}/exported_chart" if verbose + core_mv = `mv #{Helm.chart_name(helm_chart)}-*.tgz #{destination_cnf_dir}/exported_chart` + VERBOSE_LOGGING.info core_mv if verbose + + VERBOSE_LOGGING.info "cd #{destination_cnf_dir}/exported_chart; tar -xvf #{destination_cnf_dir}/exported_chart/#{Helm.chart_name(helm_chart)}-*.tgz" if verbose + tar = `cd #{destination_cnf_dir}/exported_chart; tar -xvf #{destination_cnf_dir}/exported_chart/#{Helm.chart_name(helm_chart)}-*.tgz` + VERBOSE_LOGGING.info tar if verbose + + VERBOSE_LOGGING.info "mv #{destination_cnf_dir}/exported_chart/#{Helm.chart_name(helm_chart)}/* #{destination_cnf_dir}/exported_chart" if verbose + move_chart = `mv #{destination_cnf_dir}/exported_chart/#{Helm.chart_name(helm_chart)}/* #{destination_cnf_dir}/exported_chart` + VERBOSE_LOGGING.info move_chart if verbose + ensure + cd = `cd #{current_dir}` + VERBOSE_LOGGING.info cd if verbose end - def self.sample_setup(config_file, release_name, deployment_name, helm_chart, helm_directory, git_clone_url="", deploy_with_chart=true, verbose=false, wait_count=180) + #sample_setup({config_file: cnf_path, wait_count: wait_count}) + def self.sample_setup(cli_args) + LOGGING.info "sample_setup cli_args: #{cli_args}" + config_file = cli_args[:config_file] + wait_count = cli_args[:wait_count] + verbose = cli_args[:verbose] + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + release_name = config.cnf_config[:release_name] + install_method = config.cnf_config[:install_method] + + #TODO add helm arguments to the cnf-conformance yml VERBOSE_LOGGING.info "sample_setup" if verbose LOGGING.info("config_file #{config_file}") - current_dir = FileUtils.pwd - VERBOSE_LOGGING.info current_dir if verbose - + config = CNFManager::Config.parse_config_yml(CNFManager.ensure_cnf_conformance_yml_path(config_file)) + LOGGING.debug "config in sample_setup: #{config.cnf_config}" + + release_name = config.cnf_config[:release_name] + install_method = config.cnf_config[:install_method] + helm_directory = config.cnf_config[:helm_directory] + manifest_directory = config.cnf_config[:manifest_directory] + git_clone_url = config.cnf_config[:git_clone_url] + helm_repository = config.cnf_config[:helm_repository] + helm_repo_name = "#{helm_repository && helm_repository["name"]}" + helm_repo_url = "#{helm_repository && helm_repository["repo_url"]}" + LOGGING.info "helm_repo_name: #{helm_repo_name}" + LOGGING.info "helm_repo_url: #{helm_repo_url}" + + helm_chart = config.cnf_config[:helm_chart] + helm_chart_path = config.cnf_config[:helm_chart_path] + LOGGING.debug "helm_directory: #{helm_directory}" + + #TODO move to sandbox module destination_cnf_dir = CNFManager.cnf_destination_dir(config_file) - VERBOSE_LOGGING.info "destination_cnf_dir: #{destination_cnf_dir}" if verbose - FileUtils.mkdir_p(destination_cnf_dir) + VERBOSE_LOGGING.info "destination_cnf_dir: #{destination_cnf_dir}" if verbose + LOGGING.debug "mkdir_p destination_cnf_dir: #{destination_cnf_dir}" + FileUtils.mkdir_p(destination_cnf_dir) + # TODO enable recloning/fetching etc # TODO pass in block - git_clone = `git clone #{git_clone_url} #{destination_cnf_dir}/#{release_name}` if git_clone_url.empty? == false + # TODO move to git module + git_clone = `git clone #{git_clone_url} #{destination_cnf_dir}/#{release_name}` if git_clone_url.empty? == false VERBOSE_LOGGING.info git_clone if verbose - # Copy the cnf-conformance.yml - # Copy the sample - # TODO create helm chart directory if it doesn't exist - # Document this behaviour of the helm chart directory (using it if it exists, - # creating it if it doesn't) - LOGGING.info("File.directory?(#{config_source_dir(config_file)}/#{helm_directory}) #{File.directory?(config_source_dir(config_file) + "/" + helm_directory)}") - if File.directory?(config_source_dir(config_file) + "/" + helm_directory) - LOGGING.info("cp -a #{config_source_dir(config_file) + "/" + helm_directory} #{destination_cnf_dir}") - yml_cp = `cp -a #{config_source_dir(config_file) + "/" + helm_directory} #{destination_cnf_dir}` - VERBOSE_LOGGING.info yml_cp if verbose - raise "Copy of #{config_source_dir(config_file) + "/" + helm_directory} to #{destination_cnf_dir} failed!" unless $?.success? - else - FileUtils.mkdir_p("#{destination_cnf_dir}/#{helm_directory}") - end - #TODO get yml for the config_file if it doesn't exist - LOGGING.info("cp -a #{ensure_cnf_conformance_yml_path(config_file)} #{destination_cnf_dir}") - yml_cp = `cp -a #{ensure_cnf_conformance_yml_path(config_file)} #{destination_cnf_dir}` + sandbox_setup(config, cli_args) + helm = CNFSingleton.helm + LOGGING.info "helm path: #{CNFSingleton.helm}" - begin - - # #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - helm = CNFSingleton.helm - LOGGING.info "helm path: #{CNFSingleton.helm}" - if deploy_with_chart - VERBOSE_LOGGING.info "deploying with chart repository" if verbose - helm_install = `#{helm} install #{release_name} #{helm_chart}` - VERBOSE_LOGGING.info helm_install if verbose - - # Retrieve the helm chart source - FileUtils.mkdir_p("#{destination_cnf_dir}/#{helm_directory}") - helm_pull = `#{helm} pull #{helm_chart}` - VERBOSE_LOGGING.info helm_pull if verbose - # core_mv = `mv #{release_name}-*.tgz #{destination_cnf_dir}/#{helm_directory}` - # TODO helm_chart should be helm_chart_repo - VERBOSE_LOGGING.info "mv #{chart_name(helm_chart)}-*.tgz #{destination_cnf_dir}/#{helm_directory}" if verbose - core_mv = `mv #{chart_name(helm_chart)}-*.tgz #{destination_cnf_dir}/#{helm_directory}` - VERBOSE_LOGGING.info core_mv if verbose - - VERBOSE_LOGGING.info "cd #{destination_cnf_dir}/#{helm_directory}; tar -xvf #{destination_cnf_dir}/#{helm_directory}/#{chart_name(helm_chart)}-*.tgz" if verbose - tar = `cd #{destination_cnf_dir}/#{helm_directory}; tar -xvf #{destination_cnf_dir}/#{helm_directory}/#{chart_name(helm_chart)}-*.tgz` - VERBOSE_LOGGING.info tar if verbose - - VERBOSE_LOGGING.info "mv #{destination_cnf_dir}/#{helm_directory}/#{chart_name(helm_chart)}/* #{destination_cnf_dir}/#{helm_directory}" if verbose - move_chart = `mv #{destination_cnf_dir}/#{helm_directory}/#{chart_name(helm_chart)}/* #{destination_cnf_dir}/#{helm_directory}` - VERBOSE_LOGGING.info move_chart if verbose - else - VERBOSE_LOGGING.info "deploying with helm directory" if verbose - LOGGING.info("#{helm} install #{release_name} #{destination_cnf_dir}/#{helm_directory}") - helm_install = `#{helm} install #{release_name} #{destination_cnf_dir}/#{helm_directory}` - VERBOSE_LOGGING.info helm_install if verbose + case install_method[0] + when :manifest_directory + VERBOSE_LOGGING.info "deploying by manifest file" if verbose + #kubectl apply -f ./sample-cnfs/k8s-non-helm/manifests + # TODO move to kubectlclient + # LOGGING.info("kubectl apply -f #{destination_cnf_dir}/#{manifest_directory}") + # manifest_install = `kubectl apply -f #{destination_cnf_dir}/#{manifest_directory}` + # VERBOSE_LOGGING.info manifest_install if verbose + KubectlClient::Apply.file("#{destination_cnf_dir}/#{manifest_directory}") + + when :helm_chart + if !helm_repo_name.empty? || !helm_repo_url.empty? + Helm.helm_repo_add(helm_repo_name, helm_repo_url) end + VERBOSE_LOGGING.info "deploying with chart repository" if verbose + LOGGING.info "helm command: #{helm} install #{release_name} #{helm_chart}" + #TODO move to Helm module + helm_install = `#{helm} install #{release_name} #{helm_chart}` + VERBOSE_LOGGING.info helm_install if verbose + export_published_chart(config, cli_args) + when :helm_directory + VERBOSE_LOGGING.info "deploying with helm directory" if verbose + #TODO Add helm options into cnf-conformance yml + #e.g. helm install nsm --set insecure=true ./nsm/helm_chart + LOGGING.info("#{helm} install #{release_name} #{destination_cnf_dir}/#{helm_directory}") + #TODO move to helm module + helm_install = `#{helm} install #{release_name} #{destination_cnf_dir}/#{helm_directory}` + VERBOSE_LOGGING.info helm_install if verbose + else + raise "Deployment method not found" + end - wait_for_install(deployment_name, wait_count) - if helm_install.to_s.size > 0 # && helm_pull.to_s.size > 0 - LOGGING.info "Successfully setup #{release_name}".colorize(:green) + resource_ymls = cnf_workload_resources(nil, config) do |resource| + resource + end + resource_names = Helm.workload_resource_kind_names(resource_ymls) + #TODO move to kubectlclient and make resource_install_and_wait_for_all function + resource_names.each do | resource | + case resource[:kind].as_s.downcase + when "replicaset", "deployment", "statefulset", "pod", "daemonset" + # wait_for_install(resource_name, wait_count) + KubectlClient::Get.resource_wait_for_install(resource[:kind].as_s, resource[:name].as_s, wait_count) end - ensure - cd = `cd #{current_dir}` - VERBOSE_LOGGING.info cd if verbose + end + if helm_install.to_s.size > 0 # && helm_pull.to_s.size > 0 + stdout_success "Successfully setup #{release_name}" end end - # def self.tools_helm - # current_dir = FileUtils.pwd - # #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - # helm = CNFSingleton.helm - # end - - def self.local_helm_path - current_dir = FileUtils.pwd - helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" - end - - def self.sample_cleanup(config_file, force=false, verbose=true) + def self.sample_cleanup(config_file, force=false, installed_from_manifest=false, verbose=true) + LOGGING.info "sample_cleanup" destination_cnf_dir = CNFManager.cnf_destination_dir(config_file) config = parsed_config_file(ensure_cnf_conformance_yml_path(config_file)) VERBOSE_LOGGING.info "cleanup config: #{config.inspect}" if verbose - release_name = config.get("release_name").as_s + release_name = "#{config.get("release_name").as_s?}" + manifest_directory = destination_cnf_dir + "/" + "#{config["manifest_directory"]? && config["manifest_directory"].as_s?}" LOGGING.info "helm path: #{CNFSingleton.helm}" - # #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" helm = CNFSingleton.helm - # VERBOSE_LOGGING.debug helm if verbose - # destination_cnf_dir = "#{current_dir}/#{CNF_DIR}/#{short_sample_dir(config_path)}" dir_exists = File.directory?(destination_cnf_dir) ret = true LOGGING.info("destination_cnf_dir: #{destination_cnf_dir}") if dir_exists || force == true - rm = `rm -rf #{destination_cnf_dir}` - VERBOSE_LOGGING.info rm if verbose - LOGGING.info "helm uninstall command: #{helm} uninstall #{release_name}" - helm_uninstall = `#{helm} uninstall #{release_name}` - ret = $?.success? - VERBOSE_LOGGING.info helm_uninstall if verbose - if ret - stdout_success "Successfully cleaned up #{release_name}" + if installed_from_manifest + # LOGGING.info "kubectl delete command: kubectl delete -f #{manifest_directory}" + # kubectl_delete = `kubectl delete -f #{manifest_directory}` + # ret = $?.success? + ret = KubectlClient::Delete.file("#{manifest_directory}") + # VERBOSE_LOGGING.info kubectl_delete if verbose + # TODO put more safety around this + rm = `rm -rf #{destination_cnf_dir}` + VERBOSE_LOGGING.info rm if verbose + if ret + stdout_success "Successfully cleaned up #{manifest_directory} directory" + end + else + LOGGING.info "helm uninstall command: #{helm} uninstall #{release_name.split(" ")[0]}" + #TODO add capability to add helm options for uninstall + helm_uninstall = `#{helm} uninstall #{release_name.split(" ")[0]}` + ret = $?.success? + VERBOSE_LOGGING.info helm_uninstall if verbose + rm = `rm -rf #{destination_cnf_dir}` + VERBOSE_LOGGING.info rm if verbose + if ret + stdout_success "Successfully cleaned up #{release_name.split(" ")[0]}" + end end end ret end - def self.chart_name(helm_chart_repo) - helm_chart_repo.split("/").last - end - - # TODO: figure out how to check this recursively + # TODO: figure out how to check this recursively # # def self.recursive_json_unmapped(hashy_thing): JSON::Any # unmapped_stuff = hashy_thing.json_unmapped @@ -444,7 +608,7 @@ module CNFManager # https://github.com/Nicolab/crystal-validator#check def self.validate_cnf_conformance_yml(config) ccyt_validator = nil - valid = true + valid = true begin ccyt_validator = CnfConformanceYmlType.from_json(config.settings.to_json) @@ -471,7 +635,7 @@ module CNFManager end #TODO Differentiate between unmapped subkeys or unset top level key. - if ccyt_validator && !ccyt_validator.try &.helm_repository.try &.json_unmapped.empty? + if ccyt_validator && !ccyt_validator.try &.helm_repository.try &.json_unmapped.empty? root = {} of String => (Hash(String, JSON::Any) | Nil) root["helm_repository"] = ccyt_validator.try &.helm_repository.try &.json_unmapped @@ -484,4 +648,5 @@ module CNFManager { valid, warning_output } end + end diff --git a/src/tasks/utils/config.cr b/src/tasks/utils/config.cr new file mode 100644 index 000000000..abac6c004 --- /dev/null +++ b/src/tasks/utils/config.cr @@ -0,0 +1,128 @@ +require "totem" +require "colorize" +require "./types/cnf_conformance_yml_type.cr" +require "./helm.cr" +require "uuid" +require "./points.cr" +require "./task.cr" + +module CNFManager + + class Config + def initialize(cnf_config) + @cnf_config = cnf_config + end + property cnf_config : NamedTuple(destination_cnf_dir: String, + source_cnf_file: String, + source_cnf_dir: String, + yml_file_path: String, + install_method: Tuple(Symbol, String), + manifest_directory: String, + helm_directory: String, + helm_chart_path: String, + manifest_file_path: String, + git_clone_url: String, + install_script: String, + release_name: String, + service_name: String, + docker_repository: String, + helm_repository: NamedTuple(name: String, + repo_url: String) | Nil, + helm_chart: String, + helm_chart_container_name: String, + rolling_update_tag: String, + container_names: Array(Hash(String, String )) | Nil, + white_list_container_names: Array(String)) + + def self.parse_config_yml(config_yml_path : String) : CNFManager::Config + LOGGING.debug "parse_config_yml config_yml_path: #{config_yml_path}" + yml_file = CNFManager.ensure_cnf_conformance_yml_path(config_yml_path) + #TODO modify the destination conformance yml instead of the source conformance yml + # (especially in the case of the release manager). Then reread the destination config + # TODO for cleanup, read source, then find destination and use release name from destination config + # TODO alternatively use a CRD to save the release name + config = CNFManager.parsed_config_file(yml_file) + + install_method = CNFManager.cnf_installation_method(config) + + CNFManager.generate_and_set_release_name(config_yml_path) + + destination_cnf_dir = CNFManager.cnf_destination_dir(yml_file) + + yml_file_path = CNFManager.ensure_cnf_conformance_dir(config_yml_path) + source_cnf_file = yml_file + source_cnf_dir = yml_file_path + manifest_directory = optional_key_as_string(config, "manifest_directory") + if config["helm_repository"]? + helm_repository = config["helm_repository"].as_h + helm_repo_name = optional_key_as_string(helm_repository, "name") + helm_repo_url = optional_key_as_string(helm_repository, "repo_url") + else + helm_repo_name = "" + helm_repo_url = "" + end + helm_chart = optional_key_as_string(config, "helm_chart") + release_name = optional_key_as_string(config, "release_name") + service_name = optional_key_as_string(config, "service_name") + helm_directory = optional_key_as_string(config, "helm_directory") + git_clone_url = optional_key_as_string(config, "git_clone_url") + install_script = optional_key_as_string(config, "install_script") + docker_repository = optional_key_as_string(config, "docker_repository") + if helm_directory.empty? + working_chart_directory = "exported_chart" + else + working_chart_directory = helm_directory + end + helm_chart_path = destination_cnf_dir + "/" + working_chart_directory + manifest_file_path = destination_cnf_dir + "/" + "temp_template.yml" + white_list_container_names = optional_key_as_string(config, "allowlist_helm_chart_container_names") + if config["allowlist_helm_chart_container_names"]? + white_list_container_names = config["allowlist_helm_chart_container_names"].as_a.map do |c| + "#{c.as_s?}" + end + else + white_list_container_names = [] of String + end + if config["container_names"]? + container_names_totem = config["container_names"] + container_names = container_names_totem.as_a.map do |container| + {"name" => optional_key_as_string(container, "name"), + "rolling_update_test_tag" => optional_key_as_string(container, "rolling_update_test_tag"), + "rolling_downgrade_test_tag" => optional_key_as_string(container, "rolling_downgrade_test_tag"), + "rolling_version_change_test_tag" => optional_key_as_string(container, "rolling_version_change_test_tag"), + "rollback_from_tag" => optional_key_as_string(container, "rollback_from_tag"), + } + end + else + container_names = [{"name" => "", + "rolling_update_test_tag" => "", + "rolling_downgrade_test_tag" => "", + "rolling_version_change_test_tag" => "", + "rollback_from_tag" => "", + }] + end + + new({ destination_cnf_dir: destination_cnf_dir, + source_cnf_file: source_cnf_file, + source_cnf_dir: source_cnf_dir, + yml_file_path: yml_file_path, + install_method: install_method, + manifest_directory: manifest_directory, + helm_directory: helm_directory, + helm_chart_path: helm_chart_path, + manifest_file_path: manifest_file_path, + git_clone_url: git_clone_url, + install_script: install_script, + release_name: release_name, + service_name: service_name, + docker_repository: docker_repository, + helm_repository: {name: helm_repo_name, repo_url: helm_repo_url}, + helm_chart: helm_chart, + helm_chart_container_name: "", + rolling_update_tag: "", + container_names: container_names, + white_list_container_names: white_list_container_names }) + + end + end +end diff --git a/src/tasks/utils/docker_client.cr b/src/tasks/utils/docker_client.cr new file mode 100644 index 000000000..4fd67a150 --- /dev/null +++ b/src/tasks/utils/docker_client.cr @@ -0,0 +1,138 @@ +require "totem" +require "colorize" +require "./cnf_manager.cr" +require "halite" + +module DockerClient + ############################################## + # All docker images can have one, two, three, or more segments. The docker images that have + # multiple segments are separated by a slash. + # + # ** Multiple segments ** + # (Fully qualified) registry name with optional port /Org/image combination + # Multiple segment examples: e.g. docker.io/coredns/coredns + # mydockerregistry.io:8080/coredns/coredns, mydockerregistry.io:8080/coredns/coredns:latest, + # mydockerregistry.io:8080/privatecordnsorg/coredns/coredns:latest + # + # Two segment examples: coredns/coredns, + # docker.io/busybox, + # myhostname:5000/myimagename:mytag + # + # 1) If the first segment has a period . in it, then the segment is a + # fully qualified domain name. + # + # 2) If the first segment has colon in it : everything after the colon + # is a port number + # a) If there are three or more segments, all segments (the middle + # segments) from the first and before the last are org names + # + # 3) If the first segment is not a fully qualified domain name + # a) if there are two elements, the first element is an org + # b) If there are three or more segments, all segments excluding + # the last are org names + # + # ** The last segment (or one segment) ** + # Official docker image string + # e.g. busybox + # + # 4.a) If the docker image is only one segment,docker.io is used for the + # registry, the whole segment is used image name, and if there is no + # tag, `latest` is used as the tag + # + # 4.b) Everything in the one segment (or the last segment if there are + # multiple segments) is an image or image:tag combination. + # ``` + # DockerClient.parse_image("mydockerregistry.io:8080/coredns/coredns:latest") + # # => {"org_image" => "coredns/corends:latest", "org" => "coredns", + # # "image" => "coredns:latest", "registry" => "mydockerregistry.io:8080", "tag" => "latest"} + # ``` + def self.parse_image(fqdn_image_text) + resp = {"registry" => "", + "org_image" => "", + "org" => "", + "image_and_tag" => "", + "image_name" => "", + "tag" => ""} + size = fqdn_image_text.split("/").size + first_segment = fqdn_image_text.split("/")[0] + last_segment = fqdn_image_text.split("/")[-1] + + # 1) If the first segment has a period . in it, then the segment is a + # fully qualified domain name. + # 2) If the first segment has colon in it : everything after the colon + # is a port number + if (first_segment =~ /\./ || first_segment =~ /:/) + resp["registry"] = first_segment + # a) If there are three or more segments, all segments (the middle + # segments) from the first and before the last are org names + if size > 2 + resp["org"] = fqdn_image_text.split("/")[1..-2] + elsif size = 2 + resp["org"] = first_segment + else + LOGGING.error "size of image text should never = 1 or nil: #{fqdn_image_text}" + end + else # first segment not a registry + resp["registry"] = "" + if size = 1 + resp["org"] = "" + # 3) If the first segment is not a fully qualified domain name + # a) if there are two segments, the first segment is an org + elsif size = 2 + resp["org"] = first_segment + # b) If there are three or more segments, all segments (the middle + # segments) after the first and before the last are org names + elsif size > 2 + resp["org"] = fqdn_image_text.split("/")[0..-2] + end + end + resp["org_image"] = "#{resp["org"].empty? ? "" : resp["org"] + "/"}#{last_segment}" + # 4.a) If there is only one segment, docker.io is used for the + # registry. If there is no : in the image text, `latest` is used as the tag + # 4.b) Everything in the one segment (or the last segment if there are + # multiple segments) is an image or image:tag combination. + resp["image_and_tag"] = last_segment + if size == 1 + resp["registry"] = "docker.io" + end + resp["image_name"] = last_segment.image.split(":")[0]? + if last_segment.image.split(":")[1]? + resp["tag"] = last_segment.image.split(":")[1]? + else + resp["tag"] = "latest" + end + LOGGING.info "org/image:tag : #{resp}" + resp + end + + module Get + # TODO remove if not used + def self.image_tags(image_name) : Halite::Response + LOGGING.info "tags image name: #{image_name}" + # if image doesn't have a / in it, it has no user and is an official docker reposistory + # these are prefixed with library/ + # if there are three elements in the array, use the last two elements as the org/image:tag combo + # if there are two elements in the array, use both elements as the image/tag combo + if image_name.split("/").size > 2 + image_name = "#{image_name.split("/")[1]}/#{image_name.split("/")[2]}" + end + LOGGING.info "org/image:tag : #{image_name}" + modified_image_with_repo = ((image_name =~ /\//) == nil) ? "library/" + image_name : image_name + + #TODO make this work with a local registry, if used in the future + LOGGING.info "docker halite url: #{"https://hub.docker.com/v2/repositories/#{modified_image_with_repo}/tags/?page_size=100"}" + docker_resp = Halite.get("https://hub.docker.com/v2/repositories/#{modified_image_with_repo}/tags/?page_size=100", headers: {"Authorization" => "JWT"}) + LOGGING.debug "docker image resp: #{docker_resp}" + docker_resp + end + + def self.image_by_tag(docker_image_list, tag) + # if image_tag = nil then get latest tag + modified_tag = tag == nil ? "latest" : tag + latest_image = docker_image_list.parse("json")["results"].as_a.find{|x|x["name"]=="#{modified_tag}"} + LOGGING.debug "docker parse resp: #{latest_image}" + (LOGGING.error "no image found for tag: #{modified_tag}") if latest_image == nil + latest_image + end + end +end diff --git a/src/tasks/utils/embedded_file_manager.cr b/src/tasks/utils/embedded_file_manager.cr index 13203dc75..b0c4d2226 100644 --- a/src/tasks/utils/embedded_file_manager.cr +++ b/src/tasks/utils/embedded_file_manager.cr @@ -1,6 +1,5 @@ require "totem" require "colorize" -require "./cnf_manager.cr" require "logger" require "halite" @@ -10,10 +9,19 @@ module EmbeddedFileManager CRI_TOOLS = Base64.decode_string("{{ `cat ./tools/cri-tools/manifest.yml | base64` }}") end macro node_failure_values - # NODE_FAILURE_VALUES = File.read("./embedded_files/node_failure_values.yml") - NODE_FAILURE_VALUES = Base64.decode_string("{{ `cat ./embedded_files/node_failure_values.yml | base64`}}") + # NODE_FAILED_VALUES = File.read("./embedded_files/node_failure_values.yml") + NODE_FAILED_VALUES = Base64.decode_string("{{ `cat ./embedded_files/node_failure_values.yml | base64`}}") end macro reboot_daemon REBOOT_DAEMON = Base64.decode_string("{{ `cat ./tools/reboot_daemon/manifest.yml | base64` }}") end + macro chaos_network_loss + CHAOS_NETWORK_LOSS = Base64.decode_string("{{ `cat ./embedded_files/chaos_network_loss.yml | base64`}}") + end + macro chaos_cpu_hog + CHAOS_CPU_HOG = Base64.decode_string("{{ `cat ./embedded_files/chaos_cpu_hog.yml | base64`}}") + end + macro chaos_container_kill + CHAOS_CONTAINER_KILL = Base64.decode_string("{{ `cat ./embedded_files/chaos_container_kill.yml | base64`}}") + end end diff --git a/src/tasks/utils/helm.cr b/src/tasks/utils/helm.cr new file mode 100644 index 000000000..c25ce7761 --- /dev/null +++ b/src/tasks/utils/helm.cr @@ -0,0 +1,156 @@ +require "totem" +require "colorize" +require "halite" + +module Helm + + #TODO move to kubectlclient + DEPLOYMENT="Deployment" + SERVICE="Service" + POD="Pod" + + # Utilities for manifest files that are not templates or have been converted already + module Manifest + def self.parse_manifest_as_ymls(template_file_name) + templates = File.read(template_file_name) + split_template = templates.split("---") + ymls = split_template.map { | template | + #TODO strip out NOTES + YAML.parse(template) + # compact seems to have problems with yaml::any + }.reject{|x|x==nil} + LOGGING.debug "read_template ymls: #{ymls}" + ymls + end + + def self.manifest_ymls_from_file_list(manifest_file_list) + ymls = manifest_file_list.map do |x| + parse_manifest_as_ymls(x) + end + ymls.flatten + end + + def self.manifest_file_list(manifest_directory, silent=false) + LOGGING.info("manifest_file_list") + LOGGING.info "manifest_directory: #{manifest_directory}" + if manifest_directory && !manifest_directory.empty? && manifest_directory != "/" + LOGGING.info("find: find #{manifest_directory}/ -name *.yml -o -name *.yaml") + manifests = `find #{manifest_directory}/ -name "*.yml" -o -name "*.yaml"`.split("\n").select{|x| x.empty? == false} + LOGGING.info("find response: #{manifests}") + if manifests.size == 0 && !silent + raise "No manifest ymls found in the #{manifest_directory} directory!" + end + manifests + else + [] of String + end + end + end + + + # Use helm to apply the helm values file to the helm chart templates to create a complete manifest + # Helm uses manifest files that can be jinja templates + def self.generate_manifest_from_templates(release_name, helm_chart, output_file="cnfs/temp_template.yml") + LOGGING.debug "generate_manifest_from_templates" + helm = CNFSingleton.helm + LOGGING.info "Helm::generate_manifest_from_templates command: #{helm} template #{release_name} #{helm_chart} > #{output_file}" + template_resp = `#{helm} template #{release_name} #{helm_chart} > #{output_file}` + LOGGING.info "template_resp: #{template_resp}" + [$?.success?, output_file] + end + + def self.workload_resource_by_kind(ymls : Array(YAML::Any), kind) + LOGGING.info "workload_resource_by_kind kind: #{kind}" + LOGGING.debug "workload_resource_by_kind ymls: #{ymls}" + resources = ymls.select{|x| x["kind"]?==kind}.reject! {|x| + # reject resources that contain the 'helm.sh/hook: test' annotation + LOGGING.debug "x[metadata]?: #{x["metadata"]?}" + LOGGING.debug "x[metadata][annotations]?: #{x["metadata"]? && x["metadata"]["annotations"]?}" + x.dig?("metadata","annotations","helm.sh/hook") + } + # end + LOGGING.debug "resources: #{resources}" + resources + end + + def self.all_workload_resources(yml : Array(YAML::Any)) + resources = KubectlClient::WORKLOAD_RESOURCES.map { |k,v| + Helm.workload_resource_by_kind(yml, v) + }.flatten + LOGGING.debug "all resource: #{resources}" + resources + end + + def self.workload_resource_names(resources : Array(YAML::Any) ) + resource_names = resources.map do |x| + x["metadata"]["name"] + end + LOGGING.debug "resource names: #{resource_names}" + resource_names + end + + def self.workload_resource_kind_names(resources : Array(YAML::Any) ) + resource_names = resources.map do |x| + {kind: x["kind"], name: x["metadata"]["name"]} + end + LOGGING.debug "resource names: #{resource_names}" + resource_names + end + + def self.helm_repo_add(helm_repo_name, helm_repo_url) + helm = CNFSingleton.helm + LOGGING.info "helm_repo_add: helm repo add command: #{helm} repo add #{helm_repo_name} #{helm_repo_url}" + stdout = IO::Memory.new + stderror = IO::Memory.new + begin + process = Process.new("#{helm}", ["repo", "add", "#{helm_repo_name}", "#{helm_repo_url}"], output: stdout, error: stderror) + status = process.wait + helm_resp = stdout.to_s + error = stderror.to_s + LOGGING.info "error: #{error}" + LOGGING.info "helm_resp (add): #{helm_resp}" + rescue + LOGGING.info "helm repo add command critically failed: #{helm} repo add #{helm_repo_name} #{helm_repo_url}" + end + # Helm version v3.3.3 gave us a surprise + if helm_resp =~ /has been added|already exists/ || error =~ /has been added|already exists/ + ret = true + else + ret = false + end + ret + end + + def self.helm_gives_k8s_warning?(verbose=false) + helm = CNFSingleton.helm + stdout = IO::Memory.new + stderror = IO::Memory.new + begin + process = Process.new("#{helm}", ["list"], output: stdout, error: stderror) + status = process.wait + helm_resp = stdout.to_s + error = stderror.to_s + LOGGING.info "error: #{error}" + LOGGING.info "helm_resp (add): #{helm_resp}" + # Helm version v3.3.3 gave us a surprise + if (helm_resp + error) =~ /WARNING: Kubernetes configuration file is/ + stdout_failure("For this version of helm you must set your K8s config file permissions to chmod 700") if verbose + true + else + false + end + rescue ex + stdout_failure("Please use newer version of helm") + true + end + end + + def self.local_helm_path + current_dir = FileUtils.pwd + helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" + end + + def self.chart_name(helm_chart_repo) + helm_chart_repo.split("/").last + end +end diff --git a/src/tasks/utils/kubectl_client.cr b/src/tasks/utils/kubectl_client.cr index 8af09862a..2a06cefef 100644 --- a/src/tasks/utils/kubectl_client.cr +++ b/src/tasks/utils/kubectl_client.cr @@ -3,16 +3,556 @@ require "colorize" require "./cnf_manager.cr" require "halite" -module KubectlClient +module KubectlClient + WORKLOAD_RESOURCES = {deployment: "Deployment", + service: "Service", + pod: "Pod", + replicaset: "ReplicaSet", + statefulset: "StatefulSet", + daemonset: "DaemonSet"} + # https://www.capitalone.com/tech/cloud/container-runtime/ OCI_RUNTIME_REGEX = /containerd|docker|runc|railcar|crun|rkt|gviso|nabla|runv|clearcontainers|kata|cri-o/i - module Get + def self.exec(command) + LOGGING.info "KubectlClient.exec command: #{command}" + status = Process.run("kubectl exec #{command}", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.info "KubectlClient.exec output: #{output.to_s}" + LOGGING.info "KubectlClient.exec stderr: #{stderr.to_s}" + {status: status, output: output, error: stderr} + end + def self.cp(command) + LOGGING.info "KubectlClient.cp command: #{command}" + status = Process.run("kubectl cp #{command}", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.info "KubectlClient.cp output: #{output.to_s}" + LOGGING.info "KubectlClient.cp stderr: #{stderr.to_s}" + {status: status, output: output, error: stderr} + end + def self.server_version() + LOGGING.debug "KubectlClient.server_version" + status = Process.run("kubectl version", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.debug "KubectlClient.server_version output: #{output.to_s}" + LOGGING.debug "KubectlClient.server_version stderr: #{stderr.to_s}" + # example + # Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.16", GitCommit:"7a98bb2b7c9112935387825f2fce1b7d40b76236", GitTreeState:"clean", BuildDate:"2021-02-17T11:52:32Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"} + resp = output.to_s.match /Server Version: version.Info{(Major:"(([0-9]{1,3})"\, )Minor:"([0-9]{1,3}[+]?)")/ + LOGGING.debug "KubectlClient.server_version match: #{resp}" + if resp + version = "#{resp && resp.not_nil![3]}.#{resp && resp.not_nil![4]}.0" + else + version = "" + end + LOGGING.info "KubectlClient.server_version: #{version}" + version + end + module Rollout + def self.status(deployment_name, timeout="30s") + #TODO use process command to print both standard out and error + rollout = `kubectl rollout status deployment/#{deployment_name} --timeout=#{timeout}` + rollout_status = $?.success? + LOGGING.debug "#{rollout}" + LOGGING.debug "rollout? #{rollout_status}" + $?.success? + end + def self.resource_status(kind, resource_name, timeout="30s") + rollout = `kubectl rollout status #{kind}/#{resource_name} --timeout=#{timeout}` + rollout_status = $?.success? + LOGGING.debug "#{rollout}" + LOGGING.debug "rollout? #{rollout_status}" + $?.success? + end + + def self.undo(deployment_name) + rollback = `kubectl rollout undo deployment/#{deployment_name}` + rollback_status = $?.success? + LOGGING.debug "#{rollback}" + LOGGING.debug "rollback? #{rollback_status}" + $?.success? + end + end + module Apply + def self.file(file_name) : Bool + # LOGGING.info "apply file: #{file_name}" + # apply = `kubectl apply -f #{file_name}` + # apply_status = $?.success? + # LOGGING.debug "kubectl apply resp: #{apply}" + # LOGGING.debug "apply? #{apply_status}" + # apply_status + LOGGING.info "apply file: #{file_name}" + status = Process.run("kubectl apply -f #{file_name}", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.info "KubectlClient.apply output: #{output.to_s}" + LOGGING.info "KubectlClient.apply stderr: #{stderr.to_s}" + # {status: status, output: output, error: stderr} + apply_status = $?.success? + end + end + module Delete + def self.file(file_name) + status = Process.run("kubectl delete -f #{file_name}", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + LOGGING.info "KubectlClient.delete output: #{output.to_s}" + LOGGING.info "KubectlClient.delete stderr: #{stderr.to_s}" + {status: status, output: output, error: stderr} + end + end + module Set + def self.image(deployment_name, container_name, image_name, version_tag=nil) + #TODO check if image exists in repo? DockerClient::Get.image and image_by_tags + if version_tag + LOGGING.debug "kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name}:#{version_tag} --record" + # use --record to have history + # resp = `kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name}:#{version_tag} --record` + status = Process.run("kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name}:#{version_tag} --record", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + else + LOGGING.debug "kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name} --record" + # resp = `kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name} --record` + status = Process.run("kubectl set image deployment/#{deployment_name} #{container_name}=#{image_name} --record", + shell: true, + output: output = IO::Memory.new, + error: stderr = IO::Memory.new) + end + LOGGING.info "KubectlClient.set image output: #{output.to_s}" + LOGGING.info "KubectlClient.set image stderr: #{stderr.to_s}" + # LOGGING.debug "kubectl set image: #{resp}" + $?.success? + end + end + module Get + def self.privileged_containers(namespace="--all-namespaces") + privileged_response = `kubectl get pods #{namespace} -o jsonpath='{.items[*].spec.containers[?(@.securityContext.privileged==true)].name}'` + # TODO parse this as json + resp = privileged_response.to_s.split(" ").uniq + LOGGING.debug "kubectl get privileged_containers: #{resp}" + resp + end + def self.nodes : JSON::Any # TODO should this be all namespaces? resp = `kubectl get nodes -o json` - LOGGING.info "kubectl get nodes: #{resp}" + LOGGING.debug "kubectl get nodes: #{resp}" + JSON.parse(resp) + end + + def self.deployment(deployment_name) : JSON::Any + resp = `kubectl get deployment #{deployment_name} -o json` + LOGGING.debug "kubectl get deployment: #{resp}" + if resp && !resp.empty? + JSON.parse(resp) + else + JSON.parse(%({})) + end + end + + def self.resource(kind, resource_name) : JSON::Any + LOGGING.debug "kubectl get kind: #{kind} resource name: #{resource_name}" + resp = `kubectl get #{kind} #{resource_name} -o json` + LOGGING.debug "kubectl get resource: #{resp}" + if resp && !resp.empty? + JSON.parse(resp) + else + JSON.parse(%({})) + end + end + + def self.save_manifest(deployment_name, output_file) + resp = `kubectl get deployment #{deployment_name} -o yaml > #{output_file}` + LOGGING.debug "kubectl save_manifest: #{resp}" + $?.success? + end + + def self.deployments : JSON::Any + resp = `kubectl get deployments -o json` + LOGGING.debug "kubectl get deployment: #{resp}" + if resp && !resp.empty? + JSON.parse(resp) + else + JSON.parse(%({})) + end + end + + def self.deployment_containers(deployment_name) : JSON::Any + resource_containers("deployment", deployment_name) + end + + def self.resource_containers(kind, resource_name) : JSON::Any + LOGGING.debug "kubectl get resource containers kind: #{kind} resource_name: #{resource_name}" + unless kind.downcase == "service" ## services have no containers + resp = resource(kind, resource_name).dig?("spec", "template", "spec", "containers") + end + LOGGING.info "kubectl get resource containers: #{resp}" + if resp && resp.as_a.size > 0 + resp + else + JSON.parse(%([])) + end + end + + def self.resource_volumes(kind, resource_name) : JSON::Any + LOGGING.debug "kubectl get resource volumes kind: #{kind} resource_name: #{resource_name}" + unless kind.downcase == "service" ## services have no volumes + resp = resource(kind, resource_name).dig?("spec", "template", "spec", "volumes") + end + LOGGING.debug "kubectl get resource volumes: #{resp}" + if resp && resp.as_a.size > 0 + resp + else + JSON.parse(%([])) + end + end + + def self.secrets : JSON::Any + resp = `kubectl get secrets -o json` + LOGGING.debug "kubectl get secrets: #{resp}" + if resp && !resp.empty? + JSON.parse(resp) + else + JSON.parse(%({})) + end + end + + def self.configmaps : JSON::Any + resp = `kubectl get configmaps -o json` + LOGGING.debug "kubectl get configmaps: #{resp}" + if resp && !resp.empty? + JSON.parse(resp) + else + JSON.parse(%({})) + end + end + + def self.wait_for_install(deployment_name, wait_count : Int32 = 180, namespace="default") + resource_wait_for_install("deployment", deployment_name, wait_count, namespace) + end + + def self.resource_wait_for_install(kind : String, resource_name : String, wait_count : Int32 = 180, namespace="default") + # Not all cnfs have #{kind}. some have only a pod. need to check if the + # passed in pod has a deployment, if so, watch the deployment. Otherwise watch the pod + LOGGING.info "resource_wait_for_install kind: #{kind} resource_name: #{resource_name} namespace: #{namespace}" + second_count = 0 + pod_ready : String | Nil + current_replicas : String | Nil + desired_replicas : String | Nil + #TODO use the kubectl client get + all_kind = `kubectl get #{kind} --namespace=#{namespace}` + LOGGING.debug "all_kind #{all_kind}}" + # Intialization + case kind.downcase + when "replicaset", "deployment", "statefulset" + #TODO use the kubectl client get + #TODO add extra params for kubectl client get + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.replicas}'` + LOGGING.debug "desired_replicas #{desired_replicas}" + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.readyReplicas}'` + LOGGING.debug "current_replicas #{current_replicas}" + when "daemonset" + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.desiredNumberScheduled}'` + LOGGING.debug "desired_replicas #{desired_replicas}" + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.numberAvailable}'` + LOGGING.debug "current_replicas #{current_replicas}" + when "pod" + pod_ready = KubectlClient::Get.pod_status(pod_name_prefix: resource_name, namespace: namespace).split(",")[2] # true/false + else + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.replicas}'` + LOGGING.debug "desired_replicas #{desired_replicas}" + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.readyReplicas}'` + LOGGING.debug "current_replicas #{current_replicas}" + end + + until (pod_ready && !pod_ready.empty? && pod_ready == "true") || + (current_replicas && desired_replicas && !current_replicas.empty? && current_replicas.to_i == desired_replicas.to_i) || + second_count > wait_count + LOGGING.info("second_count = #{second_count}") + sleep 1 + LOGGING.debug "wait command: kubectl get #{kind} --namespace=#{namespace}" + all_kind = `kubectl get #{kind} --namespace=#{namespace}` + case kind.downcase + when "replicaset", "deployment", "statefulset" + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.readyReplicas}'` + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.replicas}'` + when "daemonset" + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.numberAvailable}'` + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.desiredNumberScheduled}'` + when "pod" + #TODO remove split and return true /false + pod_ready = KubectlClient::Get.pod_status(pod_name_prefix: resource_name, namespace: namespace).split(",")[2] # true/false + else + current_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.readyReplicas}'` + desired_replicas = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.replicas}'` + end + LOGGING.debug "desired_replicas: #{desired_replicas}" + LOGGING.debug "pod_read: #{pod_ready}" + LOGGING.info(all_kind) + second_count = second_count + 1 + end + + LOGGING.info "final pod_ready: #{pod_ready}" + LOGGING.info "final current_replicas: #{current_replicas}" + if (pod_ready && !pod_ready.empty? && pod_ready == "true") || + (current_replicas && desired_replicas && !current_replicas.empty? && current_replicas.to_i == desired_replicas.to_i) + LOGGING.info "kind/resource #{kind}, #{resource_name} found." + true + else + LOGGING.info "kind/resource #{kind}, #{resource_name} not found." + false + end + end + + #TODO add parameter and functionality that checks for individual pods to be successfully terminated + def self.resource_wait_for_uninstall(kind : String, resource_name : String, wait_count : Int32 = 180, namespace="default") + # Not all cnfs have #{kind}. some have only a pod. need to check if the + # passed in pod has a deployment, if so, watch the deployment. Otherwise watch the pod + LOGGING.info "resource_wait_for_uninstall kind: #{kind} resource_name: #{resource_name} namespace: #{namespace}" + empty_hash = {} of String => JSON::Any + second_count = 0 + pod_ready : String | Nil + #TODO use the kubectl client get + all_kind = `kubectl get #{kind} --namespace=#{namespace}` + LOGGING.debug "all_kind #{all_kind}}" + + resource_uninstalled = KubectlClient::Get.resource(kind, resource_name) + # resource_uninstalled = `kubectl get #{kind} --namespace=#{namespace} #{resource_name} -o=jsonpath='{.status.replicas}'` + LOGGING.debug "resource_uninstalled #{resource_uninstalled}" + + until (resource_uninstalled && resource_uninstalled.as_h == empty_hash) || second_count > wait_count + LOGGING.info("second_count = #{second_count}") + sleep 1 + LOGGING.debug "wait command: kubectl get #{kind} --namespace=#{namespace}" + # all_kind = `kubectl get #{kind} --namespace=#{namespace}` + resource_uninstalled = KubectlClient::Get.resource(kind, resource_name) + LOGGING.debug "resource_uninstalled #{resource_uninstalled}}" + second_count = second_count + 1 + end + + LOGGING.info "final resource_uninstalled #{resource_uninstalled}}" + if (resource_uninstalled && resource_uninstalled.as_h == empty_hash) + LOGGING.info "kind/resource #{kind}, #{resource_name} uninstalled." + true + else + LOGGING.info "kind/resource #{kind}, #{resource_name} is still present." + false + end + end + + #TODO make dockercluser reference generic + def self.wait_for_install_by_apply(manifest_file, wait_count=180) + LOGGING.info "wait_for_install_by_apply" + second_count = 0 + apply_resp = `kubectl apply -f #{manifest_file}` + LOGGING.info("apply response: #{apply_resp}") + until (apply_resp =~ /dockercluster.infrastructure.cluster.x-k8s.io\/capd unchanged/) != nil && (apply_resp =~ /cluster.cluster.x-k8s.io\/capd unchanged/) != nil && (apply_resp =~ /kubeadmcontrolplane.controlplane.cluster.x-k8s.io\/capd-control-plane unchanged/) != nil && (apply_resp =~ /kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io\/capd-md-0 unchanged/) !=nil && (apply_resp =~ /machinedeployment.cluster.x-k8s.io\/capd-md-0 unchanged/) != nil && (apply_resp =~ /machinehealthcheck.cluster.x-k8s.io\/capd-mhc-0 unchanged/) != nil || second_count > wait_count.to_i + LOGGING.info("second_count = #{second_count}") + sleep 1 + apply_resp = `kubectl apply -f #{manifest_file}` + LOGGING.info("apply response: #{apply_resp}") + second_count = second_count + 1 + end + end + + def self.resource_desired_is_available?(kind : String, resource_name) + resp = `kubectl get #{kind} #{resource_name} -o=yaml` + replicas_applicable = false + case kind.downcase + when "deployment", "statefulset", "replicaset" + replicas_applicable = true + describe = Totem.from_yaml(resp) + LOGGING.info("desired_is_available describe: #{describe.inspect}") + desired_replicas = describe.get("status").as_h["replicas"].as_i + LOGGING.info("desired_is_available desired_replicas: #{desired_replicas}") + ready_replicas = describe.get("status").as_h["readyReplicas"]? + unless ready_replicas.nil? + ready_replicas = ready_replicas.as_i + else + ready_replicas = 0 + end + LOGGING.info("desired_is_available ready_replicas: #{ready_replicas}") + else + replicas_applicable = false + end + if replicas_applicable + desired_replicas == ready_replicas + else + true + end + end + def self.desired_is_available?(deployment_name) + resource_desired_is_available?("deployment", deployment_name) + end + + + #TODO make a function that gives all the pods for a resource + def self.pods_for_resource(kind : String, resource_name) + LOGGING.info "kind: #{kind}" + LOGGING.info "resource_name: #{resource_name}" + #TODO use get pods and use json + # all_pods = `kubectl get pods #{field_selector} -o json'` + all_pods = KubectlClient::Get.pods + LOGGING.info("all_pods: #{all_pods}") + # all_pod_names = all_pods[0].split(" ") + # time_stamps = all_pods[1].split(" ") + # pods_times = all_pod_names.map_with_index do |name, i| + # {:name => name, :time => time_stamps[i]} + # end + # LOGGING.info("pods_times: #{pods_times}") + # + # latest_pod_time = pods_times.reduce({:name => "not found", :time => "not_found"}) do | acc, i | + + end + + #TODO create a function for waiting for the complete uninstall of a resource + # that has pods + #TODO get all resources for a cnf + #TODO for a replicaset, deployment, statefulset, or daemonset list all pods + #TODO check for terminated status of all pods to be complete (check if pod + # no longer exists) + # def self.resource_wait_for_termination + # end + + #TODO remove the need for a split and return name/ true /false in a hash + #TODO add a spec for this + def self.pod_status(pod_name_prefix, field_selector="", namespace="default") + LOGGING.info "pod_status: #{pod_name_prefix}" + all_pods = `kubectl get pods #{field_selector} -o jsonpath='{.items[*].metadata.name},{.items[*].metadata.creationTimestamp}'`.split(",") + + LOGGING.info(all_pods) + all_pod_names = all_pods[0].split(" ") + time_stamps = all_pods[1].split(" ") + pods_times = all_pod_names.map_with_index do |name, i| + {:name => name, :time => time_stamps[i]} + end + LOGGING.info("pods_times: #{pods_times}") + + latest_pod_time = pods_times.reduce({:name => "not found", :time => "not_found"}) do | acc, i | + # if current i > acc + LOGGING.info("ACC: #{acc}") + LOGGING.info("I:#{i}") + LOGGING.info("pod_name_prefix: #{pod_name_prefix}") + if (i[:name] =~ /#{pod_name_prefix}/).nil? + LOGGING.info "pod_name_prefix: #{pod_name_prefix} does not match #{i[:name]}" + acc + end + if i[:name] =~ /#{pod_name_prefix}/ + LOGGING.info "pod_name_prefix: #{pod_name_prefix} matches #{i[:name]}" + # acc = i + if acc[:name] == "not found" + LOGGING.info "acc not found" + # if there is no previous time, use the time in the index + previous_time = Time.parse!( "#{i[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") + else + LOGGING.info "acc found. time: #{acc[:time]}" + previous_time = Time.parse!( "#{acc[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") + end + new_time = Time.parse!( "#{i[:time]} +00:00", "%Y-%m-%dT%H:%M:%SZ %z") + if new_time >= previous_time + acc = i + else + acc + end + else + acc + end + end + LOGGING.info("latest_pod_time: #{latest_pod_time}") + + if latest_pod_time[:name] + pod = latest_pod_time[:name] + else + pod = "" + end + # pod = all_pod_names[time_stamps.index(latest_time).not_nil!] + # pod = all_pods.select{ | x | x =~ /#{pod_name_prefix}/ } + LOGGING.info "Pods Found: #{pod}" + # TODO refactor to return container statuses + status = "#{pod_name_prefix},NotFound,false" + if pod != "not found" + status = `kubectl get pods #{pod} -o jsonpath='{.metadata.name},{.status.phase},{.status.containerStatuses[*].ready}'` + else + LOGGING.info "pod: #{pod_name_prefix} is NOT found" + end + LOGGING.info "pod_status status: #{status}" + status + end + + def self.node_status(node_name) + all_nodes = `kubectl get nodes -o jsonpath='{.items[*].metadata.name}'` + LOGGING.info(all_nodes) + status = `kubectl get nodes #{node_name} -o jsonpath='{.status.conditions[?(@.type == "Ready")].status}'` + status + end + + def self.deployment_spec_labels(deployment_name) : JSON::Any + resource_spec_labels("deployment", deployment_name) + end + def self.resource_spec_labels(kind, resource_name) : JSON::Any + LOGGING.debug "resource_labels kind: #{kind} resource_name: #{resource_name}" + resp = resource(kind, resource_name).dig?("spec", "template", "metadata", "labels") + LOGGING.debug "resource_labels: #{resp}" + if resp + resp + else + JSON.parse(%({})) + end + end + + def self.container_image_tags(deployment_containers) : Array(NamedTuple(image: String, + tag: String | Nil)) + image_tags = deployment_containers.as_a.map do |container| + LOGGING.debug "container (should have image and tag): #{container}" + {image: container.as_h["image"].as_s.rpartition(":")[0], + #TODO an image may not have a tag + tag: container.as_h["image"].as_s.rpartition(":")[2]?} + end + LOGGING.debug "image_tags: #{image_tags}" + image_tags + end + + def self.worker_nodes : Array(String) + resp = `kubectl get nodes --selector='!node-role.kubernetes.io/master' -o 'go-template={{range .items}}{{$taints:=""}}{{range .spec.taints}}{{if eq .effect "NoSchedule"}}{{$taints = print $taints .key ","}}{{end}}{{end}}{{if not $taints}}{{.metadata.name}}{{ "\\n"}}{{end}}{{end}}'` + LOGGING.debug "kubectl get nodes: #{resp}" + resp.split("\n") + end + def self.schedulable_nodes : Array(String) + resp = `kubectl get nodes -o 'go-template={{range .items}}{{$taints:=""}}{{range .spec.taints}}{{if eq .effect "NoSchedule"}}{{$taints = print $taints .key ","}}{{end}}{{end}}{{if not $taints}}{{.metadata.name}}{{ "\\n"}}{{end}}{{end}}'` + LOGGING.debug "kubectl get nodes: #{resp}" + resp.split("\n") + end + def self.pv : JSON::Any + # TODO should this be all namespaces? + resp = `kubectl get pv -o json` + LOGGING.debug "kubectl get pv: #{resp}" JSON.parse(resp) end + def self.pv_items_by_claim_name(claim_name) + items = pv["items"].as_a.map do |x| + begin + if x["spec"]["claimRef"]["name"] == claim_name + x + else + nil + end + rescue ex + LOGGING.info ex.message + nil + end + end.compact + LOGGING.debug "pv items : #{items}" + items + end def self.container_runtime nodes["items"][0]["status"]["nodeInfo"]["containerRuntimeVersion"].as_s end @@ -23,11 +563,27 @@ module KubectlClient LOGGING.info "runtimes: #{runtimes}" runtimes.uniq end - def self.pods : JSON::Any - resp = `kubectl get pods --all-namespaces -o json` + def self.pods(all_namespaces=true) : JSON::Any + option = all_namespaces ? "--all-namespaces" : "" + resp = `kubectl get pods #{option} -o json` LOGGING.debug "kubectl get pods: #{resp}" JSON.parse(resp) end + + # *pod_exists* returns true if a pod containing *pod_name* exists, regardless of status. + # If *check_ready* is set to true, *pod_exists* validates that the pod exists and + # has a ready status of true + def self.pod_exists?(pod_name, check_ready=false, all_namespaces=false) + LOGGING.debug "pod_exists? pod_name: #{pod_name}" + exists = pods(all_namespaces)["items"].as_a.any? do |x| + (name_comparison = x["metadata"]["name"].as_s? =~ /#{pod_name}/ + (x["metadata"]["name"].as_s? =~ /#{pod_name}/) || + (x["metadata"]["generateName"]? && x["metadata"]["generateName"].as_s? =~ /#{pod_name}/)) && + (check_ready && (x["status"]["conditions"].as_a.find{|x| x["type"].as_s? == "Ready"} && x["status"].as_s? == "True") || check_ready==false) + end + LOGGING.debug "pod exists: #{exists}" + exists + end def self.all_pod_statuses statuses = pods["items"].as_a.map do |x| x["status"] diff --git a/src/tasks/utils/points.cr b/src/tasks/utils/points.cr new file mode 100644 index 000000000..e15bd3745 --- /dev/null +++ b/src/tasks/utils/points.cr @@ -0,0 +1,299 @@ +require "totem" +require "colorize" +require "./types/cnf_conformance_yml_type.cr" +require "./helm.cr" +require "uuid" + +module CNFManager + + module Points + class Results + + enum ResultStatus + Passed + Failed + Skipped + end + + @@file : String + @@file = CNFManager::Points.create_final_results_yml_name + LOGGING.debug "Results.file" + continue = false + LOGGING.info "file exists?:#{File.exists?(@@file)}" + if File.exists?("#{@@file}") + stdout_info "Do you wish to overwrite the #{@@file} file? If so, your previous results.yml will be lost." + print "(Y/N) (Default N): > " + if ENV["CRYSTAL_ENV"]? == "TEST" + continue = true + else + user_input = gets + if user_input == "Y" || user_input == "y" + continue = true + end + end + else + continue = true + end + if continue + File.open("#{@@file}", "w") do |f| + YAML.dump(CNFManager::Points.template_results_yml, f) + end + end + def self.file + @@file + end + end + + def self.points_yml + # TODO get points.yml from remote http + points = File.open("points.yml") do |f| + YAML.parse(f) + end + # LOGGING.debug "points: #{points.inspect}" + points.as_a + end + def self.create_points_yml + unless File.exists?("#{POINTSFILE}") + branch = ENV.has_key?("SCORING_ENV") ? ENV["SCORING_ENV"] : "main" + default_scoring_yml = "https://raw.githubusercontent.com/cncf/cnf-conformance/#{branch}/scoring_config/#{DEFAULT_POINTSFILENAME}" + # LOGGING.info "curl -o #{DEFAULT_POINTSFILENAME} #{ENV.has_key?("SCORING_YML") ? ENV["SCORING_YML"] : default_scoring_yml}" + # `curl -o #{DEFAULT_POINTSFILENAME} #{ENV.has_key?("SCORING_YML") ? ENV["SCORING_YML"] : default_scoring_yml}` + HTTP::Client.get("#{ENV.has_key?("SCORING_YML") ? ENV["SCORING_YML"] : default_scoring_yml}") do |response| + File.write("#{DEFAULT_POINTSFILENAME}", response.body_io) + end + `mv #{DEFAULT_POINTSFILENAME} #{POINTSFILE}` + end + end + + def self.create_final_results_yml_name + FileUtils.mkdir_p("results") unless Dir.exists?("results") + "results/cnf-conformance-results-" + Time.local.to_s("%Y%m%d-%H%M%S-%L") + ".yml" + end + + def self.clean_results_yml(verbose=false) + if File.exists?("#{Results.file}") + results = File.open("#{Results.file}") do |f| + YAML.parse(f) + end + File.open("#{Results.file}", "w") do |f| + YAML.dump({name: results["name"], + status: results["status"], + exit_code: results["exit_code"], + points: results["points"], + items: [] of YAML::Any}, f) + end + end + end + + def self.task_points(task, status : CNFManager::Points::Results::ResultStatus = CNFManager::Points::Results::ResultStatus::Passed) + case status + when CNFManager::Points::Results::ResultStatus::Passed + resp = CNFManager::Points.task_points(task, true) + when CNFManager::Points::Results::ResultStatus::Failed + resp = CNFManager::Points.task_points(task, false) + when CNFManager::Points::Results::ResultStatus::Skipped + field_name = "skipped" + points =points_yml.find {|x| x["name"] == task} + LOGGING.warn "****Warning**** task #{task} not found in points.yml".colorize(:yellow) unless points + if points && points[field_name]? + resp = points[field_name].as_i if points + else + points =points_yml.find {|x| x["name"] == "default_scoring"} + resp = points[field_name].as_i if points + end + end + LOGGING.info "task_points: task: #{task} is worth: #{resp} points" + resp + end + + def self.task_points(task, passed=true) + if passed + field_name = "pass" + else + field_name = "fail" + end + points =points_yml.find {|x| x["name"] == task} + LOGGING.warn "****Warning**** task #{task} not found in points.yml".colorize(:yellow) unless points + if points && points[field_name]? + points[field_name].as_i if points + else + points =points_yml.find {|x| x["name"] == "default_scoring"} + points[field_name].as_i if points + end + end + + def self.total_points(tag=nil) + if tag + tasks = tasks_by_tag(tag) + else + tasks = all_task_test_names + end + yaml = File.open("#{Results.file}") do |file| + YAML.parse(file) + end + LOGGING.debug "total_points: #{tag}, found tasks: #{tasks}" + total = yaml["items"].as_a.reduce(0) do |acc, i| + LOGGING.debug "total_points: #{tag}, #{i["name"].as_s} = #{i["points"].as_i}" + if i["points"].as_i? && i["name"].as_s? && + tasks.find{|x| x == i["name"]} + (acc + i["points"].as_i) + else + acc + end + end + LOGGING.info "total_points: #{tag} = #{total}" + total + end + + def self.total_max_points(tag=nil) + if tag + tasks = tasks_by_tag(tag) + else + tasks = all_task_test_names + end + max = tasks.reduce(0) do |acc, x| + points = task_points(x) + if points + acc + points + else + acc + end + end + LOGGING.info "total_max_points: #{tag} = #{max}" + max + end + + def self.upsert_task(task, status, points) + results = File.open("#{Results.file}") do |f| + YAML.parse(f) + end + + result_items = results["items"].as_a + # remove the existing entry + result_items = result_items.reject do |x| + x["name"] == task + end + + result_items << YAML.parse "{name: #{task}, status: #{status}, points: #{points}}" + File.open("#{Results.file}", "w") do |f| + YAML.dump({name: results["name"], + status: results["status"], + points: results["points"], + exit_code: results["exit_code"], + items: result_items}, f) + end + LOGGING.info "upsert_task: task: #{task} has status: #{status} and is awarded: #{points} points" + end + + def self.failed_task(task, msg) + upsert_task(task, FAILED, task_points(task, false)) + stdout_failure "#{msg}" + end + + def self.passed_task(task, msg) + upsert_task(task, PASSED, task_points(task)) + stdout_success "#{msg}" + end + + def self.skipped_task(task, msg) + upsert_task(task, SKIPPED, task_points(task)) + stdout_success "#{msg}" + end + + def self.failed_required_tasks + yaml = File.open("#{Results.file}") do |file| + YAML.parse(file) + end + yaml["items"].as_a.reduce([] of String) do |acc, i| + if i["status"].as_s == "failed" && + i["name"].as_s? && + task_required(i["name"].as_s) + (acc << i["name"].as_s) + else + acc + end + end + end + + def self.task_required(task) + points =points_yml.find {|x| x["name"] == task} + LOGGING.warn "task #{task} not found in points.yml".colorize(:yellow) unless points + if points && points["required"]? && points["required"].as_bool == true + true + else + false + end + end + + def self.all_task_test_names + result_items =points_yml.reduce([] of String) do |acc, x| + if x["name"].as_s == "default_scoring" || + x["tags"].as_s.split(",").find{|x|x=="platform"} + acc + else + acc << x["name"].as_s + end + end + end + + def self.tasks_by_tag(tag) + #TODO cross reference points.yml tags with results + found = false + result_items =points_yml.reduce([] of String) do |acc, x| + # LOGGING.debug "tasks_by_tag: tag:#{tag}, points.name:#{x["name"].as_s?}, points.tags:#{x["tags"].as_s?}" + if x["tags"].as_s? && x["tags"].as_s.includes?(tag) + acc << x["name"].as_s + else + acc + end + end + end + + def self.all_result_test_names(results_file) + results = File.open(results_file) do |f| + YAML.parse(f) + end + result_items = results["items"].as_a.reduce([] of String) do |acc, x| + acc << x["name"].as_s + end + end + + def self.results_by_tag(tag) + task_list = tasks_by_tag(tag) + + results = File.open("#{Results.file}") do |f| + YAML.parse(f) + end + + found = false + result_items = results["items"].as_a.reduce([] of YAML::Any) do |acc, x| + if x["name"].as_s? && task_list.find{|tl| tl == x["name"].as_s} + acc << x + else + acc + end + end + end + + def self.template_results_yml + #TODO add tags for category summaries + YAML.parse <<-END +name: cnf conformance +status: +points: +exit_code: 0 +items: [] +END + end + + def self.final_cnf_results_yml + LOGGING.info "final_cnf_results_yml" + results_file = `find ./results/* -name "cnf-conformance-results-*.yml"`.split("\n")[-2].gsub("./", "") + if results_file.empty? + raise "No cnf_conformance-results-*.yml found! Did you run the all task?" + end + results_file + end + end + +end diff --git a/src/tasks/utils/release_manager.cr b/src/tasks/utils/release_manager.cr index db13d6266..56b191c0a 100644 --- a/src/tasks/utils/release_manager.cr +++ b/src/tasks/utils/release_manager.cr @@ -1,5 +1,6 @@ require "totem" require "colorize" +require "string_scanner" require "./cnf_manager.cr" require "halite" @@ -25,10 +26,10 @@ module ReleaseManager # cnf_bin_asset_name = "#{cnf_bin_path}" cnf_bin_asset_name = "cnf-conformance" - if ReleaseManager.remote_master_branch_hash == ReleaseManager.current_hash - upsert_version = upsert_version.sub("HEAD", "master") + if ReleaseManager.remote_main_branch_hash == ReleaseManager.current_hash + upsert_version = upsert_version.sub("HEAD", "main") end - if upsert_version =~ /(?i)(master)/ + if upsert_version =~ /(?i)(main)/ prerelease = true draft = false else @@ -36,8 +37,16 @@ module ReleaseManager draft = true end LOGGING.info "upsert_version: #{upsert_version}" - LOGGING.info "upsert_version comparison: upsert_version =~ /(?i)(master|v[0-1]|test_version)/ : #{upsert_version =~ /(?i)(master|v[0-1]|test_version)/}" - unless upsert_version =~ /(?i)(master|v[0-1]|test_version)/ + LOGGING.info "upsert_version comparison: upsert_version =~ /(?i)(main|v[0-9]|test_version)/ : #{upsert_version =~ /(?i)(main|v[0-9]|test_version)/}" + #master-381d20d + invalid_version = !(upsert_version =~ /(?i)(main|v[0-9]|test_version)/) + snap_shot_version = (upsert_version =~ /(?i)(main-)/) + head = (ReleaseManager.current_branch == "HEAD") + skip_snapshot_detached_head = (head && snap_shot_version) + LOGGING.info "invalid_version: #{invalid_version}" + LOGGING.info "current_branch: #{ReleaseManager.current_branch}" + LOGGING.info "skip_snapshot_detached_head: #{skip_snapshot_detached_head}" + if skip_snapshot_detached_head || invalid_version LOGGING.info "Not creating a release for : #{upsert_version}" return {found_release, asset} end @@ -52,6 +61,7 @@ module ReleaseManager # build_resp = `crystal build src/cnf-conformance.cr --release --static --link-flags "-lxml2 -llzma"` # LOGGING.info "build_resp: #{build_resp}" # the name of the binary asset must be unique across all releases in github for project + # TODO if upsert version == test then make unique cnf_tarball_name = "cnf-conformance-#{upsert_version}.tar.gz" cnf_tarball = `tar -czvf #{cnf_tarball_name} ./#{cnf_bin_asset_name}` LOGGING.info "cnf_tarball: #{cnf_tarball}" @@ -68,9 +78,16 @@ module ReleaseManager found_release = release_resp.find {|x| x["tag_name"] == upsert_version} LOGGING.info "find found_release?: #{found_release}" - issues = ReleaseManager.commit_message_issues(ReleaseManager.latest_release, "HEAD") + if upsert_version =~ /(?i)(main)/ + latest_build = ReleaseManager.latest_snapshot + else + latest_build = ReleaseManager.latest_release + end + LOGGING.info "latest_build: #{latest_build}" + issues = ReleaseManager.commit_message_issues(latest_build, "HEAD") + LOGGING.info "issues: #{issues}" titles = issues.reduce("") do |acc, x| - acc + "issue: #{x} Title: #{ReleaseManager.issue_title(x)}\n" + acc + "- #{x} - #{ReleaseManager.issue_title(x)}\n" end # LOGGING.info "titles: #{titles}" notes_template = <<-TEMPLATE @@ -94,7 +111,7 @@ TEMPLATE json = { "tag_name" => upsert_version, "draft" => draft, "prerelease" => prerelease, - "name" => "#{upsert_version} #{Time.local.to_s("%B, %d %Y")}", + "name" => "#{upsert_version} #{Time.local.to_s("%B %d, %Y")}", "body" => notes_template } LOGGING.info "Release not found. Creating a release: # url: #{release_url} headers: #{headers} json #{json}" @@ -111,7 +128,7 @@ TEMPLATE json: { "tag_name" => upsert_version, "draft" => draft, "prerelease" => prerelease, - "name" => "#{upsert_version} #{Time.local.to_s("%B, %d %Y")}", + "name" => "#{upsert_version} #{Time.local.to_s("%B %d, %Y")}", "body" => notes_template }) found_release = JSON.parse(found_resp.body) @@ -169,13 +186,16 @@ TEMPLATE end module CompileTimeVersionGenerater macro tagged_version - {% current_branch = `git rev-parse --abbrev-ref HEAD` %} + {% current_branch = `git rev-parse --abbrev-ref HEAD`.split("\n")[0].strip %} {% current_hash = `git rev-parse --short HEAD` %} - {% current_tag = `git tag --points-at HEAD` %} + {% current_status = `git status`.split("\n")[0].strip %} + {% current_tag = (!`git tag --points-at HEAD`.empty? && `git tag --points-at HEAD`.split("\n")[-2].strip) || `git tag --points-at HEAD` %} + {% puts "current_branch during compile: #{current_branch}" %} + {% puts "current_tag during compile: #{current_tag}" %} {% if current_tag.strip == "" %} - VERSION = "{{current_branch.strip}}-{{current_hash.strip}}" + VERSION = {{current_branch}} + "-#{Time.local.to_s("%Y-%m-%d-%H%M%S")}-{{current_hash.strip}}" {% else %} - VERSION = "{{current_tag.strip}}" + VERSION = {{current_tag.strip}} {% end %} end end @@ -195,7 +215,7 @@ TEMPLATE end def self.current_branch - results = `git rev-parse --abbrev-ref HEAD` + results = `git rev-parse --abbrev-ref HEAD`.split("\n")[0].strip LOGGING.info "current_branch rev-parse: #{results}" results.strip("\n") end @@ -206,9 +226,9 @@ TEMPLATE results.strip("\n") end - def self.remote_master_branch_hash(owner_repo="cncf/cnf-conformance") - results = `git ls-remote https://github.com/#{owner_repo}.git master | awk '{ print $1}' | cut -c1-7`.strip - LOGGING.info "remote_master_branch_hash: #{results}" + def self.remote_main_branch_hash(owner_repo="cncf/cnf-conformance") + results = `git ls-remote https://github.com/#{owner_repo}.git main | awk '{ print $1}' | cut -c1-7`.strip + LOGGING.info "remote_main_branch_hash: #{results}" results.strip("\n") end @@ -222,7 +242,8 @@ TEMPLATE # "Content-Type" => "application/gzip", # "Content-Length" => File.size("#{cnf_tarball_name}").to_s # }, raw: "#{File.open("#{cnf_tarball_name}")}")A - asset_resp = `curl -u #{ENV["GITHUB_USER"]}:#{ENV["GITHUB_TOKEN"]} -H "Content-Type: $(file -b --mime-type #{asset_name})" --data-binary @#{asset_name} "https://uploads.github.com/repos/cncf/cnf-conformance/releases/#{release_id}/assets?name=$(basename #{asset_name})"` + asset_resp = `curl --http1.1 -u #{ENV["GITHUB_USER"]}:#{ENV["GITHUB_TOKEN"]} -H "Content-Type: $(file -b --mime-type #{asset_name})" --data-binary @#{asset_name} "https://uploads.github.com/repos/cncf/cnf-conformance/releases/#{release_id}/assets?name=$(basename #{asset_name})"` + LOGGING.info "asset_resp: #{asset_resp}" asset = JSON.parse(asset_resp.strip) LOGGING.info "asset: #{asset}" asset @@ -256,6 +277,29 @@ TEMPLATE parsed_resp["tag_name"]?.not_nil!.to_s end + def self.latest_snapshot + resp = `curl -u #{ENV["GITHUB_USER"]}:#{ENV["GITHUB_TOKEN"]} --silent "https://api.github.com/repos/cncf/cnf-conformance/releases"` + LOGGING.info "latest_release: #{resp}" + parsed_resp = JSON.parse(resp) + prerelease = parsed_resp.as_a.select{ | x | x["prerelease"]==true && !("#{x["published_at"]?}".empty?) } + latest_snapshot = prerelease.sort do |a, b| + LOGGING.debug "a #{a}" + LOGGING.debug "b #{b}" + if (b["published_at"]? && a["published_at"]?) + Time.parse(b["published_at"].as_s, + "%Y-%m-%dT%H:%M:%SZ", + Time::Location::UTC) <=> + Time.parse(a["published_at"].as_s, + "%Y-%m-%dT%H:%M:%SZ", + Time::Location::UTC) + else + 0 + end + end + LOGGING.debug "latest_snapshot: #{latest_snapshot}" + latest_snapshot[0]["tag_name"]?.not_nil!.to_s + end + def self.issue_title(issue_number) pure_issue = issue_number.gsub("#", "") resp = `curl -u #{ENV["GITHUB_USER"]}:#{ENV["GITHUB_TOKEN"]} "https://api.github.com/repos/cncf/cnf-conformance/issues/#{pure_issue}"` diff --git a/src/tasks/utils/system_information/helm.cr b/src/tasks/utils/system_information/helm.cr index 392069fb4..9445aac68 100644 --- a/src/tasks/utils/system_information/helm.cr +++ b/src/tasks/utils/system_information/helm.cr @@ -8,9 +8,9 @@ def helm_installation(verbose=false) lmsg = "No Local helm version found" ghelm = helm_global_response VERBOSE_LOGGING.info ghelm if verbose - + global_helm_version = helm_version(ghelm, verbose) - + if global_helm_version && !global_helm_version.empty? gmsg = "Global helm found. Version: #{global_helm_version}" stdout_success gmsg @@ -20,9 +20,9 @@ def helm_installation(verbose=false) lhelm = helm_local_response VERBOSE_LOGGING.info lhelm if verbose - + local_helm_version = helm_version(lhelm, verbose) - + if local_helm_version && !local_helm_version.empty? lmsg = "Local helm found. Version: #{local_helm_version}" stdout_success lmsg @@ -41,17 +41,17 @@ def helm_installation(verbose=false) ) end "#{lmsg} #{gmsg}" -end +end def helm_global_response(verbose=false) helm_response = `helm version 2>/dev/null` VERBOSE_LOGGING.info helm_response if verbose - helm_response + helm_response end def helm_local_response(verbose=false) - current_dir = FileUtils.pwd - VERBOSE_LOGGING.info current_dir if verbose + current_dir = FileUtils.pwd + VERBOSE_LOGGING.info current_dir if verbose #helm = "#{current_dir}/#{TOOLS_DIR}/helm/linux-amd64/helm" helm = CNFSingleton.helm # helm_response = `#{helm} version` @@ -71,7 +71,7 @@ def helm_v2_version(helm_response) # example # Client: &version.Version{SemVer:\"v2.14.3\", GitCommit:\"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085\", GitTreeState:\"clean\"}\nServer: &version.Version{SemVer:\"v2.16.1\", GitCommit:\"bbdfe5e7803a12bbdf97e94cd847859890cf4050\", GitTreeState:\"clean\"} helm_v2 = helm_response.match /Client: &version.Version{SemVer:\"(v([0-9]{1,3}[\.]){1,2}[0-9]{1,3}).+"/ - LOGGING.info "helm_v2?: #{helm_v2}" + LOGGING.debug "helm_v2?: #{helm_v2}" helm_v2 && helm_v2.not_nil![1] end @@ -79,7 +79,7 @@ def helm_v3_version(helm_response) # example # version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"} helm_v3 = helm_response.match /BuildInfo{Version:\"(v([0-9]{1,3}[\.]){1,2}[0-9]{1,3}).+"/ - LOGGING.info "helm_v3?: #{helm_v3}" + LOGGING.debug "helm_v3?: #{helm_v3}" helm_v3 && helm_v3.not_nil![1] end diff --git a/src/tasks/utils/system_information/kubectl.cr b/src/tasks/utils/system_information/kubectl.cr index ddac3450e..cb5d2b962 100644 --- a/src/tasks/utils/system_information/kubectl.cr +++ b/src/tasks/utils/system_information/kubectl.cr @@ -78,6 +78,8 @@ def kubectl_local_response(verbose=false) kubectl_response.to_s end +# TODO create a kubernetes version checker (vs kubectl client checker) + def kubectl_version(kubectl_response, verbose=false) # example # Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T11:13:54Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"} diff --git a/src/tasks/utils/task.cr b/src/tasks/utils/task.cr new file mode 100644 index 000000000..f9fe86748 --- /dev/null +++ b/src/tasks/utils/task.cr @@ -0,0 +1,74 @@ +require "totem" +require "colorize" +require "./types/cnf_conformance_yml_type.cr" +require "./helm.cr" +require "uuid" +require "./points.cr" + +module CNFManager + + module Task + def self.task_runner(args, &block : Sam::Args, CNFManager::Config -> String | Colorize::Object(String) | Nil) + LOGGING.info("task_runner args: #{args.inspect}") + if check_cnf_config(args) + single_task_runner(args, &block) + else + all_cnfs_task_runner(args, &block) + end + end + + # TODO give example for calling + def self.all_cnfs_task_runner(args, &block : Sam::Args, CNFManager::Config -> String | Colorize::Object(String) | Nil) + + # Platforms tests dont have any cnfs + if CNFManager.cnf_config_list(silent: true).size == 0 + single_task_runner(args, &block) + else + CNFManager.cnf_config_list(silent: true).map do |x| + new_args = Sam::Args.new(args.named, args.raw) + new_args.named["cnf-config"] = x + single_task_runner(new_args, &block) + end + end + end + # TODO give example for calling + def self.single_task_runner(args, &block : Sam::Args, CNFManager::Config -> String | Colorize::Object(String) | Nil) + LOGGING.debug("single_task_runner args: #{args.inspect}") + begin + if args.named["cnf-config"]? # platform tests don't have a cnf-config + config = CNFManager::Config.parse_config_yml(args.named["cnf-config"].as(String)) + else + config = CNFManager::Config.new({ destination_cnf_dir: "", + source_cnf_file: "", + source_cnf_dir: "", + yml_file_path: "", + install_method: {:helm_chart, ""}, + manifest_directory: "", + helm_directory: "", + helm_chart_path: "", + manifest_file_path: "", + git_clone_url: "", + install_script: "", + release_name: "", + service_name: "", + docker_repository: "", + helm_repository: {name: "", repo_url: ""}, + helm_chart: "", + helm_chart_container_name: "", + rolling_update_tag: "", + container_names: [{"name" => "", "rolling_update_test_tag" => ""}], + white_list_container_names: [""]} ) + end + yield args, config + rescue ex + # Set exception key/value in results + # file to -1 + update_yml("#{CNFManager::Points::Results.file}", "exit_code", "1") + LOGGING.error ex.message + ex.backtrace.each do |x| + LOGGING.error x + end + end + end + end +end diff --git a/src/tasks/utils/types/cnf_conformance_yml_type.cr b/src/tasks/utils/types/cnf_conformance_yml_type.cr index bc16ca8cf..bd3520dcc 100644 --- a/src/tasks/utils/types/cnf_conformance_yml_type.cr +++ b/src/tasks/utils/types/cnf_conformance_yml_type.cr @@ -20,7 +20,7 @@ class CnfConformanceYmlType {{ @type.methods.map &.name.stringify }} end - property helm_directory : String + property helm_directory : String? property git_clone_url : String? @@ -28,15 +28,15 @@ class CnfConformanceYmlType property service_name : String? - property release_name : String + property release_name : String? property docker_repository : String? - property deployment_name : String + property deployment_name : String? - property deployment_label : String + property deployment_label : String? - property application_deployment_names : Array(String) + property application_deployment_names : Array(String)? property helm_repository : HelmRepositoryType? @@ -44,16 +44,22 @@ class CnfConformanceYmlType property helm_chart_container_name : String? - property rolling_update_tag : String? + property rolling_update_test_tag : String? + property rolling_downgrade_test_tag : String? + property rolling_version_change_test_tag : String? - property white_list_helm_chart_container_names : Array(String) + property rollback_from_tag : String? + + property allowlist_helm_chart_container_names : Array(String)? + + property container_names : Array(Hash(String,String)) end class HelmRepositoryType include JSON::Serializable include JSON::Serializable::Unmapped - property name : String + property name : String? - property repo_url : String + property repo_url : String? end diff --git a/src/tasks/utils/utils.cr b/src/tasks/utils/utils.cr index d780147c5..e18c3721e 100644 --- a/src/tasks/utils/utils.cr +++ b/src/tasks/utils/utils.cr @@ -7,28 +7,7 @@ require "log" require "file_utils" require "option_parser" require "../constants.cr" - -# TODO make constants local or always retrieve from environment variables -# TODO Move constants out -# TODO put these functions into a module - -# TODO: error with proper exit_code when any of these don't exist and ask user to run setup command -CNF_DIR = "cnfs" -CONFIG_FILE = "cnf-conformance.yml" -TOOLS_DIR = "tools" -BASE_CONFIG = "./config.yml" -# Results.file = "cnf-conformance-results-#{Time.utc.to_s("%Y%m%d")}.log" -# Results.file = "results.yml" -POINTSFILE = "points.yml" -PASSED = "passed" -FAILED = "failed" -DEFAULT_POINTSFILENAME = "points_v1.yml" -PRIVILEGED_WHITELIST_CONTAINERS = ["chaos-daemon"] - -#Embedded global text variables -EmbeddedFileManager.node_failure_values -EmbeddedFileManager.cri_tools -EmbeddedFileManager.reboot_daemon +require "semantic_version" def log_formatter Log::Formatter.new do |entry, io| @@ -52,14 +31,14 @@ begin end parser.on("-h", "--help", "Show this help") { puts parser } end -rescue ex : OptionParser::InvalidOption - puts ex +rescue ex : OptionParser::InvalidOption + puts ex end # this first line necessary to make sure our custom formatter # is used in the default error log line also - Log.setup(Log::Severity::Error, Log::IOBackend.new(formatter: log_formatter)) - Log.setup(loglevel, Log::IOBackend.new(formatter: log_formatter)) +Log.setup(Log::Severity::Error, Log::IOBackend.new(formatter: log_formatter)) +Log.setup(loglevel, Log::IOBackend.new(formatter: log_formatter)) def loglevel @@ -80,10 +59,14 @@ def loglevel end end - if ENV.has_key?("LOGLEVEL") + if ENV.has_key?("LOGLEVEL") levelstr = ENV["LOGLEVEL"] end + if ENV.has_key?("LOG_LEVEL") + levelstr = ENV["LOG_LEVEL"] + end + # highest priority is last if !LogLevel.command_line_loglevel.empty? levelstr = LogLevel.command_line_loglevel @@ -145,46 +128,6 @@ end LOGGING = LogginGenerator.new VERBOSE_LOGGING = VerboseLogginGenerator.new -def generate_version - version = "" - if ReleaseManager.on_a_tag? - version = ReleaseManager.tag - else - version = "#{ReleaseManager.current_branch} #{ReleaseManager.current_hash}" - end - return version -end - -class Results - @@file : String - @@file = create_final_results_yml_name - LOGGING.info "Results file" - continue = false - LOGGING.info "file exists?:#{File.exists?(@@file)}" - if File.exists?("#{@@file}") - stdout_info "Do you wish to overwrite the #{@@file} file? If so, your previous results.yml will be lost." - print "(Y/N) (Default N): > " - if ENV["CRYSTAL_ENV"]? == "TEST" - continue = true - else - user_input = gets - if user_input == "Y" || user_input == "y" - continue = true - end - end - else - continue = true - end - if continue - File.open("#{@@file}", "w") do |f| - YAML.dump(template_results_yml, f) - end - end - def self.file - @@file - end -end - def check_verbose(args) ((args.raw.includes? "verbose") || (args.raw.includes? "v")) end @@ -203,67 +146,12 @@ def check_cnf_config(args) cnf end -def check_all_cnf_args(args) - VERBOSE_LOGGING.debug "args = #{args.inspect}" if check_verbose(args) - cnf = check_cnf_config(args) - deploy_with_chart = true - if cnf - VERBOSE_LOGGING.info "all cnf: #{cnf}" if check_verbose(args) - if args.named["deploy_with_chart"]? && args.named["deploy_with_chart"] == "false" - deploy_with_chart = false - end - end - return cnf, deploy_with_chart -end - -def check_cnf_config_then_deploy(args) - config_file, deploy_with_chart = check_all_cnf_args(args) - CNFManager.sample_setup_args(sample_dir: config_file, deploy_with_chart: deploy_with_chart, args: args, verbose: check_verbose(args) ) if config_file -end - -def task_runner(args, &block : Sam::Args -> String | Colorize::Object(String) | Nil) - # LOGGING.info("single_or_all_cnfs_task_runner: #{args.inspect}") - if check_cnf_config(args) - single_task_runner(args, &block) - else - all_cnfs_task_runner(args, &block) - end -end - -# TODO give example for calling -def all_cnfs_task_runner(args, &block : Sam::Args -> String | Colorize::Object(String) | Nil) - - # Platforms tests dont have any cnfs - if CNFManager.cnf_config_list(silent: true).size == 0 - single_task_runner(args, &block) - else - CNFManager.cnf_config_list(silent: true).map do |x| - new_args = Sam::Args.new(args.named, args.raw) - new_args.named["cnf-config"] = x - single_task_runner(new_args, &block) - end - end -end - -# TODO give example for calling -def single_task_runner(args, &block) - # LOGGING.info("task_runner args: #{args.inspect}") - begin - yield args - rescue ex - LOGGING.error ex.message - ex.backtrace.each do |x| - LOGGING.error x - end - end -end - def toggle(toggle_name) toggle_on = false if File.exists?(BASE_CONFIG) - config = Totem.from_file BASE_CONFIG + config = Totem.from_file BASE_CONFIG if config["toggles"].as_a? - feature_flag = config["toggles"].as_a.find do |x| + feature_flag = config["toggles"].as_a.find do |x| x["name"] == toggle_name end toggle_on = feature_flag["toggle_on"].as_bool if feature_flag @@ -343,240 +231,39 @@ def check_destructive(args) toggle("destructive") || args.raw.includes?("destructive") end -def template_results_yml - #TODO add tags for category summaries - YAML.parse <<-END -name: cnf conformance -status: -points: -items: [] -END -end - -def create_final_results_yml_name - FileUtils.mkdir_p("results") unless Dir.exists?("results") - "results/cnf-conformance-results-" + Time.local.to_s("%Y%m%d-%H%M%S-%L") + ".yml" -end - -def create_points_yml - unless File.exists?("#{POINTSFILE}") - branch = ENV.has_key?("SCORING_ENV") ? ENV["SCORING_ENV"] : "master" - default_scoring_yml = "https://raw.githubusercontent.com/cncf/cnf-conformance/#{branch}/scoring_config/#{DEFAULT_POINTSFILENAME}" - `wget #{ENV.has_key?("SCORING_YML") ? ENV["SCORING_YML"] : default_scoring_yml}` - `mv #{DEFAULT_POINTSFILENAME} #{POINTSFILE}` - end -end - -def delete_results_yml(verbose=false) - if File.exists?("#{Results.file}") - File.delete("#{Results.file}") - end -end - -def clean_results_yml(verbose=false) - if File.exists?("#{Results.file}") - results = File.open("#{Results.file}") do |f| - YAML.parse(f) - end - File.open("#{Results.file}", "w") do |f| - YAML.dump({name: results["name"], - status: results["status"], - points: results["points"], - items: [] of YAML::Any}, f) - end - end -end - -def points_yml - # TODO get points.yml from remote http - points = File.open("points.yml") do |f| +def update_yml(yml_file, top_level_key, value) + results = File.open("#{yml_file}") do |f| YAML.parse(f) - end - # LOGGING.debug "points: #{points.inspect}" - points.as_a -end - -def upsert_task(task, status, points) - results = File.open("#{Results.file}") do |f| - YAML.parse(f) - end - - result_items = results["items"].as_a - # remove the existing entry - result_items = result_items.reject do |x| - x["name"] == task end - - result_items << YAML.parse "{name: #{task}, status: #{status}, points: #{points}}" - File.open("#{Results.file}", "w") do |f| - YAML.dump({name: results["name"], - status: results["status"], - points: results["points"], - items: result_items}, f) - end -end - -def failed_task(task, msg) - upsert_task(task, FAILED, task_points(task, false)) - stdout_failure "#{msg}" -end - -def passed_task(task, msg) - upsert_task(task, PASSED, task_points(task)) - stdout_success "#{msg}" + LOGGING.debug "update_yml results: #{results}" + # The last key assigned wins + new_yaml = YAML.dump(results) + "\n#{top_level_key}: #{value}" + parsed_new_yml = YAML.parse(new_yaml) + LOGGING.debug "update_yml parsed_new_yml: #{parsed_new_yml}" + File.open("#{yml_file}", "w") do |f| + YAML.dump(parsed_new_yml,f) + end end def upsert_failed_task(task, message) - upsert_task(task, FAILED, task_points(task, false)) + CNFManager::Points.upsert_task(task, FAILED, CNFManager::Points.task_points(task, false)) stdout_failure message message end def upsert_passed_task(task, message) - upsert_task(task, PASSED, task_points(task)) + CNFManager::Points.upsert_task(task, PASSED, CNFManager::Points.task_points(task)) stdout_success message message end -def task_points(task, passed=true) - if passed - field_name = "pass" - else - field_name = "fail" - end - points = points_yml.find {|x| x["name"] == task} - LOGGING.warn "****Warning**** task #{task} not found in points.yml".colorize(:yellow) unless points - if points && points[field_name]? - points[field_name].as_i if points - else - points = points_yml.find {|x| x["name"] == "default_scoring"} - points[field_name].as_i if points - end -end - -def task_required(task) - points = points_yml.find {|x| x["name"] == task} - LOGGING.warn "task #{task} not found in points.yml".colorize(:yellow) unless points - if points && points["required"]? && points["required"].as_bool == true - true - else - false - end -end - -def failed_required_tasks - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - yaml["items"].as_a.reduce([] of String) do |acc, i| - if i["status"].as_s == "failed" && - i["name"].as_s? && - task_required(i["name"].as_s) - (acc << i["name"].as_s) - else - acc - end - end -end - -# def total_points -# yaml = File.open("#{Results.file}") do |file| -# YAML.parse(file) -# end -# yaml["items"].as_a.reduce(0) do |acc, i| -# if i["points"].as_i? -# (acc + i["points"].as_i) -# else -# acc -# end -# end -# end - -def total_points(tag=nil) - if tag - tasks = tasks_by_tag(tag) - else - tasks = all_task_test_names - end - yaml = File.open("#{Results.file}") do |file| - YAML.parse(file) - end - yaml["items"].as_a.reduce(0) do |acc, i| - if i["points"].as_i? && i["name"].as_s? && - tasks.find{|x| x == i["name"]} - (acc + i["points"].as_i) - else - acc - end - end -end - -def total_max_points(tag=nil) - if tag - tasks = tasks_by_tag(tag) - else - tasks = all_task_test_names - end - tasks.reduce(0) do |acc, x| - points = task_points(x) - if points - acc + points - else - acc - end - end -end - -def all_task_test_names - result_items = points_yml.reduce([] of String) do |acc, x| - if x["name"].as_s == "default_scoring" || - x["tags"].as_s.split(",").find{|x|x=="platform"} - acc - else - acc << x["name"].as_s - end - end -end - -def tasks_by_tag(tag) - #TODO cross reference points.yml tags with results - found = false - result_items = points_yml.reduce([] of String) do |acc, x| - if x["tags"].as_s? && x["tags"].as_s.includes?(tag) - acc << x["name"].as_s - else - acc - end - end -end - -def all_result_test_names(results_file) - results = File.open(results_file) do |f| - YAML.parse(f) - end - result_items = results["items"].as_a.reduce([] of String) do |acc, x| - acc << x["name"].as_s - end -end - -def results_by_tag(tag) - task_list = tasks_by_tag(tag) - - results = File.open("#{Results.file}") do |f| - YAML.parse(f) - end - - found = false - result_items = results["items"].as_a.reduce([] of YAML::Any) do |acc, x| - if x["name"].as_s? && task_list.find{|tl| tl == x["name"].as_s} - acc << x - else - acc - end - end +def upsert_skipped_task(task, message) + CNFManager::Points.upsert_task(task, SKIPPED, CNFManager::Points.task_points(task, CNFManager::Points::Results::ResultStatus::Skipped)) + stdout_warning message + message end -def stdout_info(msg) +def stdout_info(msg) puts msg end @@ -593,9 +280,9 @@ def stdout_failure(msg) end def stdout_score(test_name) - total = total_points(test_name) + total = CNFManager::Points.total_points(test_name) pretty_test_name = test_name.split(/:|_/).map(&.capitalize).join(" ") - test_log_msg = "#{pretty_test_name} final score: #{total} of #{total_max_points(test_name)}" + test_log_msg = "#{pretty_test_name} final score: #{total} of #{CNFManager::Points.total_max_points(test_name)}" if total > 0 stdout_success test_log_msg @@ -603,3 +290,18 @@ def stdout_score(test_name) stdout_failure test_log_msg end end + +# this method extracts a string value from a config section if it exists +# if the value is an integer it will be converted to a string before extraction +def optional_key_as_string(totem_config, key_name) + "#{totem_config[key_name]? && (totem_config[key_name].as_s? || totem_config[key_name].as_i?)}" +end + +# compare 2 SemVer strings and return true if v1 is less than v2 +def version_less_than(v1str, v2str) + v1 = SemanticVersion.parse(v1str) + v2 = SemanticVersion.parse(v2str) + less_than = (v1 <=> v2) == -1 + LOGGING.debug "version_less_than: #{v1} < #{v2}: #{less_than}" + less_than +end diff --git a/src/tasks/compatibility.cr b/src/tasks/workload/compatibility.cr similarity index 89% rename from src/tasks/compatibility.cr rename to src/tasks/workload/compatibility.cr index d8a5fa5f3..6104745c8 100644 --- a/src/tasks/compatibility.cr +++ b/src/tasks/workload/compatibility.cr @@ -2,7 +2,7 @@ require "sam" require "file_utils" require "colorize" require "totem" -require "./utils/utils.cr" +require "../utils/utils.cr" desc "CNFs should work with any Certified Kubernetes product and any CNI-compatible network that meet their functionality requirements." task "compatibility" do |_, args| diff --git a/src/tasks/workload/configuration_lifecycle.cr b/src/tasks/workload/configuration_lifecycle.cr new file mode 100644 index 000000000..9a43b28fb --- /dev/null +++ b/src/tasks/workload/configuration_lifecycle.cr @@ -0,0 +1,583 @@ +# coding: utf-8 +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "json" +require "../utils/utils.cr" + +rolling_version_change_test_names = ["rolling_update", "rolling_downgrade", "rolling_version_change"] + +desc "Configuration and lifecycle should be managed in a declarative manner, using ConfigMaps, Operators, or other declarative interfaces." +task "configuration_lifecycle", ["ip_addresses", "liveness", "readiness", "nodeport_not_used", "hardcoded_ip_addresses_in_k8s_runtime_configuration", "rollback", "secrets_used", "immutable_configmap"].concat(rolling_version_change_test_names) do |_, args| + stdout_score("configuration_lifecycle") +end + +desc "Does a search for IP addresses or subnets come back as negative?" +task "ip_addresses" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "ip_addresses" if check_verbose(args) + LOGGING.info("ip_addresses args #{args.inspect}") + cdir = FileUtils.pwd() + response = String::Builder.new + helm_directory = config.cnf_config[:helm_directory] + helm_chart_path = config.cnf_config[:helm_chart_path] + if File.directory?(helm_chart_path) + # Switch to the helm chart directory + Dir.cd(helm_chart_path) + # Look for all ip addresses that are not comments + LOGGING.info "current directory: #{ FileUtils.pwd()}" + # should catch comments (# // or /*) and ignore 0.0.0.0 + # note: grep wants * escaped twice + Process.run("grep -r -P '^(?!.+0\.0\.0\.0)(?![[:space:]]*0\.0\.0\.0)(?!#)(?![[:space:]]*#)(?!\/\/)(?![[:space:]]*\/\/)(?!\/\\*)(?![[:space:]]*\/\\*)(.+([0-9]{1,3}[\.]){3}[0-9]{1,3})'", shell: true) do |proc| + while line = proc.output.gets + response << line + VERBOSE_LOGGING.info "#{line}" if check_verbose(args) + end + end + Dir.cd(cdir) + if response.to_s.size > 0 + resp = upsert_failed_task("ip_addresses","✖️ FAILED: IP addresses found") + else + resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") + end + resp + else + # TODO If no helm chart directory, exit with 0 points + # ADD SKIPPED tag for points.yml to allow for 0 points + Dir.cd(cdir) + resp = upsert_passed_task("ip_addresses", "✔️ PASSED: No IP addresses found") + end + end +end + +desc "Is there a liveness entry in the helm chart?" +task "liveness" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "liveness" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + resp = "" + emoji_probe="🧫" + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + test_passed = true + begin + VERBOSE_LOGGING.debug container.as_h["name"].as_s if check_verbose(args) + container.as_h["livenessProbe"].as_h + rescue ex + VERBOSE_LOGGING.error ex.message if check_verbose(args) + test_passed = false + puts "No livenessProbe found for resource: #{resource} and container: #{container.as_h["name"].as_s}".colorize(:red) + end + LOGGING.debug "liveness test_passed: #{test_passed}" + test_passed + end + LOGGING.debug "liveness task response: #{task_response}" + if task_response + resp = upsert_passed_task("liveness","✔️ PASSED: Helm liveness probe found #{emoji_probe}") + else + resp = upsert_failed_task("liveness","✖️ FAILED: No livenessProbe found #{emoji_probe}") + end + resp + end +end + +desc "Is there a readiness entry in the helm chart?" +task "readiness" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + LOGGING.debug "cnf_config: #{config}" + VERBOSE_LOGGING.info "readiness" if check_verbose(args) + # Parse the cnf-conformance.yml + resp = "" + emoji_probe="🧫" + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + test_passed = true + begin + VERBOSE_LOGGING.debug container.as_h["name"].as_s if check_verbose(args) + container.as_h["readinessProbe"].as_h + rescue ex + VERBOSE_LOGGING.error ex.message if check_verbose(args) + test_passed = false + puts "No readinessProbe found for resource: #{resource} and container: #{container.as_h["name"].as_s}".colorize(:red) + end + test_passed + end + if task_response + resp = upsert_passed_task("readiness","✔️ PASSED: Helm readiness probe found #{emoji_probe}") + else + resp = upsert_failed_task("readiness","✖️ FAILED: No readinessProbe found #{emoji_probe}") + end + resp + end +end + +rolling_version_change_test_names.each do |tn| + pretty_test_name = tn.split(/:|_/).join(" ") + pretty_test_name_capitalized = tn.split(/:|_/).map(&.capitalize).join(" ") + + desc "Test if the CNF containers are loosely coupled by performing a #{pretty_test_name}" + task "#{tn}" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + LOGGING.debug "cnf_config: #{config}" + VERBOSE_LOGGING.info "#{tn}" if check_verbose(args) + container_names = config.cnf_config[:container_names] + LOGGING.debug "container_names: #{container_names}" + update_applied = true + unless container_names + puts "Please add a container names set of entries into your cnf-conformance.yml".colorize(:red) + update_applied = false + end + + # TODO use tag associated with image name string (e.g. busybox:v1.7.9) as the version tag + # TODO optional get a valid version from the remote repo and roll to that, if no tag + # e.g. wget -q https://registry.hub.docker.com/v1/repositories/debian/tags -O - | sed -e 's/[][]//g' -e 's/"//g' -e 's/ //g' | tr '}' '\n' | awk -F: '{print $3}' + # note: all images are not on docker hub nor are they always on a docker hub compatible api + + task_response = update_applied && CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + test_passed = true + valid_cnf_conformance_yml = true + LOGGING.debug "#{tn} container: #{container}" + LOGGING.debug "container_names: #{container_names}" + config_container = container_names.find{|x| x["name"]==container.as_h["name"]} if container_names + LOGGING.debug "config_container: #{config_container}" + unless config_container && config_container["#{tn}_test_tag"]? && !config_container["#{tn}_test_tag"].empty? + puts "Please add the container name #{container.as_h["name"]} and a corresponding #{tn}_test_tag into your cnf-conformance.yml under container names".colorize(:red) + valid_cnf_conformance_yml = false + end + + VERBOSE_LOGGING.debug "#{tn}: #{container} valid_cnf_conformance_yml=#{valid_cnf_conformance_yml}" if check_verbose(args) + VERBOSE_LOGGING.debug "#{tn}: #{container} config_container=#{config_container}" if check_verbose(args) + if valid_cnf_conformance_yml && config_container + resp = KubectlClient::Set.image(resource["name"], + container.as_h["name"], + # split out image name from version tag + container.as_h["image"].as_s.rpartition(":")[0], + config_container["#{tn}_test_tag"]) + else + resp = false + end + # If any containers dont have an update applied, fail + test_passed = false if resp == false + + rollout_status = KubectlClient::Rollout.resource_status(resource["kind"], resource["name"], timeout="60s") + unless rollout_status + test_passed = false + end + VERBOSE_LOGGING.debug "#{tn}: #{container} test_passed=#{test_passed}" if check_verbose(args) + test_passed + end + VERBOSE_LOGGING.debug "#{tn}: task_response=#{task_response}" if check_verbose(args) + if task_response + resp = upsert_passed_task("#{tn}","✔️ PASSED: CNF for #{pretty_test_name_capitalized} Passed" ) + else + resp = upsert_failed_task("#{tn}", "✖️ FAILED: CNF for #{pretty_test_name_capitalized} Failed") + end + resp + # TODO should we roll the image back to original version in an ensure? + # TODO Use the kubectl rollback to history command + end + end +end + +desc "Test if the CNF can perform a rollback" +task "rollback" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "rollback" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + + container_names = config.cnf_config[:container_names] + LOGGING.debug "container_names: #{container_names}" + + update_applied = true + rollout_status = true + rollback_status = true + version_change_applied = true + + unless container_names + puts "Please add a container names set of entries into your cnf-conformance.yml".colorize(:red) + update_applied = false + end + + task_response = update_applied && CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + deployment_name = resource["name"] + container_name = container.as_h["name"] + full_image_name_tag = container.as_h["image"].as_s.rpartition(":") + image_name = full_image_name_tag[0] + image_tag = full_image_name_tag[2] + + VERBOSE_LOGGING.debug "deployment_name: #{deployment_name}" if check_verbose(args) + VERBOSE_LOGGING.debug "container_name: #{container_name}" if check_verbose(args) + VERBOSE_LOGGING.debug "image_name: #{image_name}" if check_verbose(args) + VERBOSE_LOGGING.debug "image_tag: #{image_tag}" if check_verbose(args) + LOGGING.debug "rollback: setting new version" + #do_update = `kubectl set image deployment/coredns-coredns coredns=coredns/coredns:latest --record` + + version_change_applied = true + config_container = container_names.find{|x| x["name"] == container_name } if container_names + unless config_container && config_container["rollback_from_tag"]? && !config_container["rollback_from_tag"].empty? + puts "Please add the container name #{container.as_h["name"]} and a corresponding rollback_from_tag into your cnf-conformance.yml under container names".colorize(:red) + version_change_applied = false + end + if version_change_applied && config_container + rollback_from_tag = config_container["rollback_from_tag"] + + if rollback_from_tag == image_tag + fail_msg = "✖️ FAILED: please specify a different version than the helm chart default image.tag for 'rollback_from_tag' " + puts fail_msg.colorize(:red) + version_change_applied=false + end + + VERBOSE_LOGGING.debug "rollback: update deployment: #{deployment_name}, container: #{container_name}, image: #{image_name}, tag: #{rollback_from_tag}" if check_verbose(args) + version_change_applied = KubectlClient::Set.image(deployment_name, + container_name, + image_name, + rollback_from_tag) + end + + LOGGING.info "rollback version change successful? #{version_change_applied}" + + VERBOSE_LOGGING.debug "rollback: checking status new version" if check_verbose(args) + rollout_status = KubectlClient::Rollout.status(deployment_name, timeout="60s") + if rollout_status == false + puts "Rolling update failed on resource: #{deployment_name} and container: #{container_name}".colorize(:red) + end + + # https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-to-a-previous-revision + VERBOSE_LOGGING.debug "rollback: rolling back to old version" if check_verbose(args) + rollback_status = KubectlClient::Rollout.undo(deployment_name) + + end + + + if task_response && version_change_applied && rollout_status && rollback_status + upsert_passed_task("rollback","✔️ PASSED: CNF Rollback Passed" ) + else + upsert_failed_task("rollback", "✖️ FAILED: CNF Rollback Failed") + end + end +end + +desc "Does the CNF use NodePort" +task "nodeport_not_used" do |_, args| + # TODO rename task_runner to multi_cnf_task_runner + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "nodeport_not_used" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + release_name = config.cnf_config[:release_name] + service_name = config.cnf_config[:service_name] + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + task_response = CNFManager.workload_resource_test(args, config, check_containers:false, check_service: true) do |resource, container, initialized| + LOGGING.info "nodeport_not_used resource: #{resource}" + if resource["kind"].as_s.downcase == "service" + LOGGING.info "resource kind: #{resource}" + service = KubectlClient::Get.resource(resource[:kind], resource[:name]) + LOGGING.debug "service: #{service}" + service_type = service.dig?("spec", "type") + LOGGING.info "service_type: #{service_type}" + VERBOSE_LOGGING.debug service_type if check_verbose(args) + if service_type == "NodePort" + #TODO make a service selector and display the related resources + # that are tied to this service + puts "resource service: #{resource} has a NodePort that is being used".colorize(:red) + test_passed=false + end + test_passed + end + end + if task_response + upsert_passed_task("nodeport_not_used", "✔️ PASSED: NodePort is not used") + else + upsert_failed_task("nodeport_not_used", "✖️ FAILED: NodePort is being used") + end + end +end + +desc "Does the CNF have hardcoded IPs in the K8s resource configuration" +task "hardcoded_ip_addresses_in_k8s_runtime_configuration" do |_, args| + task_response = CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "Task Name: hardcoded_ip_addresses_in_k8s_runtime_configuration" if check_verbose(args) + # config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + helm_chart = config.cnf_config[:helm_chart] + helm_directory = config.cnf_config[:helm_directory] + release_name = config.cnf_config[:release_name] + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + current_dir = FileUtils.pwd + helm = CNFSingleton.helm + VERBOSE_LOGGING.info "Helm Path: #{helm}" if check_verbose(args) + + create_namespace = `kubectl create namespace hardcoded-ip-test` + unless helm_chart.empty? + helm_install = `#{helm} install --namespace hardcoded-ip-test hardcoded-ip-test #{helm_chart} --dry-run --debug > #{destination_cnf_dir}/helm_chart.yml` + VERBOSE_LOGGING.info "helm_chart: #{helm_chart}" if check_verbose(args) + else + helm_install = `#{helm} install --namespace hardcoded-ip-test hardcoded-ip-test #{destination_cnf_dir}/#{helm_directory} --dry-run --debug > #{destination_cnf_dir}/helm_chart.yml` + VERBOSE_LOGGING.info "helm_directory: #{helm_directory}" if check_verbose(args) + end + + ip_search = File.read_lines("#{destination_cnf_dir}/helm_chart.yml").take_while{|x| x.match(/NOTES:/) == nil}.reduce([] of String){|acc, x| x.match(/([0-9]{1,3}[\.]){3}[0-9]{1,3}/) && x.match(/([0-9]{1,3}[\.]){3}[0-9]{1,3}/).try &.[0] != "0.0.0.0" ? acc << x : acc} + VERBOSE_LOGGING.info "IPs: #{ip_search}" if check_verbose(args) + + if ip_search.empty? + upsert_passed_task("hardcoded_ip_addresses_in_k8s_runtime_configuration", "✔️ PASSED: No hard-coded IP addresses found in the runtime K8s configuration") + else + upsert_failed_task("hardcoded_ip_addresses_in_k8s_runtime_configuration", "✖️ FAILED: Hard-coded IP addresses found in the runtime K8s configuration") + end + delete_namespace = `kubectl delete namespace hardcoded-ip-test --force --grace-period 0 2>&1 >/dev/null` + + end +end + +desc "Does the CNF use K8s Secrets?" +task "secrets_used" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + LOGGING.debug "cnf_config: #{config}" + VERBOSE_LOGGING.info "secrets_used" if check_verbose(args) + # Parse the cnf-conformance.yml + resp = "" + emoji_probe="🧫" + task_response = CNFManager.workload_resource_test(args, config, check_containers=false) do |resource, containers, volumes, initialized| + LOGGING.info "resource: #{resource}" + LOGGING.info "volumes: #{volumes}" + + volume_test_passed = false + container_secret_mounted = false + # Check to see any volume secrets are actually used + volumes.as_a.each do |secret_volume| + if secret_volume["secret"]? + LOGGING.info "secret_volume: #{secret_volume["name"]}" + container_secret_mounted = false + containers.as_a.each do |container| + if container["volumeMounts"]? + vmount = container["volumeMounts"].as_a + LOGGING.info "vmount: #{vmount}" + LOGGING.debug "container[env]: #{container["env"]}" + if (vmount.find { |x| x["name"] == secret_volume["name"]? }) + LOGGING.debug secret_volume["name"] + container_secret_mounted = true + volume_test_passed = true + end + end + end + # If any secret volume exists, and it is not mounted by a + # container, issue a warning + unless container_secret_mounted + puts "Warning: secret volume #{secret_volume["name"]} not mounted".colorize(:yellow) + end + end + end + + # if there are any containers that have a secretkeyref defined + # but do not have a corresponding k8s secret defined, this + # is an installation problem, and does not stop the test from passing + + secrets = KubectlClient::Get.secrets + secrets["items"].as_a.each do |s| + s_name = s["metadata"]["name"] + s_type = s["type"] + VERBOSE_LOGGING.info "secret name: #{s_name}, type: #{s_type}" if check_verbose(args) + end + secret_keyref_found_and_not_ignored = false + containers.as_a.each do |container| + c_name = container["name"] + VERBOSE_LOGGING.info "container: #{c_name} envs #{container["env"]?}" if check_verbose(args) + if container["env"]? + container["env"].as_a.find do |env| + VERBOSE_LOGGING.debug "checking container: #{c_name}" if check_verbose(args) + secret_keyref_found_and_not_ignored = secrets["items"].as_a.find do |s| + s_name = s["metadata"]["name"] + if IGNORED_SECRET_TYPES.includes?(s["type"]) + VERBOSE_LOGGING.info "container: #{c_name} ignored secret: #{s_name}" if check_verbose(args) + next + end + VERBOSE_LOGGING.debug "checking secret: #{s_name}" if check_verbose(args) + found = (s_name == env.dig?("valueFrom", "secretKeyRef", "name")) + if found + VERBOSE_LOGGING.info "container: #{c_name} found secret reference: #{s_name}" if check_verbose(args) + end + found + end + end + end + end + + # Always pass if any workload resource in a cnf uses a (non-exempt) secret. + # If the workload resource does not use a (non-exempt) secret, always skip. + + test_passed = false + if secret_keyref_found_and_not_ignored || volume_test_passed + test_passed = true + end + + unless test_passed + puts "No Secret Volumes or Container secretKeyRefs found for resource: #{resource}".colorize(:yellow) + end + test_passed + end + if task_response + resp = upsert_passed_task("secrets_used","✔️ PASSED: Secrets defined and used #{emoji_probe}") + else + resp = upsert_skipped_task("secrets_used","⏭ #{secrets_used_skipped_msg(emoji_probe)}") + end + resp + end +end + +# https://www.cloudytuts.com/tutorials/kubernetes/how-to-create-immutable-configmaps-and-secrets/ +def configmap_template + <<-TEMPLATE + apiVersion: v1 + kind: ConfigMap + metadata: + name: myapp + immutable: true + data: + api.server: {{ test_url }} + TEMPLATE +end + +desc "Does the CNF use immutable configmaps?" +task "immutable_configmap" do |_, args| + task_response = CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "immutable_configmap" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + + # https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ + + # feature test to see if immutable_configmaps are enabled + # https://github.com/cncf/cnf-conformance/issues/508#issuecomment-758438413 + + test_config_map_filename = "#{destination_cnf_dir}/test_config_map.yml"; + + template = Crinja.render(configmap_template, { "test_url" => "doesnt_matter" }) + LOGGING.debug "test immutable_configmap template: #{template}" + test_config_map_create = `echo "#{template}" > "#{test_config_map_filename}"` + VERBOSE_LOGGING.debug "#{test_config_map_create}" if check_verbose(args) + + KubectlClient::Apply.file(test_config_map_filename) + + # now we change then apply again + + template = Crinja.render(configmap_template, { "test_url" => "doesnt_matter_again" }) + LOGGING.debug "test immutable_configmap change template: #{template}" + test_config_map_create = `echo "#{template}" > "#{test_config_map_filename}"` + VERBOSE_LOGGING.debug "test_config_map_create: #{test_config_map_create}" if check_verbose(args) + + immutable_configmap_supported = true + # if the reapply with a change succedes immmutable configmaps is NOT enabled + # if KubectlClient::Apply.file(test_config_map_filename) == 0 + if KubectlClient::Apply.file(test_config_map_filename) + LOGGING.info "kubectl apply failed for: #{test_config_map_filename}" + k8s_ver = KubectlClient.server_version + if version_less_than(k8s_ver, "1.19.0") + resp = "✖️ SKIPPED: immmutable configmaps are not supported in this k8s cluster.".colorize(:yellow) + upsert_skipped_task("immutable_configmap", resp) + immutable_configmap_supported = false + else + resp = "✖️ FAILED: immmutable configmaps are not enabled in this k8s cluster.".colorize(:red) + upsert_failed_task("immutable_configmap", resp) + end + end + + # cleanup test configmap + KubectlClient::Delete.file(test_config_map_filename) + + resp = "" + emoji_probe="⚖️" + cnf_manager_workload_resource_task_response = CNFManager.workload_resource_test(args, config, check_containers=false, check_service=true) do |resource, containers, volumes, initialized| + LOGGING.info "resource: #{resource}" + LOGGING.info "volumes: #{volumes}" + + config_maps_json = KubectlClient::Get.configmaps + + volume_test_passed = false + config_map_volume_exists = false + config_map_volume_mounted = true + all_volume_configmap_are_immutable = true + # Check to see all volume config maps are actually used + # https://kubernetes.io/docs/concepts/storage/volumes/#configmap + volumes.as_a.each do |config_map_volume| + if config_map_volume["configMap"]? + config_map_volume_exists = true + LOGGING.info "config_map_volume: #{config_map_volume["name"]}" + container_config_map_mounted = false + containers.as_a.each do |container| + if container["volumeMounts"]? + vmount = container["volumeMounts"].as_a + LOGGING.info "vmount: #{vmount}" + LOGGING.debug "container[env]: #{container["env"]? && container["env"]}" + if (vmount.find { |x| x["name"] == config_map_volume["name"]? }) + LOGGING.debug config_map_volume["name"] + container_config_map_mounted = true + end + end + end + # If any config_map volume exists, and it is not mounted by a + # container, fail test + if container_config_map_mounted == false + config_map_volume_mounted = false + end + + LOGGING.debug "config_maps_json[items][0]: #{config_maps_json["items"][0]}" + LOGGING.debug "config_map_volume[configMap] #{config_map_volume["configMap"]}" + + this_volume_config_map = config_maps_json["items"].as_a.find {|x| x["metadata"]? && x["metadata"]["name"]? && x["metadata"]["name"] == config_map_volume["configMap"]["name"] } + + LOGGING.debug "this_volume_config_map: #{this_volume_config_map}" + # https://crystal-lang.org/api/0.20.4/Hash.html#key%3F%28value%29-instance-method + unless config_map_volume_mounted && this_volume_config_map && this_volume_config_map["immutable"]? && this_volume_config_map["immutable"] == true + all_volume_configmap_are_immutable = false + end + end + end + + if config_map_volume_exists && config_map_volume_mounted && all_volume_configmap_are_immutable + volume_test_passed = true + end + + all_env_configmap_are_immutable = true + + containers.as_a.each do |container| + LOGGING.debug "container config_maps #{container["env"]?}" + if container["env"]? + container["env"].as_a.find do |c| + + # https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-container-environment-variables-with-data-from-multiple-configmaps + this_env_mounted_config_map_name = c.dig?("valueFrom", "configMapKeyRef", "name") + + this_env_mounted_config_map_json = config_maps_json["items"].as_a.find{ |s| s["metadata"]["name"] == this_env_mounted_config_map_name } + + LOGGING.debug "blarf this_env_mounted_config_map_json #{this_env_mounted_config_map_json}" + unless this_env_mounted_config_map_json && this_env_mounted_config_map_json["immutable"]? && this_env_mounted_config_map_json["immutable"] == true + all_env_configmap_are_immutable = false + end + end + end + end + + all_volume_configmap_are_immutable && all_env_configmap_are_immutable + end + + if cnf_manager_workload_resource_task_response + resp = "✔️ PASSED: All volume or container mounted configmaps immutable #{emoji_probe}".colorize(:green) + upsert_passed_task("immutable_configmap", resp) + elsif immutable_configmap_supported + resp = "✖️ FAILED: Found mutable configmap(s) #{emoji_probe}".colorize(:red) + upsert_failed_task("immutable_configmap", resp) + else + resp = "✖️ SKIPPED: Immutable configmap(s) not supported #{emoji_probe}".colorize(:yellow) + upsert_skipped_task("immutable_configmap", resp) + end + resp + end +end + +def secrets_used_skipped_msg(emoji) +<<-TEMPLATE +SKIPPED: Secrets not used #{emoji} + +To addresss this issue please see the USAGE.md documentation + +TEMPLATE +end diff --git a/src/tasks/hardware.cr b/src/tasks/workload/hardware.cr similarity index 72% rename from src/tasks/hardware.cr rename to src/tasks/workload/hardware.cr index ef5f6c253..cb1d02714 100644 --- a/src/tasks/hardware.cr +++ b/src/tasks/workload/hardware.cr @@ -2,10 +2,10 @@ require "sam" require "file_utils" require "colorize" require "totem" -require "./utils/utils.cr" +require "../utils/utils.cr" desc "The CNF container should access all hardware and schedule to specific worker nodes by using a device plugin." -task "hardware_affinity" do |_, args| +task "hardware_and_scheduling" do |_, args| end diff --git a/src/tasks/workload/installability.cr b/src/tasks/workload/installability.cr new file mode 100644 index 000000000..b6201dec1 --- /dev/null +++ b/src/tasks/workload/installability.cr @@ -0,0 +1,186 @@ +# coding: utf-8 +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "../utils/utils.cr" + +desc "The CNF conformance suite checks to see if CNFs support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines) by using the native K8s kubectl" +task "installability", ["install_script_helm", "helm_chart_valid", "helm_chart_published", "helm_deploy"] do |_, args| + stdout_score("installability") +end + +desc "Will the CNF install using helm with helm_deploy?" +task "helm_deploy" do |_, args| + unless check_destructive(args) + LOGGING.info "skipping helm_deploy: not in destructive mode" + puts "SKIPPED: Helm Deploy".colorize(:yellow) + next + end + LOGGING.info "Running helm_deploy in destructive mode!" + VERBOSE_LOGGING.info "helm_deploy" if check_verbose(args) + LOGGING.info("helm_deploy args: #{args.inspect}") + if check_cnf_config(args) || CNFManager.destination_cnfs_exist? + CNFManager::Task.task_runner(args) do |args, config| + begin + # TODO if manifest file and not helm, fail + # TODO helm should template the metadata.name attribute based on the helm release name + # TODO if we dont detect a templated metadata.name, use a namespace + # TODO do something if using rbac roles since they cant be namespaced + release_name_prefix = "helm-deploy-" + create_namespace = `kubectl create namespace helm-deploy` + + helm_chart = config.cnf_config[:helm_chart] + helm_directory = config.cnf_config[:helm_directory] + release_name = config.cnf_config[:release_name] + yml_file_path = config.cnf_config[:yml_file_path] + + current_dir = FileUtils.pwd + + helm = CNFSingleton.helm + VERBOSE_LOGGING.debug helm if check_verbose(args) + + if helm_chart.empty? + VERBOSE_LOGGING.debug "#{helm} install --namespace helm-deploy #{release_name_prefix}#{release_name} #{yml_file_path}/#{helm_directory}" if check_verbose(args) + helm_install = `#{helm} install --namespace helm-deploy #{release_name_prefix}#{release_name} #{yml_file_path}/#{helm_directory}` + else + VERBOSE_LOGGING.debug "#{helm} install --namespace helm-deploy #{release_name_prefix}#{release_name} #{helm_chart}" if check_verbose(args) + helm_install = `#{helm} install --namespace helm-deploy #{release_name_prefix}#{release_name} #{helm_chart}` + end + + is_helm_installed = $?.success? + VERBOSE_LOGGING.info helm_install if check_verbose(args) + + if is_helm_installed + upsert_passed_task("helm_deploy", "✔️ PASSED: Helm deploy successful") + else + upsert_failed_task("helm_deploy", "✖️ FAILED: Helm deploy failed") + end + ensure + VERBOSE_LOGGING.debug "#{helm} uninstall --namespace helm-deploy #{release_name_prefix}#{release_name}" if check_verbose(args) + helm_uninstall = `#{helm} uninstall --namespace helm-deploy #{release_name_prefix}#{release_name}` + delete_namespace = `kubectl delete namespace helm-deploy` + end + end + else + upsert_failed_task("helm_deploy", "✖️ FAILED: No cnf_conformance.yml found! Did you run the setup task?") + end +end + +desc "Does the install script use helm?" +task "install_script_helm" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + # config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + + found = 0 + # destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) + # install_script = config.get("install_script").as_s? + install_script = config.cnf_config[:install_script] + LOGGING.info "install_script: #{install_script}" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + LOGGING.info "destination_cnf_dir: #{destination_cnf_dir}" + VERBOSE_LOGGING.debug destination_cnf_dir if check_verbose(args) + if !install_script.empty? + response = String::Builder.new + content = File.open("#{destination_cnf_dir}/#{install_script}") do |file| + file.gets_to_end + end + # LOGGING.debug content + if /helm/ =~ content + found = 1 + end + if found < 1 + upsert_failed_task("install_script_helm", "✖️ FAILED: Helm not found in supplied install script") + else + upsert_passed_task("install_script_helm", "✔️ PASSED: Helm found in supplied install script") + end + else + upsert_passed_task("install_script_helm", "✔️ PASSED (by default): No install script provided") + end + end +end + +task "helm_chart_published", ["helm_local_install"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "helm_chart_published" if check_verbose(args) + VERBOSE_LOGGING.debug "helm_chart_published args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "helm_chart_published args.named: #{args.named}" if check_verbose(args) + + # config = cnf_conformance_yml + # config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + # helm_chart = "#{config.get("helm_chart").as_s?}" + helm_chart = config.cnf_config[:helm_chart] + + current_dir = FileUtils.pwd + helm = CNFSingleton.helm + VERBOSE_LOGGING.debug helm if check_verbose(args) + + if CNFManager.helm_repo_add(args: args) + unless helm_chart.empty? + helm_search = `#{helm} search repo #{helm_chart}` + LOGGING.info "helm search command: #{helm} search repo #{helm_chart}" + VERBOSE_LOGGING.debug "#{helm_search}" if check_verbose(args) + unless helm_search =~ /No results found/ + upsert_passed_task("helm_chart_published", "✔️ PASSED: Published Helm Chart Found") + else + upsert_failed_task("helm_chart_published", "✖️ FAILED: Published Helm Chart Not Found") + end + else + upsert_failed_task("helm_chart_published", "✖️ FAILED: Published Helm Chart Not Found") + end + else + upsert_failed_task("helm_chart_published", "✖️ FAILED: Published Helm Chart Not Found") + end + end +end + +task "helm_chart_valid", ["helm_local_install"] do |_, args| + CNFManager::Task.task_runner(args) do |args| + VERBOSE_LOGGING.info "helm_chart_valid" if check_verbose(args) + VERBOSE_LOGGING.debug "helm_chart_valid args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "helm_chart_valid args.named: #{args.named}" if check_verbose(args) + + response = String::Builder.new + + config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + # helm_directory = config.get("helm_directory").as_s + helm_directory = optional_key_as_string(config, "helm_directory") + if helm_directory.empty? + working_chart_directory = "exported_chart" + else + working_chart_directory = helm_directory + end + + if args.named.keys.includes? "cnf_chart_path" + working_chart_directory = args.named["cnf_chart_path"] + end + + VERBOSE_LOGGING.debug "working_chart_directory: #{working_chart_directory}" if check_verbose(args) + + current_dir = FileUtils.pwd + VERBOSE_LOGGING.debug current_dir if check_verbose(args) + helm = CNFSingleton.helm + + destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) + + helm_lint = `#{helm} lint #{destination_cnf_dir}/#{working_chart_directory}` + VERBOSE_LOGGING.debug "helm_lint: #{helm_lint}" if check_verbose(args) + + if $?.success? + upsert_passed_task("helm_chart_valid", "✔️ PASSED: Helm Chart #{working_chart_directory} Lint Passed") + else + upsert_failed_task("helm_chart_valid", "✖️ FAILED: Helm Chart #{working_chart_directory} Lint Failed") + end + end +end + +task "validate_config" do |_, args| + yml = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + valid, warning_output = CNFManager.validate_cnf_conformance_yml(yml) + emoji_config="📋" + if valid + stdout_success "✔️ PASSED: CNF configuration validated #{emoji_config}" + else + stdout_failure "❌ FAILED: Critical Error with CNF Configuration. Please review USAGE.md for steps to set up a valid CNF configuration file #{emoji_config}" + end +end diff --git a/src/tasks/workload/microservice.cr b/src/tasks/workload/microservice.cr new file mode 100644 index 000000000..e88e28a10 --- /dev/null +++ b/src/tasks/workload/microservice.cr @@ -0,0 +1,219 @@ +# coding: utf-8 +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "../utils/utils.cr" +require "../utils/docker_client.cr" +require "halite" +require "totem" + +desc "The CNF conformance suite checks to see if CNFs follows microservice principles" +task "microservice", ["reasonable_image_size", "reasonable_startup_time"] do |_, args| + stdout_score("microservice") +end + +desc "Does the CNF have a reasonable startup time (< 30 seconds)?" +task "reasonable_startup_time" do |_, args| + unless check_destructive(args) + upsert_skipped_task("reasonable_startup_time", "✖️ SKIPPED: skipping reasonable_startup_time: not in destructive mode") + next + end + LOGGING.info "Running reasonable_startup_time in destructive mode!" + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "reasonable_startup_time" if check_verbose(args) + LOGGING.debug "cnf_config: #{config.cnf_config}" + + yml_file_path = config.cnf_config[:yml_file_path] + helm_chart = config.cnf_config[:helm_chart] + helm_directory = config.cnf_config[:helm_directory] + release_name = config.cnf_config[:release_name] + install_method = config.cnf_config[:install_method] + + current_dir = FileUtils.pwd + helm = CNFSingleton.helm + VERBOSE_LOGGING.info helm if check_verbose(args) + + create_namespace = `kubectl create namespace startup-test` + helm_template_orig = "" + helm_template_test = "" + kubectl_apply = "" + is_kubectl_applied = "" + is_kubectl_deployed = "" + # TODO make this work with a manifest installation + elapsed_time = Time.measure do + LOGGING.info("reasonable_startup_time helm_chart.empty?: #{helm_chart.empty?}") + if install_method[0] == :helm_chart + # unless helm_chart.empty? #TODO make this work for a manifest + LOGGING.info("reasonable_startup_time #{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml") + LOGGING.info "helm_template_orig command: #{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml}" + helm_template_orig = `#{helm} template #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_orig.yml` + LOGGING.info("reasonable_startup_time #{helm} template --namespace=startup-test #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_test.yml") + helm_template_test = `#{helm} template --namespace=startup-test #{release_name} #{helm_chart} > #{yml_file_path}/reasonable_startup_test.yml` + VERBOSE_LOGGING.info "helm_chart: #{helm_chart}" if check_verbose(args) + elsif install_method[0] == :helm_directory + LOGGING.info("reasonable_startup_time #{helm} template #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_orig.yml") + helm_template_orig = `#{helm} template #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_orig.yml` + LOGGING.info("reasonable_startup_time #{helm} template --namespace=startup-test #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_test.yml") + helm_template_test = `#{helm} template --namespace=startup-test #{release_name} #{yml_file_path}/#{helm_directory} > #{yml_file_path}/reasonable_startup_test.yml` + VERBOSE_LOGGING.info "helm_directory: #{helm_directory}" if check_verbose(args) + else # manifest file installation not supported + puts "Manifest file not supported for reasonable startup time yet".colorize(:yellow) + raise "Manifest file not supported yet" + end + + # kubectl_apply = `kubectl apply -f #{yml_file_path}/reasonable_startup_test.yml --namespace=startup-test` + KubectlClient::Apply.file("#{yml_file_path}/reasonable_startup_test.yml --namespace=startup-test") + is_kubectl_applied = $?.success? + + template_ymls = Helm::Manifest.parse_manifest_as_ymls("#{yml_file_path}/reasonable_startup_test.yml") + + LOGGING.debug "template_ymls: #{template_ymls}" + task_response = template_ymls.map do |resource| + LOGGING.debug "Waiting on resource: #{resource["metadata"]["name"]} of type #{resource["kind"]}" + if resource["kind"].as_s.downcase == "deployment" || + resource["kind"].as_s.downcase == "pod" || + resource["kind"].as_s.downcase == "daemonset" || + resource["kind"].as_s.downcase == "statefulset" || + resource["kind"].as_s.downcase == "replicaset" + + KubectlClient::Get.resource_wait_for_install(resource["kind"].as_s, resource["metadata"]["name"].as_s, wait_count=180, "startup-test") + $?.success? + else + true + end + end + is_kubectl_deployed = task_response.none?{|x| x == false} + end + + VERBOSE_LOGGING.info helm_template_test if check_verbose(args) + VERBOSE_LOGGING.info kubectl_apply if check_verbose(args) + VERBOSE_LOGGING.info "installed? #{is_kubectl_applied}" if check_verbose(args) + VERBOSE_LOGGING.info "deployed? #{is_kubectl_deployed}" if check_verbose(args) + + emoji_fast="🚀" + emoji_slow="🐢" + startup_time_limit = 30 + if ENV["CRYSTAL_ENV"]? == "TEST" + startup_time_limit = 37 + LOGGING.info "startup_time_limit TEST mode: #{startup_time_limit}" + end + LOGGING.info "startup_time_limit: #{startup_time_limit}" + + if is_kubectl_applied && is_kubectl_deployed && elapsed_time.seconds < startup_time_limit + upsert_passed_task("reasonable_startup_time", "✔️ PASSED: CNF had a reasonable startup time #{emoji_fast}") + else + upsert_failed_task("reasonable_startup_time", "✖️ FAILED: CNF had a startup time of #{elapsed_time.seconds} seconds #{emoji_slow}") + end + + ensure + LOGGING.debug "Reasonable startup cleanup" + delete_namespace = `kubectl delete namespace startup-test --force --grace-period 0 2>&1 >/dev/null` + # rollback_non_namespaced = `kubectl apply -f #{yml_file_path}/reasonable_startup_orig.yml` + KubectlClient::Apply.file("#{yml_file_path}/reasonable_startup_orig.yml") + # KubectlClient::Get.wait_for_install(deployment_name, wait_count=180) + end +end + +desc "Does the CNF have a reasonable container image size (< 5GB)?" +task "reasonable_image_size", ["install_dockerd"] do |_, args| + unless check_dockerd + upsert_skipped_task("reasonable_image_size", "✖️ SKIPPED: Skipping reasonable_image_size: Dockerd tool failed to install") + next + end + CNFManager::Task.task_runner(args) do |args,config| + VERBOSE_LOGGING.info "reasonable_image_size" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + yml_file_path = config.cnf_config[:yml_file_path] + + if resource["kind"].as_s.downcase == "deployment" || + resource["kind"].as_s.downcase == "statefulset" || + resource["kind"].as_s.downcase == "pod" || + resource["kind"].as_s.downcase == "replicaset" + test_passed = true + + fqdn_image = container.as_h["image"].as_s + # parsed_image = DockerClient.parse_image(fqdn_image) + + image_pull_secrets = KubectlClient::Get.resource(resource[:kind], resource[:name]).dig?("spec", "template", "spec", "imagePullSecrets") + if image_pull_secrets + auths = image_pull_secrets.as_a.map { |secret| + puts secret["name"] + secret_data = KubectlClient::Get.resource("Secret", "#{secret["name"]}").dig?("data") + if secret_data + dockerconfigjson = Base64.decode_string("#{secret_data[".dockerconfigjson"]}") + dockerconfigjson.gsub(%({"auths":{),"")[0..-3] + # parsed_dockerconfigjson = JSON.parse(dockerconfigjson) + # parsed_dockerconfigjson["auths"].to_json.gsub("{","").gsub("}", "") + else + # JSON.parse(%({})) + "" + end + } + if auths + str_auths = %({"auths":{#{auths.reduce("") { | acc, x| + acc + x.to_s + "," + }[0..-2]}}}) + puts "str_auths: #{str_auths}" + end + File.write("#{yml_file_path}/config.json", str_auths) + KubectlClient.exec("dockerd -ti -- mkdir -p /root/.docker/") + KubectlClient.cp("#{yml_file_path}/config.json default/dockerd:/root/.docker/config.json") + end + + + KubectlClient.exec("dockerd -ti -- docker pull #{fqdn_image}") + KubectlClient.exec("dockerd -ti -- docker save #{fqdn_image} -o /tmp/image.tar") + KubectlClient.exec("dockerd -ti -- gzip -f /tmp/image.tar") + exec_resp = KubectlClient.exec("dockerd -ti -- wc -c /tmp/image.tar.gz | awk '{print$1}'") + compressed_size = exec_resp[:output] + # TODO strip out secret from under auths, save in array + # TODO make a new auths array, assign previous array into auths array + # TODO save auths array to a file + # dockerhub_image_tags = DockerClient::Get.image_tags(local_image_tag[:image]) + # if dockerhub_image_tags && dockerhub_image_tags.status_code == 200 + # image_by_tag = DockerClient::Get.image_by_tag(dockerhub_image_tags, local_image_tag[:tag]) + # micro_size = image_by_tag && image_by_tag["full_size"] + # else + # puts "Failed to find resource: #{resource} and container: #{local_image_tag[:image]}:#{local_image_tag[:tag]} on dockerhub".colorize(:yellow) + # test_passed=false + # end + LOGGING.info "compressed_size: #{fqdn_image} = '#{compressed_size.to_s}'" + max_size = 5_000_000_000 + if ENV["CRYSTAL_ENV"]? == "TEST" + LOGGING.info("Using Test Mode max_size") + max_size = 16_000_000 + end + + begin + unless compressed_size.to_s.to_i64 < max_size + puts "resource: #{resource} and container: #{fqdn_image} was more than #{max_size}".colorize(:red) + test_passed=false + end + rescue ex + LOGGING.error "invalid compressed_size: #{fqdn_image} = '#{compressed_size.to_s}', #{ex.message}".colorize(:red) + test_passed = false + end + else + test_passed = true + end + test_passed + end + + emoji_image_size="⚖️👀" + emoji_small="🐜" + emoji_big="🦖" + + if task_response + upsert_passed_task("reasonable_image_size", "✔️ PASSED: Image size is good #{emoji_small} #{emoji_image_size}") + else + upsert_failed_task("reasonable_image_size", "✖️ FAILED: Image size too large #{emoji_big} #{emoji_image_size}") + end + # ensure + # delete_dockerd = `kubectl delete -f #{TOOLS_DIR}/dockerd/manifest.yml` + end +end + + diff --git a/src/tasks/observability.cr b/src/tasks/workload/observability.cr similarity index 93% rename from src/tasks/observability.cr rename to src/tasks/workload/observability.cr index f3041cd44..61792423f 100644 --- a/src/tasks/observability.cr +++ b/src/tasks/workload/observability.cr @@ -2,7 +2,7 @@ require "sam" require "file_utils" require "colorize" require "totem" -require "./utils/utils.cr" +require "../utils/utils.cr" desc "In order to maintain, debug, and have insight into a protected environment, its infrastructure elements must have the property of being observable. This means these elements must externalize their internal states in some way that lends itself to metrics, tracing, and logging." task "observability" do |_, args| diff --git a/src/tasks/workload/resilience.cr b/src/tasks/workload/resilience.cr new file mode 100644 index 000000000..78fced800 --- /dev/null +++ b/src/tasks/workload/resilience.cr @@ -0,0 +1,417 @@ +# coding: utf-8 +require "sam" +require "colorize" +require "crinja" +require "../utils/utils.cr" + +desc "The CNF conformance suite checks to see if the CNFs are resilient to failures." +#task "resilience", ["chaos_network_loss", "chaos_cpu_hog", "chaos_container_kill" ] do |t, args| + task "resilience", ["pod_network_latency", "chaos_cpu_hog", "chaos_container_kill", "disk_fill"] do |t, args| + VERBOSE_LOGGING.info "resilience" if check_verbose(args) + VERBOSE_LOGGING.debug "resilience args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "resilience args.named: #{args.named}" if check_verbose(args) + stdout_score("resilience") +end + +desc "Does the CNF crash when network loss occurs" +task "chaos_network_loss", ["install_chaosmesh"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "chaos_network_loss" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + emoji_chaos_network_loss="📶☠️" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + if KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h? && + KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.size > 0 + test_passed = true + else + puts "No resource label found for container kill test for resource: #{resource}".colorize(:red) + test_passed = false + end + + if test_passed + template = Crinja.render(network_chaos_template, { "labels" => KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h }) + chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_network_loss.yml"` + VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) + run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_network_loss.yml"` + VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) + if ChaosMeshSetup.wait_for_test("NetworkChaos", "network-loss") + LOGGING.info( "Wait Done") + unless KubectlClient::Get.resource_desired_is_available?(resource["kind"].as_s, resource["name"].as_s) + test_passed = false + puts "Replicas did not return desired count after network chaos test for resource: #{resource["name"]}".colorize(:red) + end + else + # TODO Change this to an exception (points = 0) + # Add SKIPPED to points.yml and set to points = 0 + # e.g. upsert_exception_task + test_passed = false + puts "Chaosmesh failed to finish for resource: #{resource["name"]}".colorize(:red) + end + end + test_passed + end + if task_response + resp = upsert_passed_task("chaos_network_loss","✔️ PASSED: Replicas available match desired count after network chaos test #{emoji_chaos_network_loss}") + else + resp = upsert_failed_task("chaos_network_loss","✖️ FAILED: Replicas did not return desired count after network chaos test #{emoji_chaos_network_loss}") + end + ensure + delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_network_loss.yml"` + end +end + +desc "Does the CNF crash when CPU usage is high" +task "chaos_cpu_hog", ["install_chaosmesh"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "chaos_cpu_hog" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + emoji_chaos_cpu_hog="📦💻🐷📈" + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + if KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h? && KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.size > 0 + test_passed = true + else + puts "No resource label found for container kill test for resource: #{resource["name"]}".colorize(:red) + test_passed = false + end + if test_passed + template = Crinja.render(cpu_chaos_template, { "labels" => KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h }) + chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_cpu_hog.yml"` + VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) + run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_cpu_hog.yml"` + VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) + # TODO fail if exceeds + if ChaosMeshSetup.wait_for_test("StressChaos", "burn-cpu") + unless KubectlClient::Get.resource_desired_is_available?(resource["kind"].as_s, resource["name"].as_s) + test_passed = false + puts "Chaosmesh Application pod is not healthy after high CPU consumption for resource: #{resource["name"]}".colorize(:red) + end + else + # TODO Change this to an exception (points = 0) + # TODO Add SKIPPED to points.yml and set to points = 0 + # e.g. upsert_exception_task + test_passed = false + puts "Chaosmesh failed to finish for resource: #{resource["name"]}".colorize(:red) + end + end + test_passed + end + if task_response + resp = upsert_passed_task("chaos_cpu_hog","✔️ PASSED: Application pod is healthy after high CPU consumption #{emoji_chaos_cpu_hog}") + else + resp = upsert_failed_task("chaos_cpu_hog","✖️ FAILED: Application pod is not healthy after high CPU consumption #{emoji_chaos_cpu_hog}") + end + ensure + delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_cpu_hog.yml"` + end +end + +desc "Does the CNF recover when its container is killed" +task "chaos_container_kill", ["install_chaosmesh"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "chaos_container_kill" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + emoji_chaos_container_kill="🗡️💀♻️" + resource_names = [] of Hash(String, String) + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + if KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h? && + KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.size > 0 + test_passed = true + else + puts "No resource label found for container kill test for resource: #{resource}".colorize(:red) + test_passed = false + end + if test_passed + # TODO change helm_chart_container_name to container_name + template = Crinja.render(chaos_template_container_kill, { "labels" => KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h, "helm_chart_container_name" => "#{container.as_h["name"]}" }) + LOGGING.debug "chaos template: #{template}" + chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/chaos_container_kill.yml"` + VERBOSE_LOGGING.debug "#{chaos_config}" if check_verbose(args) + run_chaos = `kubectl create -f "#{destination_cnf_dir}/chaos_container_kill.yml"` + VERBOSE_LOGGING.debug "#{run_chaos}" if check_verbose(args) + if ChaosMeshSetup.wait_for_test("PodChaos", "container-kill") + KubectlClient::Get.resource_wait_for_install(resource["kind"].as_s, resource["name"].as_s, wait_count=60) + else + # TODO Change this to an exception (points = 0) + # TODO Add SKIPPED to points.yml and set to points = 0 + # e.g. upsert_exception_task + test_passed = false + puts "Chaosmesh chaos_container_kill failed to finish for resource: #{resource} and container: #{container.as_h["name"].as_s}".colorize(:red) + end + end + + resource_names << {"kind" => resource["kind"].as_s, + "name" => resource["name"].as_s} + test_passed + end + desired_passed = resource_names.map do |x| + if KubectlClient::Get.resource_desired_is_available?(x["kind"], x["name"]) + true + else + puts "Replicas did not return desired count after container kill test for resource: #{x}".colorize(:red) + false + end + end + if task_response && desired_passed.all? + resp = upsert_passed_task("chaos_container_kill","✔️ PASSED: Replicas available match desired count after container kill test #{emoji_chaos_container_kill}") + else + resp = upsert_failed_task("chaos_container_kill","✖️ FAILED: Replicas did not return desired count after container kill test #{emoji_chaos_container_kill}") + end + ensure + delete_chaos = `kubectl delete -f "#{destination_cnf_dir}/chaos_container_kill.yml"` + end +end + +desc "Does the CNF crash when network latency occurs" +task "pod_network_latency", ["install_litmus"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "pod_network_latency" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + # config = CNFManager.parsed_config_file(CNFManager.ensure_cnf_conformance_yml_path(args.named["cnf-config"].as(String))) + # destination_cnf_dir = CNFManager.cnf_destination_dir(CNFManager.ensure_cnf_conformance_dir(args.named["cnf-config"].as(String))) + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + # deployment_name = config.get("deployment_name").as_s + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + if KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h? && KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.size > 0 + test_passed = true + else + puts "No resource label found for pod_network_latency test for resource: #{resource["name"]}".colorize(:red) + test_passed = false + end + if test_passed + KubectlClient::Apply.file("https://hub.litmuschaos.io/api/chaos/1.13.2?file=charts/generic/pod-network-latency/experiment.yaml") + # install_experiment = `kubectl apply -f https://hub.litmuschaos.io/api/chaos/1.11.1?file=charts/generic/pod-network-latency/experiment.yaml` + KubectlClient::Apply.file("https://hub.litmuschaos.io/api/chaos/1.13.2?file=charts/generic/pod-network-latency/rbac.yaml") + # install_rbac = `kubectl apply -f https://hub.litmuschaos.io/api/chaos/1.11.1?file=charts/generic/pod-network-latency/rbac.yaml` + annotate = `kubectl annotate --overwrite deploy/#{resource["name"]} litmuschaos.io/chaos="true"` + # puts "#{install_experiment}" if check_verbose(args) + # puts "#{install_rbac}" if check_verbose(args) + # puts "#{annotate}" if check_verbose(args) + + chaos_experiment_name = "pod-network-latency" + test_name = "#{resource["name"]}-#{Random.rand(99)}" + chaos_result_name = "#{test_name}-#{chaos_experiment_name}" + + template = Crinja.render(chaos_template_pod_network_latency, {"chaos_experiment_name"=> "#{chaos_experiment_name}", "deployment_label" => "#{KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.first_key}", "deployment_label_value" => "#{KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.first_value}", "test_name" => test_name}) + chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/#{chaos_experiment_name}-chaosengine.yml"` + puts "#{chaos_config}" if check_verbose(args) + # run_chaos = `kubectl apply -f "#{destination_cnf_dir}/#{chaos_experiment_name}-chaosengine.yml"` + # puts "#{run_chaos}" if check_verbose(args) + KubectlClient::Apply.file("#{destination_cnf_dir}/#{chaos_experiment_name}-chaosengine.yml") + LitmusManager.wait_for_test(test_name,chaos_experiment_name,args) + LitmusManager.check_chaos_verdict(chaos_result_name,chaos_experiment_name,args) + end + test_passed + end + if task_response + resp = upsert_passed_task("pod_network_latency","✔️ PASSED: pod_network_latency chaos test passed 🗡️💀♻️") + else + resp = upsert_failed_task("pod_network_latency","✖️ FAILED: pod_network_latency chaos test failed 🗡️💀♻️") + end + resp + end +end + +desc "Does the CNF crash when disk fill occurs" +task "disk_fill", ["install_litmus"] do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "disk_fill" if check_verbose(args) + LOGGING.debug "cnf_config: #{config}" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + if KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h? && KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.size > 0 + test_passed = true + else + puts "No resource label found for disk_fill test for resource: #{resource["name"]}".colorize(:red) + test_passed = false + end + if test_passed + KubectlClient::Apply.file("https://hub.litmuschaos.io/api/chaos/1.13.2?file=charts/generic/disk-fill/experiment.yaml") + KubectlClient::Apply.file("https://hub.litmuschaos.io/api/chaos/1.13.2?file=charts/generic/disk-fill/rbac.yaml") + annotate = `kubectl annotate --overwrite deploy/#{resource["name"]} litmuschaos.io/chaos="true"` + + chaos_experiment_name = "disk-fill" + test_name = "#{resource["name"]}-#{Random.rand(99)}" + chaos_result_name = "#{test_name}-#{chaos_experiment_name}" + + template = Crinja.render(chaos_template_disk_fill, {"chaos_experiment_name"=> "#{chaos_experiment_name}", "deployment_label" => "#{KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.first_key}", "deployment_label_value" => "#{KubectlClient::Get.resource_spec_labels(resource["kind"], resource["name"]).as_h.first_value}", "test_name" => test_name}) + chaos_config = `echo "#{template}" > "#{destination_cnf_dir}/#{chaos_experiment_name}-chaosengine.yml"` + puts "#{chaos_config}" if check_verbose(args) + KubectlClient::Apply.file("#{destination_cnf_dir}/#{chaos_experiment_name}-chaosengine.yml") + LitmusManager.wait_for_test(test_name,chaos_experiment_name,args) + LitmusManager.check_chaos_verdict(chaos_result_name,chaos_experiment_name,args) + end + test_passed + end + if task_response + resp = upsert_passed_task("disk_fill","✔️ PASSED: disk_fill chaos test passed 🗡️💀♻️") + else + resp = upsert_failed_task("disk_fill","✖️ FAILED: disk_fill chaos test failed 🗡️💀♻️") + end + resp + end +end + + +def network_chaos_template + <<-TEMPLATE + apiVersion: pingcap.com/v1alpha1 + kind: NetworkChaos + metadata: + name: network-loss + namespace: default + spec: + action: loss + mode: one + selector: + labelSelectors: + {% for label in labels %} + '{{ label[0]}}': '{{ label[1] }}' + {% endfor %} + loss: + loss: '100' + correlation: '100' + duration: '40s' + scheduler: + cron: '@every 600s' + TEMPLATE +end + +def cpu_chaos_template + <<-TEMPLATE + apiVersion: pingcap.com/v1alpha1 + kind: StressChaos + metadata: + name: burn-cpu + namespace: default + spec: + mode: one + selector: + labelSelectors: + {% for label in labels %} + '{{ label[0]}}': '{{ label[1] }}' + {% endfor %} + stressors: + cpu: + workers: 1 + load: 100 + options: ['-c 0'] + duration: '40s' + scheduler: + cron: '@every 600s' + TEMPLATE +end + +def chaos_template_container_kill + <<-TEMPLATE + apiVersion: pingcap.com/v1alpha1 + kind: PodChaos + metadata: + name: container-kill + namespace: default + spec: + action: container-kill + mode: one + containerName: '{{ helm_chart_container_name }}' + selector: + labelSelectors: + {% for label in labels %} + '{{ label[0]}}': '{{ label[1] }}' + {% endfor %} + scheduler: + cron: '@every 600s' + TEMPLATE +end + +def chaos_template_pod_network_latency + <<-TEMPLATE + apiVersion: litmuschaos.io/v1alpha1 + kind: ChaosEngine + metadata: + name: {{ test_name }} + namespace: default + spec: + jobCleanUpPolicy: 'delete' + annotationCheck: 'true' + engineState: 'active' + auxiliaryAppInfo: '' + monitoring: false + appinfo: + appns: 'default' + applabel: '{{ deployment_label}}={{ deployment_label_value }}' + appkind: 'deployment' + chaosServiceAccount: {{ chaos_experiment_name }}-sa + experiments: + - name: {{ chaos_experiment_name }} + spec: + components: + env: + # If not provided it will take the first container of target pod + - name: TARGET_CONTAINER + value: '' + + - name: NETWORK_INTERFACE + value: 'eth0' + + - name: NETWORK_LATENCY + value: '60000' + + - name: TOTAL_CHAOS_DURATION + value: '60' # in seconds + + # provide the name of container runtime + # it supports docker, containerd, crio + # default to docker + - name: CONTAINER_RUNTIME + value: 'containerd' + + # provide the socket file path + # applicable only for containerd and crio runtime + - name: SOCKET_PATH + value: '/run/containerd/containerd.sock' + + TEMPLATE + end + + def chaos_template_disk_fill + <<-TEMPLATE + apiVersion: litmuschaos.io/v1alpha1 + kind: ChaosEngine + metadata: + name: {{ test_name }} + namespace: default + spec: + annotationCheck: 'true' + engineState: 'active' + auxiliaryAppInfo: '' + appinfo: + appns: 'default' + applabel: '{{ deployment_label}}={{ deployment_label_value }}' + appkind: 'deployment' + chaosServiceAccount: {{ chaos_experiment_name }}-sa + monitoring: false + jobCleanUpPolicy: 'delete' + experiments: + - name: {{ chaos_experiment_name }} + spec: + components: + env: + # specify the fill percentage according to the disk pressure required + - name: EPHEMERAL_STORAGE_MEBIBYTES + value: '500' + + - name: TARGET_CONTAINER + value: '' + + - name: FILL_PERCENTAGE + value: '' + + - name: CONTAINER_PATH + value: '/var/lib/containerd/io.containerd.grpc.v1.cri/containers/' + + TEMPLATE + end diff --git a/src/tasks/runtime.cr b/src/tasks/workload/runtime.cr similarity index 100% rename from src/tasks/runtime.cr rename to src/tasks/workload/runtime.cr diff --git a/src/tasks/workload/scalability.cr b/src/tasks/workload/scalability.cr new file mode 100644 index 000000000..35f8a81fd --- /dev/null +++ b/src/tasks/workload/scalability.cr @@ -0,0 +1,172 @@ +# coding: utf-8 +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "../utils/utils.cr" + +desc "The CNF conformance suite checks to see if CNFs support horizontal scaling (across multiple machines) and vertical scaling (between sizes of machines) by using the native K8s kubectl" +task "scalability", ["increase_decrease_capacity"] do |t, args| + VERBOSE_LOGGING.info "scalability" if check_verbose(args) + VERBOSE_LOGGING.debug "scaling args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "scaling args.named: #{args.named}" if check_verbose(args) + # t.invoke("increase_decrease_capacity", args) + stdout_score("scalability") +end + +desc "Test increasing/decreasing capacity" +task "increase_decrease_capacity", ["increase_capacity", "decrease_capacity"] do |t, args| + VERBOSE_LOGGING.info "increase_decrease_capacity" if check_verbose(args) +end + + +def increase_decrease_capacity_failure_msg(target_replicas, emoji) +<<-TEMPLATE +✖️ FAILURE: Replicas did not reach #{target_replicas} #{emoji} + +To addresss this issue please follow this link here + +https://github.com/cncf/cnf-conformance/blob/main/USAGE.md#heavy_check_mark-to-test-the-increasing-and-decreasing-of-capacity +TEMPLATE +end + +desc "Test increasing capacity by setting replicas to 1 and then increasing to 3" +task "increase_capacity" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "increase_capacity" if check_verbose(args) + emoji_increase_capacity="📦📈" + + target_replicas = "3" + base_replicas = "1" + # TODO scale replicatsets separately + # https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#scaling-a-replicaset + # resource["kind"].as_s.downcase == "replicaset" + task_response = CNFManager.cnf_workload_resources(args, config) do | resource| + if resource["kind"].as_s.downcase == "deployment" || + resource["kind"].as_s.downcase == "statefulset" + final_count = change_capacity(base_replicas, target_replicas, args, config, resource) + target_replicas == final_count + else + true + end + end + # if target_replicas == final_count + if task_response.none?(false) + upsert_passed_task("increase_capacity", "✔️ PASSED: Replicas increased to #{target_replicas} #{emoji_increase_capacity}") + else + upsert_failed_task("increase_capacity", increase_decrease_capacity_failure_msg(target_replicas, emoji_increase_capacity)) + end + end +end + +desc "Test decrease capacity by setting replicas to 3 and then decreasing to 1" +task "decrease_capacity" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "decrease_capacity" if check_verbose(args) + target_replicas = "1" + base_replicas = "3" + task_response = CNFManager.cnf_workload_resources(args, config) do | resource| + # TODO scale replicatsets separately + # https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#scaling-a-replicaset + # resource["kind"].as_s.downcase == "replicaset" + if resource["kind"].as_s.downcase == "deployment" || + resource["kind"].as_s.downcase == "statefulset" + final_count = change_capacity(base_replicas, target_replicas, args, config, resource) + target_replicas == final_count + else + true + end + end + emoji_decrease_capacity="📦📉" + + # if target_replicas == final_count + if task_response.none?(false) + upsert_passed_task("decrease_capacity", "✔️ PASSED: Replicas decreased to #{target_replicas} #{emoji_decrease_capacity}") + else + upsert_failed_task("decrease_capacity", increase_decrease_capacity_failure_msg(target_replicas, emoji_decrease_capacity)) + end + end +end + +def change_capacity(base_replicas, target_replica_count, args, config, resource = {kind: "", + metadata: {name: ""}}) + VERBOSE_LOGGING.info "change_capacity" if check_verbose(args) + VERBOSE_LOGGING.debug "increase_capacity args.raw: #{args.raw}" if check_verbose(args) + VERBOSE_LOGGING.debug "increase_capacity args.named: #{args.named}" if check_verbose(args) + VERBOSE_LOGGING.info "base replicas: #{base_replicas}" if check_verbose(args) + LOGGING.debug "resource: #{resource}" + + initialization_time = base_replicas.to_i * 10 + VERBOSE_LOGGING.info "resource: #{resource["metadata"]["name"]}" if check_verbose(args) + + #TODO make a KubectlClient.scale command + case resource["kind"].as_s.downcase + when "deployment" + LOGGING.debug "kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{base_replicas}" + + base = `kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{base_replicas}` + when "statefulset" + `kubectl scale statefulsets #{resource["metadata"]["name"]} --replicas=#{base_replicas}` + else #TODO what else can be scaled? + LOGGING.debug "kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{base_replicas}" + + base = `kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{base_replicas}` + end + VERBOSE_LOGGING.info "base: #{base}" if check_verbose(args) + initialized_count = wait_for_scaling(resource, base_replicas, args) + if initialized_count != base_replicas + VERBOSE_LOGGING.info "#{resource["kind"]} initialized to #{initialized_count} and could not be set to #{base_replicas}" if check_verbose(args) + else + VERBOSE_LOGGING.info "#{resource["kind"]} initialized to #{initialized_count}" if check_verbose(args) + end + + case resource["kind"].as_s.downcase + when "deployment" + increase = `kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{target_replica_count}` + when "statefulset" + `kubectl scale statefulsets #{resource["metadata"]["name"]} --replicas=#{target_replica_count}` + else #TODO what else can be scaled? + LOGGING.debug "kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{base_replicas}" + base = `kubectl scale #{resource["kind"]}.v1.apps/#{resource["metadata"]["name"]} --replicas=#{target_replica_count}` + end + + current_replicas = wait_for_scaling(resource, target_replica_count, args) + current_replicas +end + +def wait_for_scaling(resource, target_replica_count, args) + VERBOSE_LOGGING.info "target_replica_count: #{target_replica_count}" if check_verbose(args) + if args.named.keys.includes? "wait_count" + wait_count_value = args.named["wait_count"] + else + wait_count_value = "30" + end + wait_count = wait_count_value.to_i + second_count = 0 + current_replicas = "0" + previous_replicas = `kubectl get #{resource["kind"]} #{resource["metadata"]["name"]} -o=jsonpath='{.status.readyReplicas}'` + until current_replicas == target_replica_count || second_count > wait_count + VERBOSE_LOGGING.debug "secound_count: #{second_count} wait_count: #{wait_count}" if check_verbose(args) + VERBOSE_LOGGING.info "current_replicas before get #{resource["kind"]}: #{current_replicas}" if check_verbose(args) + sleep 1 + VERBOSE_LOGGING.debug `echo $KUBECONFIG` if check_verbose(args) + VERBOSE_LOGGING.info "Get #{resource["kind"]} command: kubectl get #{resource["kind"]} #{resource["metadata"]["name"]} -o=jsonpath='{.status.readyReplicas}'" if check_verbose(args) + current_replicas = `kubectl get #{resource["kind"]} #{resource["metadata"]["name"]} -o=jsonpath='{.status.readyReplicas}'` + VERBOSE_LOGGING.info "current_replicas after get #{resource["kind"]}: #{current_replicas.inspect}" if check_verbose(args) + + if current_replicas.empty? + current_replicas = "0" + previous_replicas = "0" + end + + if current_replicas.to_i != previous_replicas.to_i + second_count = 0 + previous_replicas = current_replicas + end + second_count = second_count + 1 + VERBOSE_LOGGING.info "previous_replicas: #{previous_replicas}" if check_verbose(args) + VERBOSE_LOGGING.info "current_replicas: #{current_replicas}" if check_verbose(args) + end + current_replicas +end + diff --git a/src/tasks/workload/security.cr b/src/tasks/workload/security.cr new file mode 100644 index 000000000..23fc67202 --- /dev/null +++ b/src/tasks/workload/security.cr @@ -0,0 +1,41 @@ +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "../utils/utils.cr" + +desc "CNF containers should be isolated from one another and the host. The CNF Conformance suite uses tools like Falco, Sysdig Inspect and gVisor" +task "security", ["privileged"] do |_, args| + stdout_score("security") +end + +desc "Check if any containers are running in privileged mode" +task "privileged" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "privileged" if check_verbose(args) + white_list_container_names = config.cnf_config[:white_list_container_names] + VERBOSE_LOGGING.info "white_list_container_names #{white_list_container_names.inspect}" if check_verbose(args) + violation_list = [] of String + task_response = CNFManager.workload_resource_test(args, config) do |resource, container, initialized| + + privileged_list = KubectlClient::Get.privileged_containers + white_list_containers = ((PRIVILEGED_WHITELIST_CONTAINERS + white_list_container_names) - [container]) + # Only check the containers that are in the deployed helm chart or manifest + (privileged_list & ([container.as_h["name"].as_s] - white_list_containers)).each do |x| + violation_list << x + end + if violation_list.size > 0 + false + else + true + end + end + LOGGING.debug "violator list: #{violation_list.flatten}" + emoji_security="🔓🔑" + if task_response + upsert_passed_task("privileged", "✔️ PASSED: No privileged containers #{emoji_security}") + else + upsert_failed_task("privileged", "✖️ FAILED: Found #{violation_list.size} privileged containers: #{violation_list.inspect} #{emoji_security}") + end + end +end diff --git a/src/tasks/workload/statelessness.cr b/src/tasks/workload/statelessness.cr new file mode 100644 index 000000000..cf5445859 --- /dev/null +++ b/src/tasks/workload/statelessness.cr @@ -0,0 +1,114 @@ +# coding: utf-8 +require "sam" +require "file_utils" +require "colorize" +require "totem" +require "../utils/utils.cr" +require "../utils/kubectl_client.cr" + +desc "The CNF conformance suite checks if state is stored in a custom resource definition or a separate database (e.g. etcd) rather than requiring local storage. It also checks to see if state is resilient to node failure" +task "statelessness", ["volume_hostpath_not_found"] do |_, args| + stdout_score("statelessness") +end + +desc "Does the CNF use a non-cloud native data store: hostPath volume" +task "volume_hostpath_not_found" do |_, args| + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "volume_hostpath_not_found" if check_verbose(args) + failed_emoji = "(ভ_ভ) ރ 💾" + passed_emoji = "🖥️ 💾" + LOGGING.debug "cnf_config: #{config}" + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + task_response = CNFManager.cnf_workload_resources(args, config) do | resource| + hostPath_found = nil + begin + # TODO check to see if volume is actually mounted. Check to see if mount (without volume) has host path as well + volumes = resource.dig?("spec", "template", "spec", "volumes") + if volumes + hostPath_not_found = volumes.as_a.none? do |volume| + if volume.as_h["hostPath"]? + true + end + end + else + hostPath_not_found = true + end + rescue ex + VERBOSE_LOGGING.error ex.message if check_verbose(args) + puts "Rescued: On resource #{resource["metadata"]["name"]?} of kind #{resource["kind"]}, volumes not found. #{passed_emoji}".colorize(:yellow) + hostPath_not_found = true + end + hostPath_not_found + end + + if task_response.any?(false) + upsert_failed_task("volume_hostpath_not_found","✖️ FAILED: hostPath volumes found #{failed_emoji}") + else + upsert_passed_task("volume_hostpath_not_found","✔️ PASSED: hostPath volumes not found #{passed_emoji}") + end + end +end + +desc "Does the CNF use a non-cloud native data store: local volumes on the node?" +task "no_local_volume_configuration" do |_, args| + failed_emoji = "(ভ_ভ) ރ 💾" + passed_emoji = "🖥️ 💾" + CNFManager::Task.task_runner(args) do |args, config| + VERBOSE_LOGGING.info "no_local_volume_configuration" if check_verbose(args) + + destination_cnf_dir = config.cnf_config[:destination_cnf_dir] + task_response = CNFManager.cnf_workload_resources(args, config) do | resource| + hostPath_found = nil + begin + # Note: A storageClassName value of "local-storage" is insufficient to determine if the + # persistent volume is indeed local storage. This is because the storageClass can be redefined + # to be anything (e.g. the name local-storage can be redefined to be block storage behind the scenes) + + volumes = [] of YAML::Any + if resource["spec"].as_h["template"].as_h["spec"].as_h["volumes"]? + volumes = resource["spec"].as_h["template"].as_h["spec"].as_h["volumes"].as_a + end + LOGGING.debug "volumes: #{volumes}" + persistent_volume_claim_names = volumes.map do |volume| + # get persistent volume claim that matches persistent volume claim name + if volume.as_h["persistentVolumeClaim"]? && volume.as_h["persistentVolumeClaim"].as_h["claimName"]? + volume.as_h["persistentVolumeClaim"].as_h["claimName"] + else + nil + end + end.compact + LOGGING.debug "persistent volume claim names: #{persistent_volume_claim_names}" + + # TODO (optional) check storage class of persistent volume claim + # loop through all pvc names + # get persistent volume that matches pvc name + # get all items, get spec, get claimRef, get pvc name that matches pvc name + local_storage_not_found = true + persistent_volume_claim_names.map do | claim_name| + items = KubectlClient::Get.pv_items_by_claim_name(claim_name) + items.map do |item| + begin + if item["spec"]["local"]? && item["spec"]["local"]["path"]? + local_storage_not_found = false + end + rescue ex + LOGGING.info ex.message + local_storage_not_found = true + end + end + end + rescue ex + VERBOSE_LOGGING.error ex.message if check_verbose(args) + puts "Rescued: On resource #{resource["metadata"]["name"]?} of kind #{resource["kind"]}, local storage configuration volumes not found #{passed_emoji}".colorize(:yellow) + local_storage_not_found = true + end + local_storage_not_found + end + + if task_response.any?(false) + upsert_failed_task("no_local_volume_configuration","✖️ FAILED: local storage configuration volumes found #{failed_emoji}") + else + upsert_passed_task("no_local_volume_configuration","✔️ PASSED: local storage configuration volumes not found #{passed_emoji}") + end + end +end diff --git a/tools/curl_install_tester_docker_setup/Dockerfile b/tools/curl_install_tester_docker_setup/Dockerfile index a665c25be..e408598cf 100644 --- a/tools/curl_install_tester_docker_setup/Dockerfile +++ b/tools/curl_install_tester_docker_setup/Dockerfile @@ -8,7 +8,7 @@ RUN apt update && apt install -y wget curl git RUN curl -L https://get.helm.sh/${FILENAME} | tar zxv -C /tmp RUN mv /tmp/linux-amd64/helm /usr/local/bin/ -RUN helm repo add stable https://kubernetes-charts.storage.googleapis.com +RUN helm repo add stable https://charts.helm.sh/stable RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL/bin/linux/amd64/kubectl RUN mv ./kubectl /usr/local/bin/kubectl diff --git a/tools/dockerd/manifest.yml b/tools/dockerd/manifest.yml new file mode 100644 index 000000000..6db0c8cdf --- /dev/null +++ b/tools/dockerd/manifest.yml @@ -0,0 +1,39 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: docker-config +data: + config.yaml: | + { + "insecure-registries" : ["registry:5000"] + } +--- +apiVersion: v1 +kind: Pod +metadata: + name: dockerd +spec: + containers: + - name: dockerd + image: docker:dind + volumeMounts: + - name: config-volume + mountPath: /etc/docker/daemon.json + subPath: config.yaml + livenessProbe: + tcpSocket: + port: 2376 + initialDelaySeconds: 3 + periodSeconds: 3 + readinessProbe: + tcpSocket: + port: 2376 + initialDelaySeconds: 3 + periodSeconds: 3 + securityContext: + privileged: true + volumes: + - name: config-volume + configMap: + name: docker-config diff --git a/tools/ephemeral_env/Dockerfile b/tools/ephemeral_env/Dockerfile index 546fd360f..3dba68c6f 100644 --- a/tools/ephemeral_env/Dockerfile +++ b/tools/ephemeral_env/Dockerfile @@ -8,7 +8,7 @@ RUN apt update && apt install -y wget curl RUN curl -L https://get.helm.sh/${FILENAME} | tar zxv -C /tmp RUN mv /tmp/linux-amd64/helm /usr/local/bin/ -RUN helm repo add stable https://kubernetes-charts.storage.googleapis.com +RUN helm repo add stable https://charts.helm.sh/stable RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL/bin/linux/amd64/kubectl RUN mv ./kubectl /usr/local/bin/kubectl diff --git a/tools/registry/manifest.yml b/tools/registry/manifest.yml new file mode 100644 index 000000000..0072dd735 --- /dev/null +++ b/tools/registry/manifest.yml @@ -0,0 +1,36 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: registry +spec: + selector: + app: registry + ports: + - protocol: TCP + port: 5000 + targetPort: 5000 +--- +apiVersion: v1 +kind: Pod +metadata: + name: registry + labels: + app: registry +spec: + hostNetwork: true + containers: + - name: registry + image: registry:latest + ports: + - containerPort: 5000 + livenessProbe: + tcpSocket: + port: 5000 + initialDelaySeconds: 3 + periodSeconds: 3 + readinessProbe: + tcpSocket: + port: 5000 + initialDelaySeconds: 3 + periodSeconds: 3 diff --git a/cnfs/.gitkeep b/trigger_ci similarity index 100% rename from cnfs/.gitkeep rename to trigger_ci