├── .github ├── generate-reports.sh └── workflows │ ├── ci.yml │ ├── e2e-test.yml │ └── helm.yaml ├── .gitignore ├── .licenserc.yaml ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README-CN.md ├── README.md ├── SECURITY.md ├── VERSION ├── build └── build.sh ├── charts └── bfe-ingress-controller │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── hpa.yaml │ ├── rbac.yaml │ ├── service.yaml │ └── serviceaccount.yaml │ └── values.yaml ├── cmd └── ingress-controller │ ├── flags.go │ └── main.go ├── dist ├── bfe.ini └── start.sh ├── docs ├── en_us │ ├── FAQ │ │ └── FAQ.md │ ├── README.md │ ├── SUMMARY.md │ ├── appendix │ │ └── annotations.md │ ├── contribute │ │ ├── contribute-codes.md │ │ ├── contribute-documents.md │ │ └── how-to-contribute.md │ ├── deployment.md │ ├── example │ │ ├── canary-release.md │ │ └── example.md │ ├── ingress │ │ ├── basic.md │ │ ├── conflict.md │ │ ├── load-balance.md │ │ ├── priority.md │ │ ├── redirect.md │ │ ├── rewrite.md │ │ ├── tls.md │ │ └── validate-state.md │ └── rbac.md ├── images │ ├── arch.jpg │ └── qrcode_for_gh.jpg └── zh_cn │ ├── FAQ │ └── FAQ.md │ ├── README.md │ ├── SUMMARY.md │ ├── appendix │ └── annotations.md │ ├── contribute │ ├── contribute-codes.md │ ├── contribute-documents.md │ └── how-to-contribute.md │ ├── deployment.md │ ├── development │ ├── annotation-implement-guide.md │ ├── core-logic.md │ └── source-code-layout.md │ ├── example │ ├── canary-release.md │ ├── example.md │ └── example.md.orig │ ├── ingress │ ├── basic.md │ ├── conflict.md │ ├── load-balance.md │ ├── priority.md │ ├── redirect.md │ ├── rewrite.md │ ├── tls.md │ └── validate-state.md │ └── rbac.md ├── examples ├── controller-all.yaml ├── controller.yaml ├── ingress-v1.19.yaml ├── ingress.yaml ├── rbac.yaml └── whoami.yaml ├── go.mod ├── go.sum ├── internal ├── bfeConfig │ ├── annotations │ │ ├── annotation.go │ │ ├── balance.go │ │ ├── balance_test.go │ │ ├── priority.go │ │ ├── redirect.go │ │ ├── rewrite.go │ │ ├── rewrite_test.go │ │ ├── router.go │ │ ├── router_test.go │ │ └── status.go │ ├── configBuilder.go │ ├── configs │ │ ├── TLSConfig.go │ │ ├── cache │ │ │ ├── baseCache.go │ │ │ ├── baseRule.go │ │ │ └── rule.go │ │ ├── clusterConfig.go │ │ ├── log │ │ │ └── log.go │ │ ├── modules │ │ │ ├── module.go │ │ │ ├── redirect │ │ │ │ ├── cache.go │ │ │ │ └── redirect.go │ │ │ └── rewrite │ │ │ │ ├── cache.go │ │ │ │ └── rewrite.go │ │ ├── routeRuleCache.go │ │ ├── routeRuleCache_test.go │ │ └── serverDataConfig.go │ └── util │ │ ├── io.go │ │ ├── name.go │ │ └── version.go ├── controllers │ ├── event │ │ └── events.go │ ├── filter │ │ ├── ingressClass.go │ │ ├── ingressClass_test.go │ │ └── namespace.go │ ├── ingress │ │ ├── extv1beta1 │ │ │ └── ingress_controller.go │ │ ├── netv1 │ │ │ └── ingress_controller.go │ │ ├── netv1beta1 │ │ │ └── ingress_controller.go │ │ ├── secret_controller.go │ │ └── service_controller.go │ └── start.go └── option │ ├── ingress │ └── options.go │ └── options.go ├── scripts └── start.sh └── test ├── e2e ├── Dockerfile ├── Makefile ├── README.md ├── e2e_test.go ├── features │ ├── annotations │ │ ├── balance │ │ │ └── load_balance.feature │ │ ├── redirect │ │ │ └── redirect.feature │ │ ├── rewrite │ │ │ └── rewrite.feature │ │ └── route │ │ │ ├── cookie.feature │ │ │ ├── header.feature │ │ │ └── priority.feature │ ├── conformance │ │ ├── default_backend.feature │ │ ├── host_rules.feature │ │ ├── ingress_class.feature │ │ ├── load_balancing.feature │ │ └── path_rules.feature │ └── rules │ │ ├── host_rule1.feature │ │ ├── host_rule2.feature │ │ ├── multiple_ingress.feature │ │ ├── path_err.feature │ │ ├── path_rule1.feature │ │ └── path_rule2.feature ├── go.mod ├── go.sum ├── hack │ ├── boilerplate │ │ ├── boilerplate.go.txt │ │ ├── boilerplate.py │ │ ├── boilerplate.py.txt │ │ └── boilerplate.sh.txt │ ├── check-go-version.sh │ ├── codegen.go │ ├── codegen.tmpl │ ├── kube-env.sh │ ├── verify-all.sh │ ├── verify-boilerplate.sh │ ├── verify-gherkin.sh │ ├── verify-gofmt.sh │ └── verify-golint.sh ├── images │ ├── echoserver │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── echoserver │ │ └── echoserver.go │ └── reports │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── README.md │ │ └── src │ │ ├── .gitignore │ │ ├── cucumber-html-reporter │ │ ├── .eslintrc.yml │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.MD │ │ ├── lib │ │ │ ├── collect-jsons.js │ │ │ ├── generate-report.js │ │ │ ├── parse.cucumber.data.js │ │ │ └── utils.js │ │ ├── package.json │ │ └── templates │ │ │ ├── components │ │ │ ├── features-overview.chart.ejs │ │ │ ├── features-overview.ejs │ │ │ ├── scenarios-overview.chart.ejs │ │ │ └── scenarios.ejs │ │ │ ├── feature-overview.index.ejs │ │ │ ├── features-overview.index.ejs │ │ │ ├── generic.js │ │ │ └── style.css │ │ ├── index.js │ │ └── package.json ├── pkg │ ├── files │ │ └── files.go │ ├── http │ │ └── http.go │ ├── kubernetes │ │ ├── deployment.go │ │ ├── kubernetes.go │ │ └── templates │ │ │ └── templates.go │ └── state │ │ └── state.go ├── run.sh └── steps │ ├── annotations │ ├── balance │ │ └── loadbalance │ │ │ └── steps.go │ ├── redirect │ │ └── steps.go │ ├── rewrite │ │ └── steps.go │ └── route │ │ ├── cookie │ │ └── steps.go │ │ ├── header │ │ └── steps.go │ │ └── priority │ │ └── steps.go │ ├── conformance │ ├── defaultbackend │ │ └── steps.go │ ├── hostrules │ │ └── steps.go │ ├── ingressclass │ │ └── steps.go │ ├── loadbalancing │ │ └── steps.go │ └── pathrules │ │ └── steps.go │ └── rules │ ├── host1 │ └── steps.go │ ├── host2 │ └── steps.go │ ├── multipleingress │ └── steps.go │ ├── path1 │ └── steps.go │ ├── path2 │ └── steps.go │ └── patherr │ └── steps.go └── script ├── controller-svc.yaml ├── deploy-controller.sh ├── ingressclass.yaml ├── kind-config.yaml ├── kind-create-cluster.sh ├── kind-delete-cluster.sh └── kind-load-images.sh /.github/generate-reports.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2020 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | set -x 21 | 22 | (cd "$(dirname "$0")/../test/e2e/images/reports" && make build-image) 23 | 24 | REPORT_BUILDER_IMAGE=local/reports-builder:0.0.1 25 | 26 | REPORTS_DIR=${REPORTS_DIR:-/tmp/bfe-ingress-reports} 27 | 28 | INGRESS_CONTROLLER="BFE-ingress-controller" 29 | CONTROLLER_VERSION=${CONTROLLER_VERSION:-'N/A'} 30 | 31 | TEMP_CONTENT=$(mktemp -d) 32 | 33 | docker run \ 34 | -e BUILD="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ 35 | -e INPUT_DIRECTORY=/input \ 36 | -e OUTPUT_DIRECTORY=/output \ 37 | -e INGRESS_CONTROLLER="${INGRESS_CONTROLLER}" \ 38 | -e CONTROLLER_VERSION="${CONTROLLER_VERSION}" \ 39 | -v "${REPORTS_DIR}":/input:ro \ 40 | -v "${TEMP_CONTENT}":/output \ 41 | -u "$(id -u):$(id -g)" \ 42 | "${REPORT_BUILDER_IMAGE}" 43 | 44 | pushd "${TEMP_WORKTREE}" > /dev/null 45 | 46 | if [[ -d ./e2e-test ]]; then 47 | git rm -r ./e2e-test 48 | else 49 | mkdir -p "${TEMP_WORKTREE}/e2e-test" 50 | fi 51 | 52 | # copy new content 53 | cp -r -a "${TEMP_CONTENT}/." "${TEMP_WORKTREE}/e2e-test/" 54 | 55 | # cleanup HTML 56 | sudo apt-get install tidy 57 | for html_file in e2e-test/*.html;do 58 | tidy -q --break-before-br no --tidy-mark no --show-warnings no --wrap 0 -indent -m "$html_file" || true 59 | done 60 | 61 | # configure git 62 | git config --global user.email "action@github.com" 63 | git config --global user.name "GitHub Action" 64 | # commit changes 65 | git add e2e-test 66 | git commit -m "e2e test report" 67 | git push --force --quiet 68 | 69 | popd > /dev/null 70 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # This is a basic workflow to help you get started with Actions 16 | 17 | name: CI 18 | 19 | # Controls when the action will run. Triggers the workflow on push or pull request 20 | # events but only for the master branch 21 | on: 22 | push: 23 | branches: [ develop ] 24 | pull_request: 25 | branches: [ develop ] 26 | 27 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 28 | jobs: 29 | # This workflow contains a single job called "ci" 30 | ci: 31 | # The type of runner that the job will run on 32 | runs-on: ubuntu-latest 33 | 34 | # Steps represent a sequence of tasks that will be executed as part of the job 35 | steps: 36 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | with: 40 | # Must fetch at least the immediate parents so that if this is 41 | # a pull request then we can checkout the head of the pull request. 42 | # Only include this option if you are running this workflow on pull requests. 43 | fetch-depth: 2 44 | 45 | # If this run was triggered by a pull request event then checkout 46 | # the head of the pull request instead of the merge commit. 47 | # Only include this step if you are running this workflow on pull requests. 48 | - run: git checkout HEAD^2 49 | if: ${{ github.event_name == 'pull_request' }} 50 | 51 | # Build 52 | - name: Build 53 | shell: bash 54 | run: | 55 | make 56 | -------------------------------------------------------------------------------- /.github/workflows/e2e-test.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # This is a basic workflow to help you get started with Actions 16 | 17 | name: e2e-test 18 | 19 | # Controls when the action will run. Triggers the workflow on push or pull request 20 | # events but only for the master branch 21 | on: 22 | push: 23 | branches: [ main, develop ] 24 | pull_request: 25 | branches: [ develop ] 26 | 27 | permissions: 28 | actions: read 29 | checks: read 30 | contents: write 31 | deployments: read 32 | discussions: read 33 | issues: read 34 | pages: read 35 | packages: read 36 | pull-requests: write 37 | repository-projects: read 38 | security-events: read 39 | statuses: read 40 | 41 | jobs: 42 | e2e-test: 43 | runs-on: ubuntu-latest 44 | environment: e2e 45 | 46 | env: 47 | CUCUMBER_FEATURE: ${{ secrets.CUCUMBER_FEATURE }} 48 | WAIT_FOR_STATUS_TIMEOUT: ${{ secrets.WAIT_FOR_STATUS_TIMEOUT }} 49 | TEST_TIMEOUT: ${{ secrets.TEST_TIMEOUT }} 50 | 51 | steps: 52 | - name: Checkout 53 | uses: actions/checkout@v2 54 | 55 | - uses: dorny/paths-filter@v2 56 | id: filter 57 | with: 58 | token: ${{ secrets.GITHUB_TOKEN }} 59 | filters: | 60 | go: 61 | - '**/*.go' 62 | - 'go.mod' 63 | - 'go.sum' 64 | - 'Makefile' 65 | - 'Dockerfile' 66 | - 'test/**/*' 67 | 68 | - name: Run e2e test 69 | id: run-e2e-test 70 | continue-on-error: true 71 | shell: bash 72 | if: steps.filter.outputs.go == 'true' 73 | run: | 74 | export RESULTS_DIR=/tmp/bfe-ingress-reports 75 | export CUCUMBER_OUTPUT_FORMAT=cucumber 76 | make e2e-test 77 | 78 | - name: Generate reports 79 | continue-on-error: true 80 | if: steps.filter.outputs.go == 'true' 81 | run: | 82 | # clone the gh-pages repository branch 83 | export TEMP_WORKTREE=$(mktemp -d) 84 | remote_repo="https://${GITHUB_ACTOR}:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git" 85 | git clone --branch=gh-pages --depth=1 "${remote_repo}" "${TEMP_WORKTREE}" 86 | 87 | export REPORTS_DIR=/tmp/bfe-ingress-reports 88 | export CONTROLLER_VERSION=$(cat VERSION) 89 | .github/generate-reports.sh 90 | 91 | - name: Upload cucumber json files 92 | uses: actions/upload-artifact@v2 93 | continue-on-error: true 94 | with: 95 | name: cucumber-output 96 | path: /tmp/bfe-ingress-reports/* 97 | 98 | - name: Check on failures 99 | if: steps.filter.outputs.go == 'true' && steps.run-e2e-test.outcome != 'success' 100 | run: exit 1 101 | 102 | -------------------------------------------------------------------------------- /.github/workflows/helm.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | name: Helm 16 | 17 | on: 18 | push: 19 | branches: 20 | - main 21 | 22 | jobs: 23 | 24 | changes: 25 | runs-on: ubuntu-latest 26 | if: | 27 | (github.repository == 'bfenetworks/ingress-bfe') 28 | outputs: 29 | charts: ${{ steps.filter.outputs.charts }} 30 | 31 | steps: 32 | 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | 36 | - uses: dorny/paths-filter@v2 37 | id: filter 38 | with: 39 | token: ${{ secrets.GITHUB_TOKEN }} 40 | filters: | 41 | charts: 42 | - 'charts/bfe-ingress-controller/Chart.yaml' 43 | - 'charts/bfe-ingress-controller/**/*' 44 | 45 | chart: 46 | name: Release Chart 47 | runs-on: ubuntu-latest 48 | needs: 49 | - changes 50 | if: | 51 | (github.repository == 'bfenetworks/ingress-bfe') && 52 | (needs.changes.outputs.charts == 'true') 53 | 54 | steps: 55 | 56 | - name: Checkout 57 | uses: actions/checkout@v2 58 | with: 59 | fetch-depth: 0 60 | 61 | - name: Configure Git 62 | shell: bash 63 | run: | 64 | git config --global user.name "$GITHUB_ACTOR" 65 | git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" 66 | 67 | - name: Run chart-releaser 68 | uses: helm/chart-releaser-action@v1.1.0 69 | env: 70 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 71 | CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}" 72 | with: 73 | charts_dir: charts 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Binaries for programs and plugins 16 | *.exe 17 | *.exe~ 18 | *.dll 19 | *.so 20 | *.dylib 21 | 22 | # Test binary, built with `go test -c` 23 | *.test 24 | 25 | # Output of the go coverage tool, specifically when used with LiteIDE 26 | *.out 27 | 28 | # Dependency directories (remove the comment below to include it) 29 | # vendor/ 30 | 31 | # MacOS files 32 | .DS_Store 33 | */.DS_Store 34 | 35 | # .idea 36 | .idea -------------------------------------------------------------------------------- /.licenserc.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 The BFE Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | header: 16 | license: 17 | spdx-id: Apache-2.0 18 | copyright-owner: The BFE Authors 19 | 20 | paths-ignore: 21 | - '.idea' 22 | - 'conf' 23 | - 'docs/images' 24 | - '**/go.mod' 25 | - '**/go.sum' 26 | - '**/*.md' 27 | - '**/*.orig' 28 | - 'examples/*' 29 | - 'LICENSE' 30 | - 'VERSION' 31 | - 'test/e2e/*' 32 | 33 | comment: on-failure 34 | 35 | dependency: 36 | files: 37 | - go.mod 38 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | repos: 16 | - repo: git://github.com/dnephin/pre-commit-golang 17 | rev: v0.4.0 18 | hooks: 19 | - id: go-fmt -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## v0.3.0 (2021-03-12) 6 | 7 | ### Enhancements: 8 | - Record k8s event for status change. [#47](https://github.com/bfenetworks/ingress-bfe/pull/47) 9 | - E2E test support. [#57](https://github.com/bfenetworks/ingress-bfe/pull/57), [#60](https://github.com/bfenetworks/ingress-bfe/pull/60) 10 | - Optimize startup logic. [#40](https://github.com/bfenetworks/ingress-bfe/pull/40), [#61](https://github.com/bfenetworks/ingress-bfe/pull/61) 11 | - Docs improvement. [#38](https://github.com/bfenetworks/ingress-bfe/pull/38), [#39](https://github.com/bfenetworks/ingress-bfe/pull/39), [#41](https://github.com/bfenetworks/ingress-bfe/pull/41), [#42](https://github.com/bfenetworks/ingress-bfe/pull/42), [#52](https://github.com/bfenetworks/ingress-bfe/pull/52), [#56](https://github.com/bfenetworks/ingress-bfe/pull/56), [#58](https://github.com/bfenetworks/ingress-bfe/pull/58), [#59](https://github.com/bfenetworks/ingress-bfe/pull/59) 12 | - License related. [#50](https://github.com/bfenetworks/ingress-bfe/pull/50), [#51](https://github.com/bfenetworks/ingress-bfe/pull/51) 13 | 14 | 15 | 16 | ## v0.2.2 (2021-11-17) 17 | 18 | ### Enhancements: 19 | 20 | - Docs improvement. [#28](https://github.com/bfenetworks/ingress-bfe/pull/28), [#29](https://github.com/bfenetworks/ingress-bfe/pull/29), [#33](https://github.com/bfenetworks/ingress-bfe/pull/33) 21 | - Helm Chart support. [#30](https://github.com/bfenetworks/ingress-bfe/pull/30) 22 | - Modify config files for deployment example. [#32](https://github.com/bfenetworks/ingress-bfe/pull/32) 23 | 24 | ### Fixes: 25 | 26 | - Fix license in some files. [#27](https://github.com/bfenetworks/ingress-bfe/pull/27) 27 | 28 | ## v0.2.1 (2021-10-27) 29 | 30 | ### Enhancements: 31 | 32 | - Document in English. [#22](https://github.com/bfenetworks/ingress-bfe/pull/22), [#25 ](https://github.com/bfenetworks/ingress-bfe/pull/25) 33 | - Support new argument for controller. [#19](https://github.com/bfenetworks/ingress-bfe/pull/19) 34 | 35 | ### Fixes: 36 | 37 | - service port checking. [#20](https://github.com/bfenetworks/ingress-bfe/pull/20) 38 | 39 | ## v0.2.0 (2021-10-15) 40 | 41 | ### Enhancements: 42 | 43 | - New version based on controller-runtime. [#11](https://github.com/bfenetworks/ingress-bfe/pull/11) 44 | - Document improvement. [#12](https://github.com/bfenetworks/ingress-bfe/pull/12), [#15](https://github.com/bfenetworks/ingress-bfe/pull/15) 45 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | FROM golang:1.16-alpine3.14 AS build 16 | 17 | RUN apk add build-base 18 | 19 | WORKDIR /bfe-ingress-controller 20 | COPY . . 21 | RUN build/build.sh 22 | 23 | FROM bfenetworks/bfe:v-1.3.0 24 | WORKDIR / 25 | COPY --from=build /bfe-ingress-controller/output/* / 26 | 27 | EXPOSE 8080 8443 8421 28 | 29 | ENTRYPOINT ["/bfe-ingress-controller"] 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 The BFE Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # init project path 16 | WORKROOT := $(shell pwd) 17 | OUTDIR := $(WORKROOT)/output 18 | 19 | # init environment variables 20 | export PATH := $(shell go env GOPATH)/bin:$(PATH) 21 | export GO111MODULE := on 22 | 23 | # init command params 24 | GO := go 25 | GOBUILD := $(GO) build 26 | GOTEST := $(GO) test 27 | GOVET := $(GO) vet 28 | GOGET := $(GO) get 29 | GOGEN := $(GO) generate 30 | GOCLEAN := $(GO) clean 31 | GOFLAGS := -race 32 | STATICCHECK := staticcheck 33 | LICENSEEYE := license-eye 34 | 35 | # init arch 36 | ARCH := $(shell getconf LONG_BIT) 37 | ifeq ($(ARCH),64) 38 | GOTEST += $(GOFLAGS) 39 | endif 40 | 41 | # init bfe ingress version 42 | INGRESS_VERSION ?= $(shell cat VERSION) 43 | # init git commit id 44 | GIT_COMMIT ?= $(shell git rev-parse HEAD) 45 | 46 | # init bfe ingress 47 | INGRESS_PACKAGES := $(shell go list ./...) 48 | 49 | # make, make all 50 | all: compile 51 | 52 | # make compile, go build 53 | compile: test build 54 | build: 55 | $(WORKROOT)/build/build.sh 56 | 57 | # make test, test your code 58 | test: test-case vet-case 59 | test-case: 60 | $(GOTEST) -cover ./... 61 | vet-case: 62 | ${GOVET} ./... 63 | 64 | # make coverage for codecov 65 | coverage: 66 | echo -n > coverage.txt 67 | for pkg in $(INGRESS_PACKAGES) ; do $(GOTEST) -coverprofile=profile.out -covermode=atomic $${pkg} && cat profile.out >> coverage.txt; done 68 | 69 | # make check 70 | check: 71 | $(GO) get honnef.co/go/tools/cmd/staticcheck 72 | $(STATICCHECK) ./... 73 | 74 | # make license-eye-install 75 | license-eye-install: 76 | $(GO) install github.com/apache/skywalking-eyes/cmd/license-eye@latest 77 | 78 | # make license-check, check code file's license declaration 79 | license-check: license-eye-install 80 | $(LICENSEEYE) header check 81 | 82 | # make license-fix, fix code file's license declaration 83 | license-fix: license-eye-install 84 | $(LICENSEEYE) header fix 85 | 86 | # make docker 87 | docker: 88 | docker build \ 89 | -t bfenetworks/bfe-ingress-controller:$(INGRESS_VERSION) \ 90 | -f Dockerfile \ 91 | . 92 | 93 | # make clean 94 | clean: 95 | $(GOCLEAN) 96 | rm -rf $(OUTDIR) 97 | 98 | # e2e test 99 | 100 | kind-cluster: 101 | test/script/kind-create-cluster.sh 102 | 103 | test-env: docker kind-cluster 104 | test/script/kind-load-images.sh $(INGRESS_VERSION) 105 | test/script/deploy-controller.sh $(INGRESS_VERSION) 106 | 107 | e2e-test: test-env 108 | test/e2e/run.sh 109 | test/script/kind-delete-cluster.sh 110 | 111 | # avoid filename conflict and speed up build 112 | .PHONY: all compile test clean build docker e2e-test test-env kind-cluster 113 | -------------------------------------------------------------------------------- /README-CN.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress Controller 2 | 3 | 中文 | [English](README.md) 4 | 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/bfenetworks/ingress-bfe)](https://goreportcard.com/report/github.com/bfenetworks/ingress-bfe) 6 | 7 | ## 简介 8 | 9 | BFE Ingress Controller 为基于 [BFE][] 实现的[Kubernetes Ingress Controller][],用于支持在 Kubernetes 中使用 [Ingress][] 进行流量接入,并利用BFE的众多优秀特点和强大能力。 10 | 11 | ## 特性和优势 12 | 13 | - 路由转发:支持基于Host、Path、Cookie、Header的路由规则 14 | - 多服务间负载均衡:支持在提供相同服务的多个Service之间进行负载均衡 15 | - 灵活的模块框架:采用灵活的模块框架设计,支持高效率定制开发扩展功能 16 | - 配置热加载:支持配置热加载,配置的更新和生效不会影响已存在的长连接 17 | 18 | ## 开始使用 19 | 20 | 详见[部署指南](docs/zh_cn/deployment.md) 21 | 22 | ## 说明文档 23 | 详见[文档列表](docs/zh_cn/SUMMARY.md) 24 | 25 | ## 参与贡献 26 | - 请首先在 [issue 列表](https://github.com/bfenetworks/ingress-bfe/issues) 中创建一个 issue 27 | - 如有必要,请联系项目维护者/负责人进行进一步讨论 28 | - 请遵循 [Golang 编程规范](https://github.com/golang/go/wiki/Style) 29 | 30 | ## 社区交流 31 | 32 | - [用户论坛](https://github.com/bfenetworks/ingress-bfe/discussions) 33 | 34 | - **开源BFE微信公众号**:扫码关注公众号“BFE开源项目”,及时获取项目最新信息和技术分享 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | - **开源BFE用户微信群**:扫码加入,探讨和分享对BFE的建议、使用心得、疑问等 43 | 44 | 45 | 46 | 47 | 48 |
49 | 50 | - **开源BFE开发者微信群**: [发送邮件](mailto:iyangsj@gmail.com)说明您的微信号及贡献(例如PR/Issue),我们将及时邀请您加入 51 | 52 | ## 许可 53 | 基于 Apache 2.0 许可证,详见 [LICENSE](https://github.com/bfenetworks/ingress-bfe/blob/master/LICENSE) 文件说明 54 | 55 | [Kubernetes Ingress Controller]: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/ "Kubernetes" 56 | [Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/ "Kubernetes" 57 | [BFE]: https://github.com/bfenetworks/bfe "Github" 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress Controller 2 | 3 | English | [中文](README-CN.md) 4 | 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/bfenetworks/ingress-bfe)](https://goreportcard.com/report/github.com/bfenetworks/ingress-bfe) 6 | 7 | ## Overview 8 | 9 | BFE Ingress Controller is an implementation of Kubernetes [Ingress Controller][] based on [BFE][], to fulfill [Ingress][] in Kubernetes. 10 | 11 | ## Features and Advantages 12 | 13 | - Traffic routing based on Host, Path, Cookie and Header 14 | - Support for load balancing among multiple Services of the same application 15 | - Flexible plugin framework, based on which developers can add new features efficiently 16 | - Configuration hot reload, avoiding impact on existing long connections 17 | 18 | ## Quick start 19 | 20 | See [Deployment](docs/en_us/deployment.md) for quick start of using BFE Ingress Controller. 21 | 22 | ## Documentation 23 | See [Document Summary](docs/en_us/SUMMARY.md). 24 | 25 | ## Contributing 26 | - Create and issue in [Issue List](https://github.com/bfenetworks/ingress-bfe/issues) 27 | - If necessary, contact and discuss with maintainer 28 | - Follow the [Golang style guide](https://github.com/golang/go/wiki/Style) 29 | 30 | ## Communication 31 | 32 | - [Forum](https://github.com/bfenetworks/ingress-bfe/discussions) 33 | - BFE community on Slack: [Sign up](https://slack.cncf.io/) CNCF Slack and join bfe channel. 34 | - BFE developer group on WeChat: [Send a request mail](mailto:iyangsj@gmail.com) with your WeChat ID and a contribution you've made to BFE(such as a PR/Issue). We will invite you right away. 35 | 36 | ## License 37 | 38 | BFE is under the Apache 2.0 license. See the [LICENSE](https://github.com/bfenetworks/ingress-bfe/blob/master/LICENSE) file for details 39 | 40 | [Ingress Controller]: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/ "Kubernetes" 41 | [Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/ "Kubernetes" 42 | [BFE]: https://github.com/bfenetworks/bfe "Github" 43 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please do not open issues for anything you think might have a security implication. 6 | 7 | Security issues and bugs should be reported privately to . 8 | You should receive a response within 24 hours. If for some reason you do not, 9 | please follow up via email to ensure we received your original message. 10 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.3.0-dev 2 | -------------------------------------------------------------------------------- /build/build.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | set -e 16 | set -x 17 | 18 | WORK_ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" 19 | 20 | # init version 21 | VERSION=$(cat $WORK_ROOT/VERSION) 22 | # init git commit id 23 | GIT_COMMIT=$(git rev-parse HEAD) || true 24 | 25 | go build -ldflags "-X main.version=${VERSION} -X main.commit=${GIT_COMMIT}" \ 26 | -o $WORK_ROOT/output/bfe-ingress-controller $WORK_ROOT/cmd/ingress-controller 27 | 28 | # set permission for docker 29 | cp $WORK_ROOT/scripts/* $WORK_ROOT/output/ 30 | chmod a+x $WORK_ROOT/output/* 31 | echo "${GIT_COMMIT}" > $WORK_ROOT/output/ingress.commit 32 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/.helmignore: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Patterns to ignore when building packages. 16 | # This supports shell glob matching, relative path matching, and 17 | # negation (prefixed with !). Only one pattern per line. 18 | .DS_Store 19 | # Common VCS dirs 20 | .git/ 21 | .gitignore 22 | .bzr/ 23 | .bzrignore 24 | .hg/ 25 | .hgignore 26 | .svn/ 27 | # Common backup files 28 | *.swp 29 | *.bak 30 | *.tmp 31 | *.orig 32 | *~ 33 | # Various IDEs 34 | .project 35 | .idea/ 36 | *.tmproj 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/Chart.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | apiVersion: v2 16 | name: bfe-ingress-controller 17 | description: Helm chart for BFE Ingress Controller 18 | type: application 19 | version: 0.1.0 20 | appVersion: "0.2.2" 21 | keywords: 22 | - ingress 23 | - bfe 24 | home: https://github.com/bfenetworks/ingress-bfe 25 | icon: https://landscape.cncf.io/logos/bfe.svg 26 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if contains "NodePort" .Values.service.type }} 3 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "bfe-ingress-controller.fullname" . }}) 4 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 5 | echo http://$NODE_IP:$NODE_PORT 6 | {{- else if contains "LoadBalancer" .Values.service.type }} 7 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 8 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "bfe-ingress-controller.fullname" . }}' 9 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "bfe-ingress-controller.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 10 | echo http://$SERVICE_IP:{{ .Values.containerPort.http }} 11 | {{- else if contains "ClusterIP" .Values.service.type }} 12 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "bfe-ingress-controller.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 13 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 14 | echo "Visit http://127.0.0.1:8080 to use your application" 15 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 16 | {{- end }} 17 | 18 | 2. Test HTTP port, return 500 19 | curl -v $(echo http://$NODE_IP:$NODE_PORT) 20 | 21 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {* 2 | Copyright 2022 The BFE Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | *} 17 | {{/* 18 | Expand the name of the chart. 19 | */}} 20 | {{- define "bfe-ingress-controller.name" -}} 21 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | 24 | {{/* 25 | Create a default fully qualified app name. 26 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 27 | If release name contains chart name it will be used as a full name. 28 | */}} 29 | {{- define "bfe-ingress-controller.fullname" -}} 30 | {{- if .Values.fullnameOverride }} 31 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 32 | {{- else }} 33 | {{- $name := default .Chart.Name .Values.nameOverride }} 34 | {{- if contains $name .Release.Name }} 35 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 36 | {{- else }} 37 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 38 | {{- end }} 39 | {{- end }} 40 | {{- end }} 41 | 42 | {{/* 43 | Create chart name and version as used by the chart label. 44 | */}} 45 | {{- define "bfe-ingress-controller.chart" -}} 46 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 47 | {{- end }} 48 | 49 | {{/* 50 | Common labels 51 | */}} 52 | {{- define "bfe-ingress-controller.labels" -}} 53 | helm.sh/chart: {{ include "bfe-ingress-controller.chart" . }} 54 | {{ include "bfe-ingress-controller.selectorLabels" . }} 55 | {{- if .Chart.AppVersion }} 56 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 57 | {{- end }} 58 | app.kubernetes.io/managed-by: {{ .Release.Service }} 59 | {{- end }} 60 | 61 | {{/* 62 | Selector labels 63 | */}} 64 | {{- define "bfe-ingress-controller.selectorLabels" -}} 65 | app.kubernetes.io/name: {{ include "bfe-ingress-controller.name" . }} 66 | app.kubernetes.io/instance: {{ .Release.Name }} 67 | {{- end }} 68 | 69 | {{/* 70 | Create the name of the service account to use 71 | */}} 72 | {{- define "bfe-ingress-controller.serviceAccountName" -}} 73 | {{- if .Values.serviceAccount.create }} 74 | {{- default (include "bfe-ingress-controller.fullname" .) .Values.serviceAccount.name }} 75 | {{- else }} 76 | {{- default "default" .Values.serviceAccount.name }} 77 | {{- end }} 78 | {{- end }} 79 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | metadata: 18 | name: {{ include "bfe-ingress-controller.fullname" . }} 19 | labels: 20 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 21 | spec: 22 | {{- if not .Values.autoscaling.enabled }} 23 | replicas: {{ .Values.replicaCount }} 24 | {{- end }} 25 | selector: 26 | matchLabels: 27 | {{- include "bfe-ingress-controller.selectorLabels" . | nindent 6 }} 28 | template: 29 | metadata: 30 | {{- with .Values.podAnnotations }} 31 | annotations: 32 | {{- toYaml . | nindent 8 }} 33 | {{- end }} 34 | labels: 35 | {{- include "bfe-ingress-controller.selectorLabels" . | nindent 8 }} 36 | spec: 37 | {{- with .Values.imagePullSecrets }} 38 | imagePullSecrets: 39 | {{- toYaml . | nindent 8 }} 40 | {{- end }} 41 | serviceAccountName: {{ include "bfe-ingress-controller.serviceAccountName" . }} 42 | securityContext: 43 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 44 | containers: 45 | - name: {{ .Chart.Name }} 46 | securityContext: 47 | {{- toYaml .Values.securityContext | nindent 12 }} 48 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 49 | imagePullPolicy: {{ .Values.image.pullPolicy }} 50 | args: 51 | {{- if .Values.scope.namespaces }} 52 | - "-n" 53 | - {{ .Values.scope.namespaces | quote}} 54 | {{- end }} 55 | ports: 56 | {{- range $key, $value := .Values.containerPort }} 57 | - name: {{ $key }} 58 | containerPort: {{ $value }} 59 | protocol: TCP 60 | {{- end }} 61 | livenessProbe: {{ toYaml .Values.livenessProbe | nindent 12 }} 62 | readinessProbe: {{ toYaml .Values.readinessProbe | nindent 12 }} 63 | resources: 64 | {{- toYaml .Values.resources | nindent 12 }} 65 | {{- with .Values.nodeSelector }} 66 | nodeSelector: 67 | {{- toYaml . | nindent 8 }} 68 | {{- end }} 69 | {{- with .Values.affinity }} 70 | affinity: 71 | {{- toYaml . | nindent 8 }} 72 | {{- end }} 73 | {{- with .Values.tolerations }} 74 | tolerations: 75 | {{- toYaml . | nindent 8 }} 76 | {{- end }} 77 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | {{- if .Values.autoscaling.enabled }} 16 | apiVersion: autoscaling/v2beta1 17 | kind: HorizontalPodAutoscaler 18 | metadata: 19 | name: {{ include "bfe-ingress-controller.fullname" . }} 20 | labels: 21 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 22 | spec: 23 | scaleTargetRef: 24 | apiVersion: apps/v1 25 | kind: Deployment 26 | name: {{ include "bfe-ingress-controller.fullname" . }} 27 | minReplicas: {{ .Values.autoscaling.minReplicas }} 28 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 29 | metrics: 30 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 31 | - type: Resource 32 | resource: 33 | name: cpu 34 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 35 | {{- end }} 36 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 37 | - type: Resource 38 | resource: 39 | name: memory 40 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 41 | {{- end }} 42 | {{- end }} 43 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | {{- if .Values.rbac.create }} 16 | 17 | apiVersion: rbac.authorization.k8s.io/v1 18 | kind: ClusterRole 19 | metadata: 20 | labels: 21 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 22 | name: {{ include "bfe-ingress-controller.fullname" . }} 23 | rules: 24 | - apiGroups: 25 | - "" 26 | resources: 27 | - endpoints 28 | - services 29 | - secrets 30 | - namespaces 31 | - nodes 32 | verbs: 33 | - get 34 | - list 35 | - watch 36 | - apiGroups: 37 | - "" 38 | resources: 39 | - events 40 | verbs: 41 | - create 42 | - patch 43 | - apiGroups: 44 | - extensions 45 | - networking.k8s.io 46 | resources: 47 | - ingresses 48 | verbs: 49 | - get 50 | - list 51 | - watch 52 | - update 53 | - patch 54 | - apiGroups: 55 | - "" 56 | resources: 57 | - events 58 | verbs: 59 | - create 60 | - patch 61 | - update 62 | - apiGroups: 63 | - networking.k8s.io 64 | resources: 65 | - ingresses/status 66 | verbs: 67 | - update 68 | - patch 69 | - apiGroups: 70 | - networking.k8s.io 71 | resources: 72 | - ingressclasses 73 | verbs: 74 | - get 75 | - list 76 | - watch 77 | 78 | --- 79 | apiVersion: rbac.authorization.k8s.io/v1 80 | kind: ClusterRoleBinding 81 | metadata: 82 | labels: 83 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 84 | name: {{ include "bfe-ingress-controller.fullname" . }} 85 | roleRef: 86 | apiGroup: rbac.authorization.k8s.io 87 | kind: ClusterRole 88 | name: {{ include "bfe-ingress-controller.fullname" . }} 89 | subjects: 90 | - kind: ServiceAccount 91 | name: {{ template "bfe-ingress-controller.serviceAccountName" . }} 92 | namespace: {{ .Release.Namespace | quote }} 93 | 94 | {{- end }} 95 | 96 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/service.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | apiVersion: v1 16 | kind: Service 17 | metadata: 18 | name: {{ include "bfe-ingress-controller.fullname" . }} 19 | labels: 20 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 21 | spec: 22 | type: {{ .Values.service.type }} 23 | ports: 24 | {{- range $key, $value := .Values.containerPort }} 25 | - name: {{ $key }} 26 | port: {{ $value }} 27 | targetPort: {{ $value }} 28 | {{- end }} 29 | selector: 30 | {{- include "bfe-ingress-controller.selectorLabels" . | nindent 4 }} 31 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | {{- if .Values.serviceAccount.create }} 16 | apiVersion: v1 17 | kind: ServiceAccount 18 | metadata: 19 | name: {{ include "bfe-ingress-controller.serviceAccountName" . }} 20 | labels: 21 | {{- include "bfe-ingress-controller.labels" . | nindent 4 }} 22 | {{- with .Values.serviceAccount.annotations }} 23 | annotations: 24 | {{- toYaml . | nindent 4 }} 25 | {{- end }} 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/bfe-ingress-controller/values.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 The BFE Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Default values for bfe-ingress-controller. 16 | replicaCount: 1 17 | 18 | image: 19 | repository: bfenetworks/bfe-ingress-controller 20 | pullPolicy: IfNotPresent 21 | # Overrides the image tag whose default is the chart appVersion. 22 | tag: "" 23 | 24 | imagePullSecrets: [] 25 | nameOverride: "" 26 | fullnameOverride: "" 27 | 28 | containerPort: 29 | http: 8080 30 | https: 8443 31 | monitor: 8421 32 | 33 | livenessProbe: 34 | httpGet: 35 | path: "/" 36 | port: 8421 37 | scheme: HTTP 38 | initialDelaySeconds: 5 39 | periodSeconds: 5 40 | timeoutSeconds: 1 41 | successThreshold: 1 42 | failureThreshold: 5 43 | 44 | readinessProbe: 45 | httpGet: 46 | path: "/" 47 | port: 8421 48 | scheme: HTTP 49 | initialDelaySeconds: 10 50 | periodSeconds: 5 51 | timeoutSeconds: 1 52 | successThreshold: 1 53 | failureThreshold: 3 54 | 55 | serviceAccount: 56 | # Specifies whether a service account should be created 57 | create: true 58 | # Annotations to add to the service account 59 | annotations: {} 60 | # The name of the service account to use. 61 | # If not set and create is true, a name is generated using the fullname template 62 | name: "" 63 | 64 | podAnnotations: {} 65 | 66 | podSecurityContext: {} 67 | # fsGroup: 2000 68 | 69 | securityContext: {} 70 | # capabilities: 71 | # drop: 72 | # - ALL 73 | # readOnlyRootFilesystem: true 74 | # runAsNonRoot: true 75 | # runAsUser: 1000 76 | 77 | service: 78 | type: NodePort 79 | 80 | scope: {} 81 | # Set namespaces the controller watch, delimited by ',' 82 | # Default to all namespace 83 | # namespaces: namespace1,namespace2 84 | 85 | resources: {} 86 | # We usually recommend not to specify default resources and to leave this as a conscious 87 | # choice for the user. This also increases chances charts run on environments with little 88 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 89 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 90 | # limits: 91 | # cpu: 100m 92 | # memory: 128Mi 93 | # requests: 94 | # cpu: 100m 95 | # memory: 128Mi 96 | 97 | autoscaling: 98 | enabled: false 99 | minReplicas: 1 100 | maxReplicas: 100 101 | targetCPUUtilizationPercentage: 80 102 | # targetMemoryUtilizationPercentage: 80 103 | 104 | nodeSelector: {} 105 | 106 | tolerations: [] 107 | 108 | affinity: {} 109 | 110 | rbac: 111 | create: true 112 | -------------------------------------------------------------------------------- /cmd/ingress-controller/flags.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | 20 | "github.com/bfenetworks/ingress-bfe/internal/option" 21 | ) 22 | 23 | var ( 24 | help bool 25 | showVersion bool 26 | 27 | opts *option.Options = option.NewOptions() 28 | ) 29 | 30 | func initFlags() { 31 | flag.BoolVar(&help, "help", false, "Show help.") 32 | flag.BoolVar(&help, "h", false, "Show help.") 33 | 34 | flag.BoolVar(&showVersion, "version", false, "Show version of bfe-ingress-controller.") 35 | flag.BoolVar(&showVersion, "v", false, "Show version of bfe-ingress-controller.") 36 | 37 | flag.StringVar(&opts.Namespaces, "namespace", opts.Namespaces, "Namespaces to watch, delimited by ','.") 38 | flag.StringVar(&opts.Namespaces, "n", opts.Namespaces, "Namespaces to watch, delimited by ','.") 39 | 40 | flag.StringVar(&opts.MetricsAddr, "metrics-bind-address", opts.MetricsAddr, "The address the metric endpoint binds to.") 41 | flag.StringVar(&opts.HealthProbeAddr, "health-probe-bind-address", opts.HealthProbeAddr, "The address the probe endpoint binds to.") 42 | flag.StringVar(&opts.ClusterName, "k8s-cluster-name", opts.ClusterName, "k8s cluster name") 43 | 44 | flag.StringVar(&opts.Ingress.ConfigPath, "bfe-config-path", opts.Ingress.ConfigPath, "Root directory of bfe configuration files.") 45 | flag.StringVar(&opts.Ingress.ConfigPath, "c", opts.Ingress.ConfigPath, "Root directory of bfe configuration files.") 46 | flag.StringVar(&opts.Ingress.BfeBinary, "bfe-binary", opts.Ingress.BfeBinary, "Absolute path of BFE binary. If set, is overwritten by /../conf") 47 | flag.StringVar(&opts.Ingress.BfeBinary, "b", opts.Ingress.BfeBinary, "Absolute path of BFE binary. If set, is overwritten by /../conf,") 48 | flag.StringVar(&opts.Ingress.ReloadAddr, "bfe-reload-address", opts.Ingress.ReloadAddr, "Address of bfe config reloading.") 49 | flag.StringVar(&opts.Ingress.IngressClass, "ingress-class", opts.Ingress.IngressClass, "Class name of bfe ingress controller.") 50 | flag.StringVar(&opts.Ingress.DefaultBackend, "default-backend", opts.Ingress.DefaultBackend, "set default backend name, default backend is used if no any ingress rule matched, format namespace/name.") 51 | 52 | } 53 | -------------------------------------------------------------------------------- /cmd/ingress-controller/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "fmt" 20 | rt "runtime" 21 | 22 | "k8s.io/apimachinery/pkg/runtime" 23 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 24 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 25 | ctrl "sigs.k8s.io/controller-runtime" 26 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 27 | 28 | "github.com/bfenetworks/ingress-bfe/internal/controllers" 29 | "github.com/bfenetworks/ingress-bfe/internal/option" 30 | ) 31 | 32 | var ( 33 | scheme = runtime.NewScheme() 34 | setupLog = ctrl.Log.WithName("setup") 35 | ) 36 | 37 | func init() { 38 | utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 39 | initFlags() 40 | } 41 | 42 | var ( 43 | version string 44 | commit string 45 | ) 46 | 47 | func main() { 48 | zapOpts := zap.Options{ 49 | Development: true, 50 | } 51 | zapOpts.BindFlags(flag.CommandLine) 52 | flag.Parse() 53 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&zapOpts))) 54 | 55 | if help { 56 | flag.PrintDefaults() 57 | return 58 | } 59 | if showVersion { 60 | fmt.Printf("bfe-ingress-controller version: %s\n", version) 61 | fmt.Printf("go version: %s\n", rt.Version()) 62 | fmt.Printf("git commit: %s\n", commit) 63 | return 64 | } 65 | 66 | err := option.SetOptions(opts) 67 | if err != nil { 68 | setupLog.Error(err, "fail to start controllers") 69 | return 70 | } 71 | 72 | setupLog.Info("starting bfe-ingress-controller") 73 | 74 | if err := controllers.Start(scheme); err != nil { 75 | setupLog.Error(err, "fail to start controllers") 76 | } 77 | 78 | setupLog.Info("bfe-ingress-controller exit") 79 | } 80 | -------------------------------------------------------------------------------- /dist/bfe.ini: -------------------------------------------------------------------------------- 1 | ; Copyright 2021 The BFE Authors 2 | ; 3 | ; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ; you may not use this file except in compliance with the License. 5 | ; You may obtain a copy of the License at 6 | ; 7 | ; http://www.apache.org/licenses/LICENSE-2.0 8 | ; 9 | ; Unless required by applicable law or agreed to in writing, software 10 | ; distributed under the License is distributed on an "AS IS" BASIS, 11 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ; See the License for the specific language governing permissions and 13 | ; limitations under the License. 14 | ; 15 | [program:bfe] 16 | directory=/home/work/bfe/bin/ 17 | command=./bfe -c ../conf -l ../log -d 18 | priority=999 ; the relative start priority (default 999) 19 | autostart=true ; start at supervisord start (default: true) 20 | autorestart=true ; retstart at unexpected quit (default: true) 21 | startsecs=10 ; number of secs prog must stay running (def. 10) 22 | startretries=3 ; max # of serial start failures (default 3) 23 | exitcodes=0,2 ; 'expected' exit codes for process (default 0,2) 24 | stopsignal=QUIT ; signal used to kill process (default TERM) 25 | stopwaitsecs=10 ; max num secs to wait before SIGKILL (default 10) 26 | user=work ; setuid to this UNIX account to run the program 27 | log_stdout=true 28 | log_stderr=true ; if true, log program stderr (def false) 29 | logfile=/tmp/echo_time.log 30 | logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) 31 | logfile_backups=10 ; # of logfile backups (default 10) 32 | stdout_logfile_maxbytes=20MB ; stdout file size,default 50MB 33 | stdout_logfile_backups=2 ; stdout file number 34 | stdout_logfile=/tmp/echo_time.stdout.log 35 | -------------------------------------------------------------------------------- /dist/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2021 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | set -x 17 | 18 | readonly BFE_BIN=bfe 19 | 20 | cd /home/work/bfe/bin/ && nohup ./${BFE_BIN} -c ../conf -l ../log -d & 21 | 22 | if [ -n "$INGRESS_LISTEN_NAMESPACE" ]; then 23 | cd /home/work/bfe/bin/ && ./bfe_ingress_controller -l ../log -c "/home/work/bfe/conf/" -n "$INGRESS_LISTEN_NAMESPACE" "$@" 24 | else 25 | cd /home/work/bfe/bin/ && ./bfe_ingress_controller -l ../log -c "/home/work/bfe/conf/" "$@" 26 | fi -------------------------------------------------------------------------------- /docs/en_us/FAQ/FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 1. Question:what arguments can be used to run BFE Ingress Controller, and how to define them? 3 | 4 | Answer: Arguments supported by BFE Ingress Controller: 5 | 6 | |Argument | Default value | Description| 7 | | --- | --- | --- | 8 | | --namespace
-n | Empty String | Specify in which namespaces BFE Ingress Controller will monitor Ingress. Multiple namespaces are seperated by `,`.
Default value is empty string which means to monitor all namespaces. | 9 | | --ingress-class| bfe | Specify the `kubernetes.io/ingress.class` value of Ingress it monitors.
If not specified, BFE Ingress Controller monitors the Ingress with ingress class set as "bfe". Usually you don't need to specify it. | 10 | | --default-backend| Empty String | Specify name of default backend service, in the format of `namespace/name`.
If specified, requests that match no Ingress rule will be forwarded to the service specified. | 11 | 12 | How to define: 13 | Define in config file of BFE Ingress Controller, like [controller.yaml](../../../examples/controller.yaml). Example: 14 | 15 | ```yaml 16 | ... 17 | containers: 18 | - name: bfe-ingress-controller 19 | image: bfenetworks/bfe-ingress-controller:latest 20 | args: ["-n", "ns1,ns2", "--default-backend", "test/whoami"] 21 | ... 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/en_us/README.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress Controller 2 | 3 | BFE Ingress Controller is a Kubernetes [Ingress Controller][] based on [BFE][], to fulfill the [Ingress][] in Kubernetes. 4 | 5 | [Documents](SUMMARY.md) 6 | 7 | [Ingress Controller]: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/ "Kubernetes" 8 | [Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/ "Kubernetes" 9 | [BFE]: https://github.com/bfenetworks/bfe "Github" 10 | 11 | -------------------------------------------------------------------------------- /docs/en_us/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [comment]: <> "For user" 4 | * Deployment 5 | * [Deployment Guide](deployment.md) 6 | * [Role-Based Access Control (RBAC)](rbac.md) 7 | * Configuration 8 | * [Configuration Guide](ingress/basic.md) 9 | * [Ingress Status](ingress/validate-state.md) 10 | * [Priority of Route Rules](ingress/priority.md) 11 | * [Principles of Handling Route Rule Conflicts](ingress/conflict.md) 12 | * [TLS Configuration](ingress/tls.md) 13 | * [Load Balance](ingress/load-balance.md) 14 | * [Redirect](ingress/redirect.md) 15 | * [Rewrite](ingress/rewrite.md) 16 | * Configuration Examples 17 | * [Config File Example](example/example.md) 18 | * [Canary Release Example](example/canary-release.md) 19 | * [FAQ](FAQ/FAQ.md) 20 | * Appendix 21 | * [Annotations](appendix/annotations.md) 22 | 23 | --- 24 | 25 | [comment]: <> "For developer" 26 | * [How to contribute](contribute/how-to-contribute.md) 27 | * [Contribute codes](contribute/contribute-codes.md) 28 | * [Contribute documents](contribute/contribute-documents.md) 29 | * [Release Regulation](https://www.bfe-networks.net/en_us/development/release_regulation/) 30 | 31 | -------------------------------------------------------------------------------- /docs/en_us/contribute/contribute-documents.md: -------------------------------------------------------------------------------- 1 | # Contribute Document 2 | 3 | ## Requirement 4 | - All documents should be written in [Markdown][markdown] (GitHub style),using filename with suffix `.md` 5 | - If new document is created, add its link in the index file([SUMMARY.md](../SUMMARY.md)) 6 | ## Process 7 | 8 | 1. Create or edit document 9 | 2. Use preview tools to preview and modify if necessary 10 | - [How to use preview tool](https://www.bfe-networks.net/en_us/development/write_doc_guide/#_2) 11 | 3. Submit 12 | - Commit and initiate a Pull Request, refer to [Contribute Code](contribute-codes.md) 13 | 14 | > Refer to [Contribute Documentation](https://www.bfe-networks.net/en_us/development/write_doc_guide/) of BFE 15 | 16 | [markdown]: https://guides.github.com/features/mastering-markdown/ 17 | 18 | -------------------------------------------------------------------------------- /docs/en_us/contribute/how-to-contribute.md: -------------------------------------------------------------------------------- 1 | # Contribute 2 | - [Contribute Code](contribute-codes.md) 3 | - [Contribute Document](contribute-documents.md) 4 | - [Release Regulation](https://www.bfe-networks.net/en_us/development/release_regulation/) 5 | 6 | -------------------------------------------------------------------------------- /docs/en_us/deployment.md: -------------------------------------------------------------------------------- 1 | # Deployment Guide 2 | 3 | ## Installation 4 | Install BFE Ingress Controller in either of two ways: 5 | * Apply a configure file 6 | * Install helm charts of controller 7 | 8 | ### Configure file 9 | 10 | ``` shell script 11 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/controller-all.yaml 12 | ``` 13 | 14 | - Above configure file uses the latest version of [BFE Ingress Controller image](https://hub.docker.com/r/bfenetworks/bfe-ingress-controller) in Docker Hub. You can edit configure file to specify other version of the image. 15 | 16 | - For details of permission configuration, please find more information in [Role-Based Access Control](rbac.md) 17 | 18 | ### Helm 19 | 20 | ``` 21 | helm upgrade --install bfe-ingress-controller bfe-ingress-controller --repo https://bfenetworks.github.io/ingress-bfe --namespace ingress-bfe --create-namespace 22 | ``` 23 | 24 | - helm3 is required. 25 | 26 | ## Testing 27 | 28 | * Create a testing service 29 | 30 | ``` shell script 31 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/whoami.yaml 32 | ``` 33 | 34 | * Create ingress resource for testing service to verify the installation 35 | 36 | ``` shell script 37 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/ingress.yaml 38 | 39 | ``` 40 | 41 | * Create ingress resource for testing service to verify the installation if your kubernetes version >= 1.19 42 | ``` shell script 43 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/ingress-v1.19.yaml 44 | 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/en_us/example/canary-release.md: -------------------------------------------------------------------------------- 1 | # Canary Release 2 | 3 | ## Introduction 4 | BFE Ingress Controller supports `Header/Cookie` based "canary release" by configuring`Annotation`. 5 | 6 | ## Config Example 7 | * Original ingress configuration is shown as follows. Ingress will forward matched requests to `service`: 8 | ```yaml 9 | kind: Ingress 10 | apiVersion: networking.k8s.io/v1beta1 11 | metadata: 12 | name: "original" 13 | namespace: production 14 | 15 | spec: 16 | rules: 17 | - host: example.net 18 | http: 19 | paths: 20 | - path: /bar 21 | pathType: Exact 22 | backend: 23 | serviceName: service 24 | servicePort: 80 25 | ``` 26 | 27 | * Canary release is applied and interested requests should be forwarded to a new service `service2`. 28 | * To achieve this, create a new ingress, with header or cookie information of interested requests included in annotations. 29 | ```yaml 30 | kind: Ingress 31 | apiVersion: networking.k8s.io/v1beta1 32 | metadata: 33 | name: "greyscale" 34 | namespace: production 35 | annotations: 36 | bfe.ingress.kubernetes.io/router.cookie: "key: value" 37 | bfe.ingress.kubernetes.io/router.header: "Key: Value" 38 | 39 | spec: 40 | rules: 41 | - host: example.net 42 | http: 43 | paths: 44 | - path: /bar 45 | pathType: Exact 46 | backend: 47 | serviceName: service2 48 | servicePort: 80 49 | 50 | ``` 51 | * Based on above configuration, BFE Ingress Controller will 52 | 1. forward requests with `host == example.net && path == /bar && cookie[key] == value && Header[Key] == Value` 53 | to service `service-new` 54 | 1. forward other requests with `host == example.net && path == /bar` 55 | to service `service` 56 | -------------------------------------------------------------------------------- /docs/en_us/example/example.md: -------------------------------------------------------------------------------- 1 | # Examples of Config File 2 | 3 | ## deployment 4 | | Program | File | Description | 5 | | ---- | ---- | ---- | 6 | | bfe-ingress-controller | [controller.yaml](../../../examples/controller.yaml)| to deploy BFE Ingress Controller | 7 | | example backend service: whoami | [whoami.yaml](../../../examples/whoami.yaml) | to deploy example service `whoami` | 8 | 9 | ## ingress 10 | | File | Description | 11 | | ---- | ---- | 12 | | [ingress.yaml](../../../examples/ingress.yaml) | to config route for traffic to example service `whoami` | 13 | 14 | ## rbac 15 | | File | Description | 16 | | ---- | ---- | 17 | | [rbac.yaml](../../../examples/rbac.yaml) | to config access control for BFE Ingress Controller | 18 | 19 | -------------------------------------------------------------------------------- /docs/en_us/ingress/conflict.md: -------------------------------------------------------------------------------- 1 | # Route Rule Conflict 2 | 3 | ## Definition 4 | If Ingress configurations create Ingress resources containing at least one identical Ingress rule (host, path and advanced conditions are all the same), a route rule conflict happens. 5 | 6 | ## Conflict handling: first-created-resource-win principle 7 | 8 | For those Ingress resources with route rule conflict, BFE Ingress Controller will follow first-created-resource-win principle and only takes the first created Ingress resource as valid. 9 | 10 | This principle will be followed when route rule conflict happens within a namespace or across different namespaces. 11 | 12 | For those invalid Ingress resources due to route rule conflict, error messages will be written to its annotation, see [Ingress Status](validate-state.md). 13 | 14 | ## Example 15 | 16 | ```yaml 17 | apiVersion: networking.k8s.io/v1beta1 18 | kind: Ingress 19 | metadata: 20 | name: ingress-A 21 | namespace: production 22 | annotations: 23 | kubernetes.io/ingress.class: bfe 24 | spec: 25 | rules: 26 | - host: example.foo.com 27 | http: 28 | paths: 29 | - path: /foo 30 | pathType: Prefix 31 | backend: 32 | serviceName: service1 33 | servicePort: 80 34 | --- 35 | apiVersion: networking.k8s.io/v1beta1 36 | kind: Ingress 37 | metadata: 38 | name: ingress-B 39 | namespace: production 40 | annotations: 41 | kubernetes.io/ingress.class: bfe 42 | spec: 43 | rules: 44 | - host: example.foo.com 45 | http: 46 | paths: 47 | - path: /foo 48 | pathType: Prefix 49 | backend: 50 | serviceName: service2 51 | servicePort: 80 52 | 53 | ``` 54 | In above configuration, there is conflict between ingress-A and ingress-B, and ingress-A is created before ingress-B. So only ingress-A will be created and take effect. 55 | 56 | ## Ingress status feedback 57 | If an Ingress resource is invalid due to route rule conflict, after the ingress status is written back, the `status` in `annotation` will be set as “fail”, and `message` will tell which Ingress resource it has conflict with. 58 | 59 | In previous example, `annotation` for ingress status will be like: 60 | 61 | 62 | ```yaml 63 | metadata: 64 | annotations: 65 | bfe.ingress.kubernetes.io/bfe-ingress-status: | 66 | {"status": "fail", "message": "conflict with production/ingress-A"} 67 | ``` 68 | 69 | For more information about ingress status, refer to [ingress status](validate-state.md)。 70 | 71 | -------------------------------------------------------------------------------- /docs/en_us/ingress/load-balance.md: -------------------------------------------------------------------------------- 1 | # Load balancing between Services 2 | ## Introduction 3 | 4 | For `Service`s that providing the same service (called Sub-Services), BFE Ingress Controller supports load balancing between them, based on weight configured for each `Service`. 5 | 6 | ## Configuration 7 | 8 | BFE Ingress Controller use `Annotation` to support load-balancing between multiple Sub-Services: 9 | 10 | - in `annotations` 11 | 12 | - configure weight for each Sub-Service. 13 | 14 | - define a `Service` name for the service they provided together: 15 | 16 | ``` yaml 17 | bfe.ingress.kubernetes.io/balance.weight: '{"service": {"sub-service1":80, "sub-service2":20}}' 18 | ``` 19 | 20 | - in `rules` 21 | 22 | - set the `serviceName` of `backend` as the `Service` name in `Annotation`, and set the `servicePort`. 23 | 24 | ## Example 25 | 26 | ```yaml 27 | apiVersion: networking.k8s.io/v1beta1 28 | kind: Ingress 29 | metadata: 30 | name: tls-example-ingress 31 | annotations: 32 | kubernetes.io/ingress.class: bfe 33 | bfe.ingress.kubernetes.io/balance.weight: '{"service": {"service1":80, "service2":20}}' 34 | spec: 35 | tls: 36 | - hosts: 37 | - https-example.foo.com 38 | secretName: testsecret-tls 39 | rules: 40 | - host: https-example.foo.com 41 | http: 42 | paths: 43 | - path: / 44 | pathType: Prefix 45 | backend: 46 | serviceName: service 47 | servicePort: 80 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/en_us/ingress/redirect.md: -------------------------------------------------------------------------------- 1 | # Redirect 2 | 3 | The BFE Ingress Controller supports redirecting traffic matched by the Ingress by using `metadata.annotations` of the Ingress object. 4 | 5 | ## How to Config 6 | 7 | In the Ingress object, 8 | 9 | - `spec.rules` defines the route rules; 10 | - `metadata.annotations` defines the behavior of redirecting traffic matched by the Ingress. 11 | 12 | Reference format: 13 | 14 | ```yaml 15 | metadata: 16 | annotations: 17 | bfe.ingress.kubernetes.io/redirect.url-set: "https://www.baidu.com" 18 | spec: 19 | rules: 20 | - ... 21 | ``` 22 | 23 | ```yaml 24 | metadata: 25 | annotations: 26 | bfe.ingress.kubernetes.io/redirect.scheme-set: https 27 | bfe.ingress.kubernetes.io/redirect.status: 301 28 | spec: 29 | rules: 30 | - ... 31 | ``` 32 | 33 | ## Redirect Location 34 | 35 | The BFE Ingress Controller supports 4 ways to configure the redirect location, and only one of them can be set in an Ingress object. 36 | 37 | ### Static URL 38 | 39 | Use `bfe.ingress.kubernetes.io/redirect.url-set` to config the static redirect location。 40 | 41 | For example: 42 | 43 | ```yaml 44 | bfe.ingress.kubernetes.io/redirect.target: "https://www.baidu.com" 45 | ``` 46 | 47 | Corresponding scenario: 48 | 49 | - Request: http://host/path?query-key=value 50 | - Response: https://www.baidu.com 51 | 52 | ### Fetch URL from Query 53 | 54 | Redirect location is fetched from specific Query of request URL, query key is specified by `bfe.ingress.kubernetes.io/redirect.url-from-query`. 55 | 56 | For example: 57 | 58 | ```yaml 59 | bfe.ingress.kubernetes.io/redirect.url-from-query: url 60 | ``` 61 | 62 | Corresponding scenario: 63 | 64 | - Request: https://host/path?url=https%3A%2F%2Fwww.baidu.com 65 | - Response: https://www.baidu.com 66 | 67 | ### Add Prefix 68 | 69 | Redirect location is a combination of given prefix and the `Path` of request URL, the prefix is set by `bfe.ingress.kubernetes.io/redirect.url-prefix-add`. 70 | 71 | For example: 72 | 73 | ```yaml 74 | bfe.ingress.kubernetes.io/redirect.url-prefix-add: "http://www.baidu.com/redirect" 75 | ``` 76 | 77 | Corresponding scenario: 78 | 79 | - Request: https://host/path?query-key=value 80 | - Response: http://www.baidu.com/redirect/path?query-key=value 81 | 82 | ### Set Scheme 83 | 84 | Change the scheme of the request。Only HTTP and HTTPS are supported. 85 | 86 | For example: 87 | 88 | ```yaml 89 | bfe.ingress.kubernetes.io/redirect.scheme-set: http 90 | ``` 91 | 92 | Corresponding scenario: 93 | 94 | - Request: https://host/path?query-key=value 95 | - Response: http://host/path?query-key=value 96 | 97 | ## Response Status Code 98 | 99 | By default, the status code of the redirect response is `302`. Users can manually specify the redirect status code by setting `bfe.ingress.kubernetes.io/redirect.response-status`. 100 | 101 | For example: 102 | 103 | ```yaml 104 | bfe.ingress.kubernetes.io/redirect.response-status: 301 105 | ``` 106 | 107 | The supported redirection status codes are: 301, 302, 303, 307, 308. -------------------------------------------------------------------------------- /docs/en_us/ingress/tls.md: -------------------------------------------------------------------------------- 1 | # TLS Configuration 2 | BFE Ingress Controller manages TLS certificates and secretes in the way defined by Kubernetes. 3 | 4 | TLS certificates and secretes are stored in `Secret`. See examples below: 5 | 6 | **Configure Secret** 7 | 8 | ```yaml 9 | apiVersion: v1 10 | kind: Secret 11 | metadata: 12 | name: testsecret-tls 13 | namespace: default 14 | data: 15 | tls.crt: base64 encoded cert 16 | tls.key: base64 encoded key 17 | type: kubernetes.io/tls 18 | ``` 19 | **Configure Ingress** 20 | 21 | ```yaml 22 | apiVersion: networking.k8s.io/v1beta1 23 | kind: Ingress 24 | metadata: 25 | name: tls-example-ingress 26 | spec: 27 | tls: 28 | - hosts: 29 | - https-example.foo.com 30 | secretName: testsecret-tls 31 | rules: 32 | - host: https-example.foo.com 33 | http: 34 | paths: 35 | - path: / 36 | pathType: Prefix 37 | backend: 38 | serviceName: service1 39 | servicePort: 80 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/en_us/ingress/validate-state.md: -------------------------------------------------------------------------------- 1 | # Ingress status 2 | 3 | ## Feedback for ingress status 4 | The validation of the Ingress configuration is an asynchronous process. The status can only be returned after the configuration has taken effect. 5 | 6 | In order to provide feedback for ingress status, BFE Ingress Controller will write status back to its annotations. 7 | 8 | **BFE Ingress Controller defines the annotation for status as follows:** 9 | 10 | ```yaml 11 | #bfe.ingress.kubernetes.io/bfe-ingress-status is the reserved Annotation key of BFE Ingress Controller 12 | #used for status feedback. 13 | # status: success -> ingress is valid, error -> ingress is invalid. 14 | # message: if ingress is invalid, error messages will be recorded 15 | bfe.ingress.kubernetes.io/bfe-ingress-status: {"status": "", "message": ""} 16 | ``` 17 | ## Example 18 | 19 | The following example shows the status of two ingresses with route rules conflict. 20 | `Ingress1` and `Ingress2` have one identical route rule (`Host:example.net, Path:/bar`) 21 | 22 | ```yaml 23 | kind: Ingress 24 | apiVersion: networking.k8s.io/v1beta1 25 | metadata: 26 | name: "ingress1" 27 | namespace: production 28 | annotations: 29 | kubernetes.io/ingress.class: bfe 30 | spec: 31 | rules: 32 | - host: example.net 33 | http: 34 | paths: 35 | - path: /bar 36 | backend: 37 | serviceName: service1 38 | servicePort: 80 39 | --- 40 | kind: Ingress 41 | apiVersion: networking.k8s.io/v1beta1 42 | metadata: 43 | name: "ingress2" 44 | namespace: production 45 | annotations: 46 | kubernetes.io/ingress.class: bfe 47 | spec: 48 | rules: 49 | - host: example.net 50 | http: 51 | paths: 52 | - path: /bar 53 | backend: 54 | serviceName: service2 55 | servicePort: 80 56 | ``` 57 | According to [principles of handling route rule conflict](conflict.md), `Ingress1` will take effect and `Ingress2` will be ignored. After the status is returned, `status` of `Ingress1` will be "success" and status of `Ingress2` it will be "fail". 58 | ```yaml 59 | kind: Ingress 60 | apiVersion: networking.k8s.io/v1beta1 61 | metadata: 62 | name: "ingress1" 63 | namespace: production 64 | annotations: 65 | kubernetes.io/ingress.class: bfe 66 | bfe.ingress.kubernetes.io/bfe-ingress-status: {"status": "success"} 67 | spec: 68 | rules: 69 | - host: example.net 70 | http: 71 | paths: 72 | - path: /bar 73 | backend: 74 | serviceName: service1 75 | servicePort: 80 76 | --- 77 | kind: Ingress 78 | apiVersion: networking.k8s.io/v1beta1 79 | metadata: 80 | name: "ingress2" 81 | namespace: production 82 | annotations: 83 | kubernetes.io/ingress.class: bfe 84 | bfe.ingress.kubernetes.io/bfe-ingress-status: | 85 | {"status": "fail", "message": "conflict with production/ingress1"} 86 | spec: 87 | rules: 88 | - host: example.net 89 | http: 90 | paths: 91 | - path: /bar 92 | backend: 93 | serviceName: service2 94 | servicePort: 80 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/en_us/rbac.md: -------------------------------------------------------------------------------- 1 | # Role-Based Access Control (RBAC) 2 | 3 | ## Introduction 4 | 5 | This document describes how to deploy BFE Ingress Controller in an environment with RBAC enabled. 6 | 7 | Kubernetes use [Role-based access control](https://kubernetes.io/docs/reference/access-authn-authz/rbac/), and define below objects: 8 | 9 | - Define 'role', to set permissions for the role: 10 | - `ClusterRole` - to define permissions of a role which is cluster-wide 11 | - `Role` - to define permissions of a role which belongs to specific namespace 12 | 13 | - Define 'role binding', to grant permissions defined in a role to a user or set of users: 14 | - `ClusterRoleBinding` , to grant permissions defined in `ClusterRole` to user 15 | - `RoleBinding` , to grant permissions defined in `Role` to user 16 | 17 | To deploy a BFE Ingress Controller instance in an environment with RBAC enabled, use the `ServiceAccount` that bound to a `ClusterRole`, which has been granted with all permissions BFE Ingress Controller required. 18 | 19 | ## Minimum permission set 20 | 21 | BFE Ingress Controller required at least below permissions: 22 | 23 | - permissions defined for a ClusterRole: 24 | 25 | ```yaml 26 | services, endpoints, secrets, namespaces: get, list, watch 27 | ingresses, ingressclasses: get, list, watch, update 28 | ``` 29 | 30 | ## Example 31 | 32 | ### Example config files 33 | 34 | [controller.yaml](../../examples/controller.yaml) 35 | 36 | [rbac.yaml](../../examples/rbac.yaml) 37 | 38 | ### Define and refer ServiceAccount 39 | 40 | In [controller.yaml](../../examples/controller.yaml) : 41 | 42 | - define a `ServiceAccount` , 43 | - name it as `bfe-ingress-controller` 44 | - define a BFE Ingress Controller instance deployment 45 | - Instance deployed should be linked to ServiceAccount `bfe-ingress-controller` 46 | 47 | ### Define ClusterRole 48 | 49 | In [rbac.yaml](../../examples/rbac.yaml) : 50 | - define a `ClusterRole`, 51 | - name it as `bfe-ingress-controller` 52 | - grant cluster-wide permissions below to it: 53 | 54 | ```yaml 55 | services, endpoints, secrets, namespaces: get, list, watch 56 | ingresses, ingressclasses: get, list, watch, update 57 | ``` 58 | 59 | ### Bind ClusterRole 60 | 61 | In [rbac.yaml](../../examples/rbac.yaml) : 62 | 63 | - define a `ClusterRoleBinding`, 64 | - bind ServiceAccount `bfe-ingress-controller` to ClusterRole `bfe-ingress-controller` 65 | 66 | -------------------------------------------------------------------------------- /docs/images/arch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bfenetworks/ingress-bfe/593a473ce6016f41d99de24722008423e5085322/docs/images/arch.jpg -------------------------------------------------------------------------------- /docs/images/qrcode_for_gh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bfenetworks/ingress-bfe/593a473ce6016f41d99de24722008423e5085322/docs/images/qrcode_for_gh.jpg -------------------------------------------------------------------------------- /docs/zh_cn/FAQ/FAQ.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 1. 问题:BFE Ingress Controller支持哪些启动参数,如何设置 3 | 4 | 支持的启动参数: 5 | 6 | 选项 | 默认值 | 用途| 7 | | --- | --- | --- | 8 | | --namespace
-n | 空字符串 | 设置需监听的ingress所在的namespace,多个namespace 之间用`,`分割。
默认值为空字符串,表示监听所有的 namespace。 | 9 | | --ingress-class| bfe | 指定需监听的Ingress的`kubernetes.io/ingress.class`值。
如不指定,BFE Ingress Controller将监听class设置为bfe的Ingress。 通常无需设置。 | 10 | | --default-backend| 空字符串 | 指定default-backend服务的名字,格式为`namespace/name`。
如指定default-backend,没有命中任何Ingress规则的请求,将被转发到default-backend。 | 11 | 12 | 设置方式: 13 | 在BFE Ingress Controller的部署文件[controller.yaml](../../../examples/controller.yaml)中指定。例如: 14 | ```yaml 15 | ... 16 | containers: 17 | - name: bfe-ingress-controller 18 | image: bfenetworks/bfe-ingress-controller:latest 19 | args: ["-n", "ns1,ns2", "--default-backend", "test/whoami"] 20 | ... 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/zh_cn/README.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress Controller 2 | 3 | BFE Ingress Controller 是基于 [BFE][] 实现的 Kubernetes [Ingress Controller][], 4 | 用于支持在 Kubernetes 中使用 [Ingress][]。 5 | 6 | [文档列表](SUMMARY.md) 7 | 8 | [Ingress Controller]: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/ "Kubernetes" 9 | [Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/ "Kubernetes" 10 | [BFE]: https://github.com/bfenetworks/bfe "Github" 11 | -------------------------------------------------------------------------------- /docs/zh_cn/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [comment]: <> "For user" 4 | * 部署 5 | * [部署指南](deployment.md) 6 | * [基于角色的访问控制(RBAC)](rbac.md) 7 | * 配置 8 | * [配置指南](ingress/basic.md) 9 | * [生效状态](ingress/validate-state.md) 10 | * [路由优先级](ingress/priority.md) 11 | * [路由冲突处理](ingress/conflict.md) 12 | * [TLS 配置](ingress/tls.md) 13 | * [负载均衡](ingress/load-balance.md) 14 | * [重定向](ingress/redirect.md) 15 | * [URL重写](ingress/rewrite.md) 16 | * 配置示例 17 | * [配置文件示例](example/example.md) 18 | * [灰度发布示例](example/canary-release.md) 19 | * [常见问题](FAQ/FAQ.md) 20 | * 附录 21 | * [Annotations](appendix/annotations.md) 22 | --- 23 | 24 | [comment]: <> "For developer" 25 | * [参与贡献](contribute/how-to-contribute.md) 26 | * [如何贡献代码](contribute/contribute-codes.md) 27 | * [代码结构说明](development/source-code-layout.md) 28 | * [核心工作原理](development/core-logic.md) 29 | * [Annotation 开发指南](development/annotation-implement-guide.md) 30 | * [如何贡献文档](contribute/contribute-documents.md) 31 | * [版本发布说明](https://www.bfe-networks.net/zh_cn/development/release_regulation/) 32 | 33 | -------------------------------------------------------------------------------- /docs/zh_cn/contribute/contribute-documents.md: -------------------------------------------------------------------------------- 1 | # 如何贡献文档 2 | ## 文档要求 3 | - 所有内容都应该以 [Markdown][markdown] (GitHub风格)的形式编写,文件以`.md`为后缀 4 | - 如果是新增文档,需将新增的文档名,添加到对应的index文件中([SUMMARY.md](../SUMMARY.md)) 5 | ## 文档开发流程 6 | 7 | 1. 编写文档 8 | 1. 运行预览工具,并预览修改 9 | - [如何使用预览工具](https://www.bfe-networks.net/zh_cn/development/write_doc_guide/#_2) 10 | 1. 提交修改 11 | - 修改文档, 提交修改与PR的步骤可以参考[代码开发流程](contribute-codes.md#代码开发流程) 12 | 13 | > 可参考 BFE [如何贡献文档](https://www.bfe-networks.net/zh_cn/development/write_doc_guide/) 14 | 15 | [markdown]: https://guides.github.com/features/mastering-markdown/ -------------------------------------------------------------------------------- /docs/zh_cn/contribute/how-to-contribute.md: -------------------------------------------------------------------------------- 1 | # 参与贡献 2 | - [如何贡献代码](contribute-codes.md) 3 | - [如何贡献文档](contribute-documents.md) 4 | - [版本发布说明](https://www.bfe-networks.net/zh_cn/development/release_regulation/) 5 | -------------------------------------------------------------------------------- /docs/zh_cn/deployment.md: -------------------------------------------------------------------------------- 1 | # 部署指南 2 | 3 | ## 安装 4 | 可通过下述两种方式中任意一种进行安装: 5 | 6 | * 通过配置文件安装 7 | * 通过helm安装 8 | 9 | ### 配置文件安装 10 | 11 | ``` shell script 12 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/controller-all.yaml 13 | ``` 14 | 15 | - 配置文件中使用了Docker Hub 上的[BFE Ingress Controller镜像](https://hub.docker.com/r/bfenetworks/bfe-ingress-controller)的最新版本。如需使用指定版本的镜像,修改配置文件,指定镜像版本。 16 | - 权限配置具体说明可参见[RBAC 文件编写指南](rbac.md)。 17 | 18 | ### Helm安装 19 | 20 | ``` 21 | helm upgrade --install bfe-ingress-controller bfe-ingress-controller --repo https://bfenetworks.github.io/ingress-bfe --namespace ingress-bfe --create-namespace 22 | ``` 23 | - 要求helm3 24 | 25 | ## 测试 26 | * 创建测试服务whoami 27 | ``` shell script 28 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/whoami.yaml 29 | ``` 30 | 31 | * 创建k8s Ingress资源,验证消息路由 32 | ``` shell script 33 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/ingress.yaml 34 | ``` 35 | 36 | * 创建k8s Ingress资源,验证消息路由 (kubernetes version >=1.19) 37 | ``` shell script 38 | kubectl apply -f https://raw.githubusercontent.com/bfenetworks/ingress-bfe/develop/examples/ingress-v1.19.yaml 39 | 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /docs/zh_cn/development/core-logic.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress Controller 工作原理 2 | 3 | ## 核心处理逻辑 4 | 5 | > 前置知识 6 | > - 什么是 [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) 7 | > - 什么是 [Ingress Controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) 8 | 9 | ![arch](../../images/arch.jpg) 10 | 11 | BFE Ingress Controller 的核心处理逻辑是: 12 | 1. 监听获取 k8s 集群中的 Ingress 资源 13 | 2. 解析 Ingress 资源中定义的配置逻辑,生成对应的 BFE 配置 14 | 3. 使新生成的 BFE 配置在 BFE进程中生效 15 | 16 | ## 如何实现 Ingress 资源的监听 17 | 18 | 通过 [Kubernetes controller-runtime][] 框架实现: 19 | 1. 创建 Manager,Manager 内部维护了 Client、Cache 和 Schema 等 20 | 2. 创建 Reconciler,并实现回调逻辑 21 | 3. 使用 Builder 模式创建 Controller,并指定监听 Ingress 资源和对应的 Reconcile 22 | 4. 启动 Manager 23 | 24 | ## BFE配置如何定义 25 | 26 | BFE 的配置定义可以通过以下方式获得: 27 | 1. 官网文档:[配置概述][](主要关注动态配置) 28 | 2. BFE 源码: bfe/[bfe_modules][]/mod_\*/\*_load.go 29 | 30 | 官网更新可能存在延迟,以源代码为准。 31 | 32 | > 常见动态配置: 33 | > - 流量路由配置 34 | > - [域名规则配置](https://www.bfe-networks.net/zh_cn/configuration/server_data_conf/host_rule.data/) 35 | > - [分流规则配置](https://www.bfe-networks.net/zh_cn/configuration/server_data_conf/route_rule.data/) 36 | > - 负载均衡配置 37 | > - [子集群负载均衡配置](https://www.bfe-networks.net/zh_cn/configuration/cluster_conf/gslb.data/) 38 | > - 接入协议配置 39 | > - [TLS协议配置](https://www.bfe-networks.net/zh_cn/configuration/tls_conf/tls_rule_conf.data/) 40 | > - 扩展模块配置 41 | > - [mod_header 配置](https://www.bfe-networks.net/zh_cn/modules/mod_header/mod_header/) 42 | > - [mod_redirect 配置](https://www.bfe-networks.net/zh_cn/modules/mod_redirect/mod_redirect/) 43 | > - [mod_rewrite 配置](https://www.bfe-networks.net/zh_cn/modules/mod_rewrite/mod_rewrite/) 44 | 45 | ## BFE配置如何生效 46 | 47 | 通过 BFE [配置热加载][],完成在 BFE 不停机的情况下更新动态配置。 48 | 49 | [Kubernetes controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime 50 | [配置概述]: https://www.bfe-networks.net/zh_cn/configuration/config/ 51 | [bfe_modules]: https://github.com/bfenetworks/bfe/tree/develop/bfe_modules 52 | [配置热加载]: https://www.bfe-networks.net/zh_cn/operation/reload/ -------------------------------------------------------------------------------- /docs/zh_cn/development/source-code-layout.md: -------------------------------------------------------------------------------- 1 | # BFE Ingress 源代码框架 2 | 3 | ```shell 4 | . 5 | ├── .github : Github 工作流目录 6 | ├── build : 编译脚本目录 7 | ├── charts : BFE Ingress Controller 的 Helm Charts目录 8 | ├── cmd 9 | │   └── ingress-controller : 主程序目录 10 | ├── docs : 中英文用户文档及其素材目录 11 | ├── examples : k8s 资源描述文件示例目录 12 | ├── internal : 核心源码目录 13 | │   ├── bfeConfig : BFE Ingress Controller 配置选项定义代码 14 | │   ├── controllers : k8s 集群交互相关代码,主要包含各资源的controller的实现以及reconcile逻辑 15 | │   └── option : BFE 配置相关代码,主要包含各 BFE 配置的生成和热加载逻辑 16 | ├── scripts : 镜像依赖的脚本目录 17 | ├── CHANGELOG.md : 版本修改日志 18 | ├── Dockerfile : 构建镜像的指令文件 19 | ├── LICENSE : License 协议 20 | ├── Makefile : 程序编译与镜像制作的指令文件 21 | ├── SECURITY.md : 安全策略 22 | ├── VERSION : 程序版本 23 | ├── go.mod : Go 语言依赖管理文件 24 | └── go.sum : Go 语言依赖管理文件 25 | ``` 26 | 27 | ## 核心代码 28 | - /[internal][]: 核心源码目录 29 | - /[option][]: BFE Ingress Controller 配置选项定义代码 30 | - /[controllers][]: k8s 集群交互相关代码,主要包含各资源的controller的实现以及reconcile逻辑 31 | - /[bfeConfig][]: BFE 配置相关代码,主要包含各 BFE 配置的生成和热加载逻辑 32 | 33 | ## 持续集成 34 | 35 | ### 工作流 36 | - /[.github][]: Github 工作流目录 37 | - /[Makefile][]: 程序编译与镜像制作的指令文件 38 | 39 | ### 程序编译 40 | - /cmd/[ingress-controller][]: 主程序目录 41 | - /[VERSION][]: 程序版本 42 | - /[build][]: 编译脚本目录 43 | - /[go.mod][]: Go 语言依赖管理文件 44 | - /[go.sum][]: Go 语言依赖管理文件 45 | 46 | ### 镜像制作 47 | - /[Dockerfile][]: 构建镜像的指令文件 48 | - /[scripts][]: 镜像依赖的脚本目录(如镜像启动脚本) 49 | 50 | ## Helm 支持 51 | - /[charts][]: BFE Ingress Controller 的 Helm Charts 52 | 53 | ## 项目文档 54 | - /[docs][]: 中英文用户文档及其素材目录 55 | - /[examples][]: k8s 资源描述文件示例目录 56 | - /[CHANGELOG.md][]: 版本修改日志 57 | - /[LICENSE][]: License 协议 58 | - /[SECURITY.md][]: 安全策略 59 | 60 | [.github]: ../../../.github 61 | [build]: ../../../build 62 | [charts]: ../../../charts 63 | [ingress-controller]: ../../../cmd/ingress-controller 64 | [docs]: ../../../docs 65 | [examples]: ../../../examples 66 | [internal]: ../../../internal 67 | [bfeConfig]: ../../../internal/bfeConfig 68 | [controllers]: ../../../internal/controllers 69 | [go.mod]: ../../../go.mod 70 | [go.sum]: ../../../go.sum 71 | [option]: ../../../internal/option 72 | [scripts]: ../../../scripts 73 | [CHANGELOG.md]: ../../../CHANGELOG.md 74 | [Dockerfile]: ../../../Dockerfile 75 | [LICENSE]: ../../../LICENSE 76 | [Makefile]: ../../../Makefile 77 | [SECURITY.md]: ../../../SECURITY.md 78 | [VERSION]: ../../../VERSION -------------------------------------------------------------------------------- /docs/zh_cn/example/canary-release.md: -------------------------------------------------------------------------------- 1 | # 支持灰度发布 2 | 3 | ## 说明 4 | BFE-Ingress-controller支持通过配置`Annotation`,实现基于`Header/Cookie`的灰度发布功能。 5 | 6 | ## 配置示例 7 | * 初始的ingress配置如下,请求转发到服务`service`: 8 | ```yaml 9 | kind: Ingress 10 | apiVersion: networking.k8s.io/v1beta1 11 | metadata: 12 | name: "original" 13 | namespace: production 14 | 15 | spec: 16 | rules: 17 | - host: example.net 18 | http: 19 | paths: 20 | - path: /bar 21 | pathType: Exact 22 | backend: 23 | serviceName: service 24 | servicePort: 80 25 | ``` 26 | 27 | * 做灰度发布,对特定请求,转发到新的服务`service2`。 28 | * 为实现上述目的,创建一个新的ingress,在annotations中包含特定请求的header或cookie的信息。 29 | ```yaml 30 | kind: Ingress 31 | apiVersion: networking.k8s.io/v1beta1 32 | metadata: 33 | name: "greyscale" 34 | namespace: production 35 | annotations: 36 | bfe.ingress.kubernetes.io/router.cookie: "key: value" 37 | bfe.ingress.kubernetes.io/router.header: "Key: Value" 38 | 39 | spec: 40 | rules: 41 | - host: example.net 42 | http: 43 | paths: 44 | - path: /bar 45 | pathType: Exact 46 | backend: 47 | serviceName: service2 48 | servicePort: 80 49 | 50 | ``` 51 | * 基于上面的配置,BFE对 52 | 1. 满足 `host == example.net && path == /bar && cookie[key] == value && Header[Key] == Value`, 53 | 则转发到`service-new`集群 54 | 1. 仅满足 `host == example.net && path == /bar`, 55 | 仍转发到`service`集群 56 | -------------------------------------------------------------------------------- /docs/zh_cn/example/example.md: -------------------------------------------------------------------------------- 1 | # 配置文件示例 2 | 3 | ## deployment 4 | | 程序 | 文件 | 说明 | 5 | | ---- | ---- | ---- | 6 | | bfe-ingress-controller | [controller.yaml](../../../examples/controller.yaml)| 用于 bfe ingress controller 的部署| 7 | | 示例后端服务 whoami | [whoami.yaml](../../../examples/whoami.yaml) | 用于示例服务(whoami)的部署 | 8 | 9 | ## ingress 10 | | 文件 | 说明 | 11 | | ---- | ---- | 12 | | [ingress.yaml](../../../examples/ingress.yaml) | 用于配置示例服务(whoami)流量的路由 | 13 | 14 | ## rbac 15 | | 文件 | 说明 | 16 | | ---- | ---- | 17 | | [rbac.yaml](../../../examples/rbac.yaml) | 用于授予 bfe ingress controller 的权限 | 18 | 19 | -------------------------------------------------------------------------------- /docs/zh_cn/example/example.md.orig: -------------------------------------------------------------------------------- 1 | # 部署配置示例 2 | 3 | ## deployment 4 | | 程序 | 文件 | 说明 | 5 | | ---- | ---- | ---- | 6 | | bfe ingress controller | [controller.yaml](../../../examples/controller.yaml)| 用于 bfe ingress controller 的部署| 7 | | 示例后端服务 whoami | [whoami.yaml](../../../examples/whoami.yaml) | 用于示例服务(whoami)的部署 | 8 | 9 | ## ingress 10 | | 文件 | 说明 | 11 | | ---- | ---- | 12 | | [ingress.yaml](../../../examples/ingress.yaml) | 用于配置示例服务(whoami)的流量调度 | 13 | 14 | ## rbac 15 | | 文件 | 说明 | 16 | | ---- | ---- | 17 | | [rbac.yaml](../../../examples/rbac.yaml) | 用于授予 bfe ingress controller 的权限 | 18 | 19 | -------------------------------------------------------------------------------- /docs/zh_cn/ingress/conflict.md: -------------------------------------------------------------------------------- 1 | # 路由冲突处理 2 | 3 | ## 路由冲突的定义 4 | 5 | 当Ingress配置最终生成包含相同的Ingress规则(Host、Path、高级匹配条件均完全相同)的Ingress资源的情况下,会产生路由冲突。 6 | 7 | ## 处理原则:最先创建的生效 8 | 9 | 对存在路由冲突的多个Ingress资源,BFE Ingress Controller将按照"最先创建的生效"的原则,仅使最早被创建的Ingress资源生效。 10 | 11 | 在同一个namespace之间,或在多个namespace之间的路由冲突,均按照此原则处理。 12 | 13 | 对于因路由冲突导致的没有在BFE Ingress Controller中生效的Ingress资源,可在[生效状态](validate-state.md)反馈的Annotation中查找相应的错误消息。 14 | 15 | ## 示例 16 | 17 | ```yaml 18 | apiVersion: networking.k8s.io/v1beta1 19 | kind: Ingress 20 | metadata: 21 | name: ingress-A 22 | namespace: production 23 | annotations: 24 | kubernetes.io/ingress.class: bfe 25 | spec: 26 | rules: 27 | - host: example.foo.com 28 | http: 29 | paths: 30 | - path: /foo 31 | pathType: Prefix 32 | backend: 33 | serviceName: service1 34 | servicePort: 80 35 | --- 36 | apiVersion: networking.k8s.io/v1beta1 37 | kind: Ingress 38 | metadata: 39 | name: ingress-B 40 | namespace: production 41 | annotations: 42 | kubernetes.io/ingress.class: bfe 43 | spec: 44 | rules: 45 | - host: example.foo.com 46 | http: 47 | paths: 48 | - path: /foo 49 | pathType: Prefix 50 | backend: 51 | serviceName: service2 52 | servicePort: 80 53 | 54 | ``` 55 | 在以上配置中,ingress-A和ingress-B冲突,ingress-A先于ingress-B创建,所以最终仅ingress-A生效。 56 | 57 | ## 生效状态反馈 58 | 若一个Ingress资源因路由冲突而被忽略(未生效),生效状态反馈回写后,对于生效状态的注解的status会被设为“fail”,message中会包含和哪个Ingress资源发生了冲突。 59 | 60 | 在前面的示例中,ingress-B的生效状态的注解将会如下面所示: 61 | 62 | 63 | ```yaml 64 | metadata: 65 | annotations: 66 | bfe.ingress.kubernetes.io/bfe-ingress-status: | 67 | {"status": "fail", "message": "conflict with production/ingress-A"} 68 | ``` 69 | 70 | 更多生效状态的说明见[生效状态](validate-state.md)。 71 | 72 | -------------------------------------------------------------------------------- /docs/zh_cn/ingress/load-balance.md: -------------------------------------------------------------------------------- 1 | # 多Service之间的负载均衡 2 | ## 说明 3 | 4 | BFE Ingress Controller支持在提供相同服务的多个Service(为便于理解,在BFE Ingress文档中称其为子服务,Sub-Service)之间按权重进行负载均衡。 5 | 6 | 配置方式 7 | 8 | BFE Ingress Controller通过`注解`(`Annotation`)的方式支持多个Sub-Service之间的负载均衡。配置方式为: 9 | 10 | - 在`annotations`中 11 | 12 | - 为多个Sub-Service分别指定流量分配权重 13 | 14 | - 为它们提供的服务设置一个Service名称 15 | 16 | - 格式如下: 17 | 18 | ``` yaml 19 | bfe.ingress.kubernetes.io/balance.weight: '{"service": {"sub-service1":80, "sub-service2":20}}' 20 | ``` 21 | 22 | - 在`rules`中 23 | 24 | - 将backend的serviceName设置为注解中设置的Service名称,并指定servicePort 25 | 26 | ## 示例 27 | 28 | ```yaml 29 | apiVersion: networking.k8s.io/v1beta1 30 | kind: Ingress 31 | metadata: 32 | name: tls-example-ingress 33 | annotations: 34 | kubernetes.io/ingress.class: bfe 35 | bfe.ingress.kubernetes.io/balance.weight: '{"service": {"service1":80, "service2":20}}' 36 | spec: 37 | tls: 38 | - hosts: 39 | - https-example.foo.com 40 | secretName: testsecret-tls 41 | rules: 42 | - host: https-example.foo.com 43 | http: 44 | paths: 45 | - path: / 46 | pathType: Prefix 47 | backend: 48 | serviceName: service 49 | servicePort: 80 50 | ``` -------------------------------------------------------------------------------- /docs/zh_cn/ingress/redirect.md: -------------------------------------------------------------------------------- 1 | # 重定向配置 2 | 3 | BFE Ingress Controller支持通过在声明在Ingress中使用注解(Annotations)的方式,对当前Ingress匹配的流量进行重定向。 4 | 5 | ## 配置方式 6 | 7 | Ingress 资源内 8 | 9 | - `spec.rules`定义路由规则 10 | - `metadata.annotations`定义对符合路由规则的流量,重定向响应的行为 11 | 12 | 参考格式: 13 | 14 | ```yaml 15 | metadata: 16 | annotations: 17 | bfe.ingress.kubernetes.io/redirect.url-set: "https://www.baidu.com" 18 | spec: 19 | rules: 20 | - ... 21 | ``` 22 | 23 | ```yaml 24 | metadata: 25 | annotations: 26 | bfe.ingress.kubernetes.io/redirect.scheme-set: https 27 | bfe.ingress.kubernetes.io/redirect.status: 301 28 | spec: 29 | rules: 30 | - ... 31 | ``` 32 | 33 | ## 重定向Location 34 | 35 | BFE Ingress Controller支持使用4种方式配置重定向目标URL,并且每个Ingress对象仅允许使用一种配置方式。 36 | 37 | ### 静态URL 38 | 39 | 通过设置 `bfe.ingress.kubernetes.io/redirect.url-set`,配置静态重定向目标URL。 40 | 41 | 例如: 42 | 43 | ```yaml 44 | bfe.ingress.kubernetes.io/redirect.target: "https://www.baidu.com" 45 | ``` 46 | 47 | 对应示例 48 | 49 | - Request: http://host/path?query-key=value 50 | - Response: https://www.baidu.com 51 | 52 | ### 从Query中获得URL 53 | 54 | 从请求URL的指定`Query`值中获取重定向目标URL。通过设置`bfe.ingress.kubernetes.io/redirect.url-from-query`指定Query名。 55 | 56 | 例如: 57 | 58 | ```yaml 59 | bfe.ingress.kubernetes.io/redirect.url-from-query: url 60 | ``` 61 | 62 | 对应示例 63 | 64 | - Request: https://host/path?url=https%3A%2F%2Fwww.baidu.com 65 | - Response: https://www.baidu.com 66 | 67 | ### 添加前缀 68 | 69 | 重定向目标URL由指定前缀和请求URL的`Path`拼接而成。通过`bfe.ingress.kubernetes.io/redirect.url-prefix-add`设置拼接的前缀字符串。 70 | 71 | 例如: 72 | 73 | ```yaml 74 | bfe.ingress.kubernetes.io/redirect.url-prefix-add: "http://www.baidu.com/redirect" 75 | ``` 76 | 77 | 对应示例 78 | 79 | - Request: https://host/path?query-key=value 80 | - Response: http://www.baidu.com/redirect/path?query-key=value 81 | 82 | ### 设置Scheme 83 | 84 | 修改请求的协议。目前仅支持HTTP和HTTPS。 85 | 86 | 例如: 87 | 88 | ```yaml 89 | bfe.ingress.kubernetes.io/redirect.scheme-set: http 90 | ``` 91 | 92 | 对应示例 93 | 94 | - Request: https://host/path?query-key=value 95 | - Response: http://host/path?query-key=value 96 | 97 | ## 重定向状态码 98 | 99 | 默认情况下,重定向Response的状态码为302。也可以通过设置 `bfe.ingress.kubernetes.io/redirect.response-status`,手动指定重定向的状态码。 100 | 101 | 例如: 102 | 103 | ```yaml 104 | bfe.ingress.kubernetes.io/redirect.response-status: 301 105 | ``` 106 | 107 | 目前支持的重定向状态码有:301、302、303、307、308。 -------------------------------------------------------------------------------- /docs/zh_cn/ingress/tls.md: -------------------------------------------------------------------------------- 1 | # TLS 配置 2 | BFE Ingress Controller按照Kubernetes原生定义的方式来管理TLS的证书和密钥。 3 | 4 | TLS的证书和密钥通过Secrets进行保存,示例如下: 5 | 6 | **Secret配置** 7 | 8 | ```yaml 9 | apiVersion: v1 10 | kind: Secret 11 | metadata: 12 | name: testsecret-tls 13 | namespace: default 14 | data: 15 | tls.crt: base64 encoded cert 16 | tls.key: base64 encoded key 17 | type: kubernetes.io/tls 18 | ``` 19 | **Ingress配置** 20 | ```yaml 21 | apiVersion: networking.k8s.io/v1beta1 22 | kind: Ingress 23 | metadata: 24 | name: tls-example-ingress 25 | annotations: 26 | kubernetes.io/ingress.class: bfe 27 | spec: 28 | tls: 29 | - hosts: 30 | - https-example.foo.com 31 | secretName: testsecret-tls 32 | rules: 33 | - host: https-example.foo.com 34 | http: 35 | paths: 36 | - path: / 37 | pathType: Prefix 38 | backend: 39 | serviceName: service1 40 | servicePort: 80 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/zh_cn/ingress/validate-state.md: -------------------------------------------------------------------------------- 1 | # 生效状态 2 | 3 | ## 生效状态反馈 4 | Ingress配置的合法性检查是一个异步过程,检查结果在配置生效的过程中才能返回。 5 | 6 | 为了能给用户反馈当前Ingress是否生效,BFE Ingress Controller会将Ingress的实际生效状态回写到Ingress的一个Annotation当中。 7 | **BFE Ingress Controller的状态Annotation定义如下:** 8 | 9 | ```yaml 10 | #bfe.ingress.kubernetes.io/bfe-ingress-status为BFE-Ingress预留的Annotation key, 11 | #用于BFE-Ingress反馈生效状态 12 | # status: 表示当前ingress是否合法, 取值为:success -> ingress合法, error -> ingress不合法 13 | # message: 当ingress不合法的情况下,message记录错误详细原因。 14 | bfe.ingress.kubernetes.io/bfe-ingress-status: {"status": "", "message": ""} 15 | ``` 16 | ## 示例 17 | 18 | 下面是BFE-Ingress生效状态反馈的一个示例,展示发生路由冲突的两个Ingress资源的生效状态反馈。 19 | `Ingress1`和`Ingress2`的路由规则完全一样(`Host:example.net, Path:/bar`)。 20 | 21 | ```yaml 22 | kind: Ingress 23 | apiVersion: networking.k8s.io/v1beta1 24 | metadata: 25 | name: "ingress1" 26 | namespace: production 27 | annotations: 28 | kubernetes.io/ingress.class: bfe 29 | spec: 30 | rules: 31 | - host: example.net 32 | http: 33 | paths: 34 | - path: /bar 35 | backend: 36 | serviceName: service1 37 | servicePort: 80 38 | --- 39 | kind: Ingress 40 | apiVersion: networking.k8s.io/v1beta1 41 | metadata: 42 | name: "ingress2" 43 | namespace: production 44 | annotations: 45 | kubernetes.io/ingress.class: bfe 46 | spec: 47 | rules: 48 | - host: example.net 49 | http: 50 | paths: 51 | - path: /bar 52 | backend: 53 | serviceName: service2 54 | servicePort: 80 55 | ``` 56 | 根据[路由冲突处理原则](conflict.md),`Ingress1`将生效,而`Ingress2`将被忽略。状态回写反馈后,`Ingress1`的状态为success,而`Ingress2`的状态为fail。 57 | ```yaml 58 | kind: Ingress 59 | apiVersion: networking.k8s.io/v1beta1 60 | metadata: 61 | name: "ingress1" 62 | namespace: production 63 | annotations: 64 | kubernetes.io/ingress.class: bfe 65 | bfe.ingress.kubernetes.io/bfe-ingress-status: {"status": "success"} 66 | spec: 67 | rules: 68 | - host: example.net 69 | http: 70 | paths: 71 | - path: /bar 72 | backend: 73 | serviceName: service1 74 | servicePort: 80 75 | --- 76 | kind: Ingress 77 | apiVersion: networking.k8s.io/v1beta1 78 | metadata: 79 | name: "ingress2" 80 | namespace: production 81 | annotations: 82 | kubernetes.io/ingress.class: bfe 83 | bfe.ingress.kubernetes.io/bfe-ingress-status: | 84 | {"status": "fail", "message": "conflict with production/ingress1"} 85 | spec: 86 | rules: 87 | - host: example.net 88 | http: 89 | paths: 90 | - path: /bar 91 | backend: 92 | serviceName: service2 93 | servicePort: 80 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/zh_cn/rbac.md: -------------------------------------------------------------------------------- 1 | # 基于角色的访问控制(RBAC) 2 | 3 | ## 说明 4 | 5 | 本文档说明如何在启用了RBAC的环境中部署BFE Ingress controller。 6 | 7 | Kubernetes 中,采用[基于角色的访问控制](https://kubernetes.io/docs/reference/access-authn-authz/rbac/),使用了如下对象: 8 | 9 | - 通过定义角色,配置角色相关的权限: 10 | - `ClusterRole` - 定义适用于整个集群的角色及其所具有的权限 11 | - `Role` - 定义适用于特定名称空间的角色及其所具有的权限 12 | 13 | - 通过配置角色绑定,可以将角色中定义的权限赋予一个或者一组用户 14 | - `ClusterRoleBinding` ,赋予用户`ClusterRole`角色中定义的权限 15 | - `RoleBinding` ,赋予用户`ClusterRole`角色中定义的权限 16 | 17 | 在启用了RBAC的环境中部署BFE Ingress Controller,应该将其关联到一个`ServiceAccount`,且该`ServiceAccount`需要绑定到具有BFE Ingress Controller所需权限的`ClusterRole`。 18 | 19 | ## 最小权限集 20 | 21 | BFE Ingress Controller所需要的权限至少应该包括: 22 | 23 | - 具有ClusterRole中定义的如下权限: 24 | 25 | ```yaml 26 | services, endpoints, secrets, namespaces: get, list, watch 27 | ingresses, ingressclasses: get, list, watch, update 28 | ``` 29 | 30 | ## 示例 31 | 32 | ### 示例配置文件controller 33 | 34 | [controller.yaml](../../examples/controller.yaml) 35 | 36 | [rbac.yaml](../../examples/rbac.yaml) 37 | 38 | ### 创建并引用ServiceAccount 39 | 40 | 在 [controller.yaml](../../examples/controller.yaml) 中: 41 | 42 | - 定义一个 `ServiceAccount` , 43 | - 命名为`bfe-ingress-controller` 44 | - 定义了BFE Ingress Controller的部署 45 | - 部署的实例关联 ServiceAccount `bfe-ingress-controller` 46 | 47 | ### 创建ClusterRole 48 | 49 | 在 [rbac.yaml](../../examples/rbac.yaml) 中: 50 | - 定义了一个`ClusterRole`, 51 | - 命名为`bfe-ingress-controller` 52 | - 定义了它具有如下的集群权限(适用于整个集群): 53 | 54 | ```yaml 55 | services, endpoints, secrets, namespaces: get, list, watch 56 | ingresses, ingressclasses: get, list, watch, update 57 | ``` 58 | 59 | ### 绑定ClusterRole 60 | 61 | 在 [rbac.yaml](../../examples/rbac.yaml) 中: 62 | 63 | - 定义了一个`ClusterRoleBinding`, 64 | - 将 ServiceAccount `bfe-ingress-controller` 绑定到 ClusterRole `bfe-ingress-controller` 65 | 66 | -------------------------------------------------------------------------------- /examples/controller.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ingress-bfe 5 | labels: 6 | app.kubernetes.io/name: bfe-ingress-controller 7 | app.kubernetes.io/instance: bfe-ingress-controller 8 | 9 | --- 10 | apiVersion: v1 11 | kind: ServiceAccount 12 | metadata: 13 | name: bfe-ingress-controller 14 | namespace: ingress-bfe 15 | labels: 16 | app.kubernetes.io/name: bfe-ingress-controller 17 | app.kubernetes.io/instance: bfe-ingress-controller 18 | 19 | --- 20 | kind: Deployment 21 | apiVersion: apps/v1 22 | metadata: 23 | name: bfe-ingress-controller 24 | namespace: ingress-bfe 25 | labels: 26 | app.kubernetes.io/name: bfe-ingress-controller 27 | app.kubernetes.io/instance: bfe-ingress-controller 28 | 29 | spec: 30 | replicas: 1 31 | selector: 32 | matchLabels: 33 | app.kubernetes.io/name: bfe-ingress-controller 34 | app.kubernetes.io/instance: bfe-ingress-controller 35 | template: 36 | metadata: 37 | labels: 38 | app.kubernetes.io/name: bfe-ingress-controller 39 | app.kubernetes.io/instance: bfe-ingress-controller 40 | spec: 41 | serviceAccountName: bfe-ingress-controller 42 | containers: 43 | - name: bfe-ingress-controller 44 | image: bfenetworks/bfe-ingress-controller:latest 45 | ports: 46 | - name: http 47 | containerPort: 8080 48 | - name: https 49 | containerPort: 8443 50 | - name: monitor 51 | containerPort: 8421 52 | 53 | --- 54 | apiVersion: v1 55 | kind: Service 56 | metadata: 57 | name: bfe-controller-service 58 | namespace: ingress-bfe 59 | labels: 60 | app.kubernetes.io/name: bfe-ingress-controller 61 | app.kubernetes.io/instance: bfe-ingress-controller 62 | spec: 63 | type: NodePort 64 | selector: 65 | app.kubernetes.io/name: bfe-ingress-controller 66 | app.kubernetes.io/instance: bfe-ingress-controller 67 | ports: 68 | - name: http 69 | port: 8080 70 | targetPort: 8080 71 | - name: https 72 | port: 8443 73 | targetPort: 8443 74 | -------------------------------------------------------------------------------- /examples/ingress-v1.19.yaml: -------------------------------------------------------------------------------- 1 | kind: Ingress 2 | apiVersion: networking.k8s.io/v1 3 | metadata: 4 | name: ingress-test 5 | namespace: ingress-bfe 6 | annotations: 7 | kubernetes.io/ingress.class: bfe 8 | 9 | spec: 10 | rules: 11 | - host: "foo.com" 12 | http: 13 | paths: 14 | - path: /whoami 15 | pathType: Prefix 16 | backend: 17 | service: 18 | name: whoami 19 | port: 20 | number: 80 21 | -------------------------------------------------------------------------------- /examples/ingress.yaml: -------------------------------------------------------------------------------- 1 | kind: Ingress 2 | apiVersion: networking.k8s.io/v1beta1 3 | metadata: 4 | name: ingress-test 5 | namespace: ingress-bfe 6 | annotations: 7 | kubernetes.io/ingress.class: bfe 8 | 9 | spec: 10 | rules: 11 | - host: "foo.com" 12 | http: 13 | paths: 14 | - path: /whoami 15 | backend: 16 | serviceName: whoami 17 | servicePort: 80 18 | -------------------------------------------------------------------------------- /examples/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: ClusterRole 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | name: bfe-ingress-controller 6 | labels: 7 | app.kubernetes.io/name: bfe-ingress-controller 8 | app.kubernetes.io/instance: bfe-ingress-controller 9 | rules: 10 | - apiGroups: 11 | - "" 12 | resources: 13 | - services 14 | - endpoints 15 | - secrets 16 | - namespaces 17 | verbs: 18 | - get 19 | - list 20 | - watch 21 | - apiGroups: 22 | - "" 23 | resources: 24 | - events 25 | verbs: 26 | - create 27 | - patch 28 | - apiGroups: 29 | - extensions 30 | resources: 31 | - ingresses 32 | - ingressclasses 33 | verbs: 34 | - get 35 | - list 36 | - watch 37 | - update 38 | - patch 39 | - apiGroups: 40 | - networking.k8s.io 41 | resources: 42 | - ingresses 43 | - ingressclasses 44 | verbs: 45 | - get 46 | - list 47 | - watch 48 | - update 49 | - patch 50 | 51 | --- 52 | kind: ClusterRoleBinding 53 | apiVersion: rbac.authorization.k8s.io/v1 54 | metadata: 55 | name: bfe-ingress-controller 56 | labels: 57 | app.kubernetes.io/name: bfe-ingress-controller 58 | app.kubernetes.io/instance: bfe-ingress-controller 59 | roleRef: 60 | apiGroup: rbac.authorization.k8s.io 61 | kind: ClusterRole 62 | name: bfe-ingress-controller 63 | subjects: 64 | - kind: ServiceAccount 65 | name: bfe-ingress-controller 66 | namespace: ingress-bfe 67 | -------------------------------------------------------------------------------- /examples/whoami.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | name: whoami 5 | namespace: ingress-bfe 6 | labels: 7 | app.kubernetes.io/name: whoami 8 | app.kubernetes.io/instance: whoami 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/name: whoami 14 | app.kubernetes.io/instance: whoami 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: whoami 19 | app.kubernetes.io/instance: whoami 20 | spec: 21 | containers: 22 | - name: containouswhoami 23 | image: containous/whoami 24 | ports: 25 | - containerPort: 80 26 | 27 | --- 28 | apiVersion: v1 29 | kind: Service 30 | metadata: 31 | name: whoami 32 | namespace: ingress-bfe 33 | 34 | spec: 35 | ports: 36 | - name: http 37 | port: 80 38 | selector: 39 | app.kubernetes.io/name: whoami 40 | app.kubernetes.io/instance: whoami 41 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bfenetworks/ingress-bfe 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/bfenetworks/bfe v1.5.0 7 | github.com/jwangsadinata/go-multimap v0.0.0-20190620162914-c29f3d7f33b6 8 | k8s.io/api v0.21.2 9 | k8s.io/apimachinery v0.21.2 10 | k8s.io/client-go v0.21.2 11 | k8s.io/klog/v2 v2.9.0 //indirect 12 | sigs.k8s.io/controller-runtime v0.9.2 13 | ) 14 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/annotation.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package annotations 15 | 16 | import ( 17 | netv1beta1 "k8s.io/api/networking/v1beta1" 18 | ) 19 | 20 | const ( 21 | BfeAnnotationPrefix = "bfe.ingress.kubernetes.io/" 22 | 23 | IngressClassKey = netv1beta1.AnnotationIngressClass 24 | IsDefaultIngressClass = netv1beta1.AnnotationIsDefaultIngressClass 25 | ) 26 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/balance.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package annotations 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | ) 20 | 21 | const ( 22 | WeightKey = "balance.weight" 23 | WeightAnnotation = BfeAnnotationPrefix + WeightKey 24 | ) 25 | 26 | // ServicesWeight define struct of annotation "balance.weight" 27 | // example: {"service": {"service1":80, "service2":20}} 28 | type ServicesWeight map[string]int 29 | type Balance map[string]ServicesWeight 30 | 31 | // GetBalance parse annotation "balance.weight" 32 | func GetBalance(annotations map[string]string) (Balance, error) { 33 | value, ok := annotations[WeightAnnotation] 34 | if !ok { 35 | return nil, nil 36 | } 37 | 38 | var lb = make(Balance) 39 | err := json.Unmarshal([]byte(value), &lb) 40 | if err != nil { 41 | return nil, fmt.Errorf("annotation %s is illegal, error: %s", WeightAnnotation, err) 42 | } 43 | 44 | // check whether weight sum > 0 45 | for _, services := range lb { 46 | sum := 0 47 | for _, weight := range services { 48 | if weight < 0 { 49 | return nil, fmt.Errorf("weight of load balance service should >= 0") 50 | } 51 | sum += weight 52 | } 53 | if sum == 0 { 54 | return nil, fmt.Errorf("sum of all load balance service weight should > 0") 55 | } 56 | } 57 | return lb, nil 58 | } 59 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/priority.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package annotations 15 | 16 | const ( 17 | PriorityBasic = 10 18 | PriorityHeader = 20 19 | PriorityCookie = 30 20 | PriorityCookieHeader = 40 21 | ) 22 | 23 | func Priority(annotations map[string]string) int { 24 | _, ok1 := annotations[CookieAnnotation] 25 | _, ok2 := annotations[HeaderAnnotation] 26 | 27 | if ok1 && ok2 { 28 | return PriorityCookieHeader 29 | } else if ok1 { 30 | return PriorityCookie 31 | } else if ok2 { 32 | return PriorityHeader 33 | } else { 34 | return PriorityBasic 35 | } 36 | } 37 | 38 | func Equal(annotations1, annotations2 map[string]string) bool { 39 | if annotations1 == nil && annotations2 == nil { 40 | return true 41 | } 42 | 43 | return annotations1[CookieAnnotation] == annotations2[CookieAnnotation] && 44 | annotations1[HeaderAnnotation] == annotations2[HeaderAnnotation] 45 | } 46 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/redirect.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package annotations 16 | 17 | import ( 18 | "errors" 19 | "strconv" 20 | ) 21 | 22 | const ( 23 | redirectAnnotationPrefix = BfeAnnotationPrefix + "redirect." 24 | defaultRedirectResponseStatusCode = 302 25 | ) 26 | 27 | // the annotations related to how to set the location in the redirection response's header 28 | const ( 29 | RedirectURLSetAnnotation = redirectAnnotationPrefix + "url-set" 30 | RedirectURLFromQueryAnnotation = redirectAnnotationPrefix + "url-from-query" 31 | RedirectURLPrefixAddAnnotation = redirectAnnotationPrefix + "url-prefix-add" 32 | RedirectSchemeSetSetAnnotation = redirectAnnotationPrefix + "scheme-set" 33 | ) 34 | 35 | // RedirectResponseStatusAnnotation is used to set the status code of the redirection response manually 36 | const RedirectResponseStatusAnnotation = redirectAnnotationPrefix + "response-status" 37 | 38 | // GetRedirectAction try to parse the cmd and the param of the redirection action from the annotations 39 | func GetRedirectAction(annotations map[string]string) (cmd, param string, err error) { 40 | switch { 41 | case annotations[RedirectURLSetAnnotation] != "": 42 | cmd, param = "URL_SET", annotations[RedirectURLSetAnnotation] 43 | 44 | case annotations[RedirectURLFromQueryAnnotation] != "": 45 | cmd, param = "URL_FROM_QUERY", annotations[RedirectURLFromQueryAnnotation] 46 | 47 | case annotations[RedirectURLPrefixAddAnnotation] != "": 48 | cmd, param = "URL_PREFIX_ADD", annotations[RedirectURLPrefixAddAnnotation] 49 | 50 | case annotations[RedirectSchemeSetSetAnnotation] != "": 51 | cmd, param = "SCHEME_SET", annotations[RedirectSchemeSetSetAnnotation] 52 | } 53 | return 54 | } 55 | 56 | func GetRedirectStatusCode(annotations map[string]string) (int, error) { 57 | statusCodeStr := annotations[RedirectResponseStatusAnnotation] 58 | if statusCodeStr == "" { 59 | return defaultRedirectResponseStatusCode, nil 60 | } 61 | 62 | statusCodeInt64, err := strconv.ParseInt(statusCodeStr, 10, 64) 63 | if err != nil { 64 | return 0, err 65 | } 66 | if err != nil { 67 | return 0, errors.New("the annotation %s should be a integer") 68 | } 69 | return int(statusCodeInt64), nil 70 | } 71 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/router.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package annotations 15 | 16 | import ( 17 | "fmt" 18 | "strings" 19 | ) 20 | 21 | const ( 22 | CookieKey = "router.cookie" 23 | HeaderKey = "router.header" 24 | 25 | CookieAnnotation = BfeAnnotationPrefix + CookieKey 26 | HeaderAnnotation = BfeAnnotationPrefix + HeaderKey 27 | ) 28 | 29 | func GetRouteExpression(annotations map[string]string) (string, error) { 30 | var primitive1 string 31 | var err error 32 | if primitive1, err = cookiePrimitive(annotations[CookieAnnotation]); err != nil { 33 | return "", err 34 | } 35 | 36 | var primitive2 string 37 | if primitive2, err = headerPrimitive(annotations[HeaderAnnotation]); err != nil { 38 | return "", err 39 | } 40 | 41 | if len(primitive1) > 0 && len(primitive2) > 0 { 42 | return primitive1 + "&&" + primitive2, nil 43 | } 44 | if len(primitive1) > 0 { 45 | return primitive1, nil 46 | } 47 | if len(primitive2) > 0 { 48 | return primitive2, nil 49 | } 50 | return "", nil 51 | } 52 | 53 | // cookiePrimitive generates bfe condition primitive for cookie match 54 | func cookiePrimitive(cookie string) (string, error) { 55 | if len(cookie) == 0 { 56 | return "", nil 57 | } 58 | index := strings.Index(cookie, ":") 59 | if index == -1 || index == len(cookie)-1 { 60 | return "", fmt.Errorf("cookie annotation[%s] is illegal", cookie) 61 | } 62 | 63 | con := fmt.Sprintf("req_cookie_value_in(\"%s\", \"%v\", false)", strings.TrimSpace(cookie[:index]), strings.TrimSpace(cookie[index+1:])) 64 | return con, nil 65 | 66 | } 67 | 68 | // cookiePrimitive generates bfe condition primitive for header match 69 | func headerPrimitive(header string) (string, error) { 70 | if len(header) == 0 { 71 | return "", nil 72 | } 73 | index := strings.Index(header, ":") 74 | if index == -1 || index == len(header)-1 { 75 | return "", fmt.Errorf("header annotation[%s] is illegal", header) 76 | } 77 | 78 | con := fmt.Sprintf("req_header_value_in(\"%s\", \"%v\", false)", strings.TrimSpace(header[:index]), strings.TrimSpace(header[index+1:])) 79 | return con, nil 80 | } 81 | -------------------------------------------------------------------------------- /internal/bfeConfig/annotations/status.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package annotations 15 | 16 | import ( 17 | "encoding/json" 18 | ) 19 | 20 | var ( 21 | StatusKey = "bfe-ingress-status" 22 | StatusAnnotationKey = BfeAnnotationPrefix + StatusKey 23 | ) 24 | 25 | type statusMsg struct { 26 | Status string `json:"status"` 27 | Message string `json:"message,omitempty"` 28 | } 29 | 30 | func GenErrorMsg(err error) string { 31 | var status = statusMsg{} 32 | 33 | if err == nil { 34 | status.Status = "success" 35 | } else { 36 | status.Status = "error" 37 | status.Message = err.Error() 38 | } 39 | 40 | jsons, _ := json.Marshal(status) 41 | return string(jsons) 42 | } 43 | 44 | // CompareStatus check errMsg with status, return 0 if equal 45 | func CompareStatus(e error, status string) int { 46 | if len(status) == 0 { 47 | return 1 48 | } 49 | 50 | s := &statusMsg{} 51 | if err := json.Unmarshal([]byte(status), s); err != nil { 52 | return 1 53 | } 54 | 55 | if e == nil && s.Status == "success" { 56 | return 0 57 | } 58 | 59 | if e != nil && s.Status == "error" && s.Message == e.Error() { 60 | return 0 61 | } 62 | 63 | return 1 64 | } 65 | -------------------------------------------------------------------------------- /internal/bfeConfig/configs/cache/baseRule.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cache 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | "time" 21 | 22 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/annotations" 23 | ) 24 | 25 | type BaseRule struct { 26 | Ingress string 27 | Host string 28 | Path string 29 | Annotations map[string]string 30 | CreateTime time.Time 31 | } 32 | 33 | func (rule BaseRule) GetIngress() string { 34 | return rule.Ingress 35 | } 36 | 37 | func (rule BaseRule) GetHost() string { 38 | return rule.Host 39 | } 40 | 41 | func (rule BaseRule) GetPath() string { 42 | return rule.Path 43 | } 44 | 45 | func (rule BaseRule) GetAnnotations() map[string]string { 46 | return rule.Annotations 47 | } 48 | 49 | func (rule BaseRule) GetCreateTime() time.Time { 50 | return rule.CreateTime 51 | } 52 | 53 | func (rule BaseRule) GetCond() (string, error) { 54 | return buildCondition(rule.Host, rule.Path, rule.Annotations) 55 | } 56 | 57 | func buildCondition(host string, path string, annots map[string]string) (string, error) { 58 | var statement []string 59 | 60 | primitive, err := hostPrimitive(host) 61 | if err != nil { 62 | return "", err 63 | } 64 | if len(primitive) > 0 { 65 | statement = append(statement, primitive) 66 | } 67 | 68 | primitive, err = pathPrimitive(path) 69 | if err != nil { 70 | return "", err 71 | } 72 | if len(primitive) > 0 { 73 | statement = append(statement, primitive) 74 | } 75 | 76 | primitive, err = annotations.GetRouteExpression(annots) 77 | if err != nil { 78 | return "", err 79 | } 80 | if len(primitive) > 0 { 81 | statement = append(statement, primitive) 82 | } 83 | 84 | return strings.Join(statement, "&&"), nil 85 | } 86 | 87 | // hostPrimitive builds host primitive in condition 88 | func hostPrimitive(host string) (string, error) { 89 | if len(host) == 0 || host == "*" { 90 | return "", nil 91 | } 92 | 93 | if strings.HasPrefix(host, "*.") { 94 | dn := host[2:] 95 | dn = strings.ReplaceAll(dn, ".", "\\.") 96 | return fmt.Sprintf(`req_host_regmatch("(?i)^[^\.]+%s")`, dn), nil 97 | } 98 | return fmt.Sprintf(`req_host_in("%s")`, host), nil 99 | } 100 | 101 | // pathPrimitive builds path primitive in condition 102 | func pathPrimitive(path string) (string, error) { 103 | if len(path) == 0 || path == "*" { 104 | return "", nil // no restriction 105 | } 106 | if path[len(path)-1] == '*' { 107 | return fmt.Sprintf(`req_path_element_prefix_in("%s", false)`, path[:len(path)-1]), nil 108 | } 109 | return fmt.Sprintf(`req_path_in("%s", false)`, path), nil 110 | } 111 | -------------------------------------------------------------------------------- /internal/bfeConfig/configs/log/log.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package log 16 | 17 | import "sigs.k8s.io/controller-runtime" 18 | 19 | var ( 20 | Log = controllerruntime.Log.WithName("configBuilder") 21 | ) 22 | -------------------------------------------------------------------------------- /internal/bfeConfig/configs/modules/module.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package modules 16 | 17 | import ( 18 | netv1 "k8s.io/api/networking/v1" 19 | 20 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/configs/modules/redirect" 21 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/configs/modules/rewrite" 22 | ) 23 | 24 | // BFEModuleConfig is an abstraction of the BFE module configuration. 25 | // The ConfigBuilder will call the corresponding function in this interface when update/delete ingresses or reload the BFE Engine. 26 | type BFEModuleConfig interface { 27 | // UpdateIngress uses the ingress to update the BFEModuleConfig 28 | UpdateIngress(ingress *netv1.Ingress) error 29 | 30 | // DeleteIngress delete everything related to the ingress from the BFEModuleConfig 31 | DeleteIngress(ingressNamespace, ingressName string) 32 | 33 | // Reload dumps the data in the BFEModuleConfig to the corresponding BFE conf files on the disk 34 | Reload() error 35 | 36 | // Name returns the name of the BFEModuleConfig 37 | Name() string 38 | } 39 | 40 | func InitBFEModules(version string) []BFEModuleConfig { 41 | var modules []BFEModuleConfig 42 | // mod_redirect 43 | modules = append(modules, redirect.NewRedirectConfig(version)) 44 | modules = append(modules, rewrite.NewRewriteConfig(version)) 45 | return modules 46 | } 47 | -------------------------------------------------------------------------------- /internal/bfeConfig/configs/modules/redirect/cache.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package redirect 16 | 17 | import ( 18 | "github.com/bfenetworks/bfe/bfe_modules/mod_redirect" 19 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/annotations" 20 | netv1 "k8s.io/api/networking/v1" 21 | 22 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/configs/cache" 23 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/util" 24 | ) 25 | 26 | type redirectRule struct { 27 | *cache.BaseRule 28 | // statusCode is the response status code of redirect 29 | statusCode int 30 | // action is the redirect action. Refer to https://www.bfe-networks.net/en_us/modules/mod_redirect/mod_redirect/. 31 | action *mod_redirect.ActionFileList 32 | } 33 | 34 | type redirectRuleCache struct { 35 | *cache.BaseCache 36 | } 37 | 38 | func newRedirectRuleCache(version string) *redirectRuleCache { 39 | return &redirectRuleCache{ 40 | BaseCache: cache.NewBaseCache(version), 41 | } 42 | } 43 | 44 | func (c redirectRuleCache) UpdateByIngress(ingress *netv1.Ingress) error { 45 | if len(ingress.Spec.Rules) == 0 { 46 | return nil 47 | } 48 | 49 | cmd, param, err := parseRedirectActionFromAnnotations(ingress.Annotations) 50 | if err != nil { 51 | return err 52 | } 53 | statusCode, err := annotations.GetRedirectStatusCode(ingress.Annotations) 54 | if err != nil { 55 | return err 56 | } 57 | return c.BaseCache.UpdateByIngressFramework( 58 | ingress, 59 | func(ingress *netv1.Ingress, host, path string, _ netv1.HTTPIngressPath) (cache.Rule, error) { 60 | // preCheck 61 | if err := checkAction(cmd, param); err != nil { 62 | return nil, err 63 | } 64 | if err := checkStatusCode(statusCode); err != nil { 65 | return nil, err 66 | } 67 | 68 | action := &mod_redirect.ActionFileList{mod_redirect.ActionFile{ 69 | Cmd: &cmd, 70 | Params: []string{param}, 71 | }} 72 | if err = mod_redirect.ActionFileListCheck(action); err != nil { 73 | return nil, err 74 | } 75 | return &redirectRule{ 76 | BaseRule: cache.NewBaseRule( 77 | util.NamespacedName(ingress.Namespace, ingress.Name), 78 | host, 79 | path, 80 | ingress.Annotations, 81 | ingress.CreationTimestamp.Time, 82 | ), 83 | statusCode: statusCode, 84 | action: action, 85 | }, nil 86 | }, 87 | func() (bool, error) { 88 | return cmd != "", err 89 | }, 90 | nil, 91 | ) 92 | } 93 | -------------------------------------------------------------------------------- /internal/bfeConfig/configs/routeRuleCache.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package configs 16 | 17 | import ( 18 | "sort" 19 | "time" 20 | 21 | "github.com/bfenetworks/bfe/bfe_config/bfe_route_conf/route_rule_conf" 22 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/util" 23 | netv1 "k8s.io/api/networking/v1" 24 | 25 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/annotations" 26 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/configs/cache" 27 | ) 28 | 29 | type routeRule struct { 30 | Cluster string 31 | *cache.BaseRule 32 | } 33 | 34 | type RouteRuleCache struct { 35 | *cache.BaseCache 36 | } 37 | 38 | func newRouteRuleCache(version string) *RouteRuleCache { 39 | return &RouteRuleCache{ 40 | BaseCache: cache.NewBaseCache(version), 41 | } 42 | } 43 | 44 | func newRouteRule(ingress string, host string, path string, annots map[string]string, cluster string, time time.Time) *routeRule { 45 | return &routeRule{ 46 | BaseRule: cache.NewBaseRule( 47 | ingress, 48 | host, 49 | path, 50 | annots, 51 | time, 52 | ), 53 | Cluster: cluster, 54 | } 55 | } 56 | 57 | func (c *RouteRuleCache) getRouteRules() (basicRuleList []*routeRule, advancedRuleList []*routeRule) { 58 | httpRules := c.BaseRules 59 | for _, paths := range httpRules.RuleMap { 60 | for _, ruleList := range paths { 61 | if len(ruleList) == 0 { 62 | continue 63 | } 64 | 65 | // add host+path rule to basic rule list 66 | if len(ruleList) == 1 && annotations.Priority(ruleList[0].GetAnnotations()) == annotations.PriorityBasic { 67 | basicRuleList = append(basicRuleList, ruleList[0].(*routeRule)) 68 | continue 69 | } 70 | // add a fake basicRule,cluster=ADVANCED_MODE 71 | newRule := *ruleList[0].(*routeRule) 72 | newRule.Cluster = route_rule_conf.AdvancedMode 73 | basicRuleList = append(basicRuleList, &newRule) 74 | 75 | // add advanced rule 76 | for _, rule := range ruleList { 77 | advancedRuleList = append(advancedRuleList, rule.(*routeRule)) 78 | } 79 | } 80 | } 81 | 82 | // host: exact match over wildcard match 83 | // path: long path over short path 84 | sort.SliceStable(advancedRuleList, func(i, j int) bool { 85 | return cache.CompareRule(advancedRuleList[i], advancedRuleList[j]) 86 | }) 87 | 88 | return 89 | } 90 | 91 | func (c *RouteRuleCache) UpdateByIngress(ingress *netv1.Ingress) error { 92 | return c.BaseCache.UpdateByIngressFramework( 93 | ingress, 94 | func(ingress *netv1.Ingress, host, path string, httpPath netv1.HTTPIngressPath) (cache.Rule, error) { 95 | ingressName := util.NamespacedName(ingress.Namespace, ingress.Name) 96 | return newRouteRule( 97 | ingressName, 98 | host, 99 | path, 100 | ingress.Annotations, 101 | util.ClusterName(ingressName, httpPath.Backend.Service), 102 | ingress.CreationTimestamp.Time, 103 | ), nil 104 | }, 105 | nil, 106 | nil, 107 | ) 108 | } 109 | -------------------------------------------------------------------------------- /internal/bfeConfig/util/io.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package util 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | "io" 20 | "io/ioutil" 21 | "net/http" 22 | "os" 23 | "path/filepath" 24 | 25 | "github.com/bfenetworks/ingress-bfe/internal/option" 26 | ) 27 | 28 | func DumpBfeConf(configFile string, object interface{}) error { 29 | buf, err := json.MarshalIndent(object, "", " ") 30 | if err != nil { 31 | return fmt.Errorf("config json marshal err %s", err) 32 | } 33 | return DumpFile(configFile, buf) 34 | } 35 | 36 | func DumpFile(filename string, data []byte) error { 37 | name := option.Opts.Ingress.ConfigPath + filename 38 | filePath := filepath.Dir(name) 39 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 40 | os.MkdirAll(filePath, option.Opts.Ingress.FilePerm) 41 | } 42 | 43 | return ioutil.WriteFile(name, data, option.Opts.Ingress.FilePerm) 44 | } 45 | 46 | func DeleteFile(filename string) { 47 | name := option.Opts.Ingress.ConfigPath + filename 48 | os.Remove(name) 49 | } 50 | 51 | // ReloadBfe triggers bfe process to reload new config file through bfe monitor port 52 | func ReloadBfe(configName string) error { 53 | url := option.Opts.Ingress.ReloadUrl + configName 54 | res, err := http.Get(url) 55 | if err != nil { 56 | return err 57 | } 58 | defer res.Body.Close() 59 | 60 | if res.StatusCode == http.StatusOK { 61 | return nil 62 | } 63 | 64 | failReason, err := ioutil.ReadAll(io.LimitReader(res.Body, 1024)) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | return fmt.Errorf("fail to reload: %s", failReason) 70 | } 71 | -------------------------------------------------------------------------------- /internal/bfeConfig/util/name.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package util 15 | 16 | import ( 17 | "fmt" 18 | "strconv" 19 | "strings" 20 | 21 | "github.com/bfenetworks/ingress-bfe/internal/option" 22 | netv1 "k8s.io/api/networking/v1" 23 | "k8s.io/apimachinery/pkg/types" 24 | ) 25 | 26 | func ClusterName(ingressName string, backend *netv1.IngressServiceBackend) string { 27 | port := backend.Port.Name 28 | if backend.Port.Number > 0 { 29 | port = fmt.Sprintf("%d", backend.Port.Number) 30 | } 31 | return fmt.Sprintf("%s_%s_%s", ingressName, backend.Name, port) 32 | } 33 | 34 | // DefaultClusterName returns a default cluster for default backend 35 | func DefaultClusterName() string { 36 | ingress := "__defaultCluster__" 37 | return fmt.Sprintf("%s_%s_%d", ingress, option.Opts.Ingress.DefaultBackend, 0) 38 | } 39 | 40 | func ParsePort(clusterName string) netv1.ServiceBackendPort { 41 | port := netv1.ServiceBackendPort{} 42 | index := strings.LastIndexByte(clusterName, '_') 43 | if index < 0 { 44 | return port 45 | } 46 | portStr := clusterName[index+1:] 47 | 48 | if i, err := strconv.Atoi(portStr); err == nil { 49 | port.Number = int32(i) 50 | } else { 51 | port.Name = portStr 52 | } 53 | return port 54 | } 55 | 56 | func NamespacedName(namespace, name string) string { 57 | return types.NamespacedName{ 58 | Namespace: namespace, 59 | Name: name, 60 | }.String() 61 | } 62 | 63 | func SplitNamespacedName(namespacedName string) (namespace, name string) { 64 | names := strings.Split(namespacedName, "/") 65 | if len(names) != 2 { 66 | return "", "" 67 | } 68 | return names[0], names[1] 69 | } 70 | -------------------------------------------------------------------------------- /internal/bfeConfig/util/version.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package util 15 | 16 | import ( 17 | "time" 18 | ) 19 | 20 | func NewVersion() string { 21 | return time.Now().Format(time.RFC3339Nano) 22 | } 23 | -------------------------------------------------------------------------------- /internal/controllers/event/events.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package event 14 | 15 | // event reason 16 | const ( 17 | SyncFailed = "SyncFailed" 18 | SyncSucceed = "SyncSucceed" 19 | ) 20 | -------------------------------------------------------------------------------- /internal/controllers/filter/ingressClass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package filter 16 | 17 | import ( 18 | "context" 19 | "strings" 20 | 21 | netv1 "k8s.io/api/networking/v1" 22 | netv1beta1 "k8s.io/api/networking/v1beta1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "sigs.k8s.io/controller-runtime/pkg/client" 25 | 26 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/annotations" 27 | "github.com/bfenetworks/ingress-bfe/internal/option" 28 | ) 29 | 30 | func IngressClassFilter(ctx context.Context, r client.Reader, annots map[string]string, ingressClassName *string) bool { 31 | if annots[annotations.IngressClassKey] == option.Opts.Ingress.IngressClass { 32 | return true 33 | } 34 | 35 | classListV1 := &netv1.IngressClassList{} 36 | err := r.List(ctx, classListV1) 37 | if err == nil { 38 | for _, class := range classListV1.Items { 39 | if class.Spec.Controller != option.Opts.Ingress.ControllerName { 40 | continue 41 | } 42 | if matchIngressClass(ingressClassName, &class) { 43 | return true 44 | } 45 | } 46 | } 47 | 48 | classListV1Beta1 := &netv1beta1.IngressClassList{} 49 | err = r.List(ctx, classListV1Beta1) 50 | if err != nil { 51 | return false 52 | } 53 | for _, classV1Beta1 := range classListV1Beta1.Items { 54 | if classV1Beta1.Spec.Controller != option.Opts.Ingress.ControllerName { 55 | continue 56 | } 57 | if matchIngressClass(ingressClassName, &classV1Beta1) { 58 | return true 59 | } 60 | } 61 | 62 | return false 63 | } 64 | 65 | // matchIngressClass matches for specific or default ingress class 66 | // Params: 67 | // targetCls: target ingress class name 68 | // if non-nil, matches ingress class with the same name 69 | // if nil, matches default ingress class 70 | func matchIngressClass(targetCls *string, testCls v1.Object) bool { 71 | // specific ingress class 72 | if targetCls != nil { 73 | return *targetCls == testCls.GetName() 74 | } 75 | 76 | // default ingress class 77 | annots := testCls.GetAnnotations() 78 | return strings.EqualFold(annots[annotations.IsDefaultIngressClass], "true") 79 | 80 | } 81 | -------------------------------------------------------------------------------- /internal/controllers/filter/ingressClass_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package filter 16 | 17 | import ( 18 | "testing" 19 | 20 | netv1 "k8s.io/api/networking/v1" 21 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | "k8s.io/utils/pointer" 23 | 24 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig/annotations" 25 | ) 26 | 27 | func Test_matchIngressClass(t *testing.T) { 28 | type args struct { 29 | targetCls *string 30 | testCls v1.Object 31 | } 32 | tests := []struct { 33 | name string 34 | args args 35 | want bool 36 | }{ 37 | { 38 | name: "match specific", 39 | args: args{ 40 | targetCls: pointer.String("bfe"), 41 | testCls: &netv1.IngressClass{ 42 | ObjectMeta: v1.ObjectMeta{ 43 | Name: "bfe", 44 | }, 45 | }, 46 | }, 47 | want: true, 48 | }, 49 | { 50 | name: "mismatch specific", 51 | args: args{ 52 | targetCls: pointer.String("bfe"), 53 | testCls: &netv1.IngressClass{ 54 | ObjectMeta: v1.ObjectMeta{ 55 | Name: "other", 56 | }, 57 | }, 58 | }, 59 | want: false, 60 | }, 61 | { 62 | name: "match default", 63 | args: args{ 64 | targetCls: nil, 65 | testCls: &netv1.IngressClass{ 66 | ObjectMeta: v1.ObjectMeta{ 67 | Annotations: map[string]string{ 68 | annotations.IsDefaultIngressClass: "True", 69 | }, 70 | }, 71 | }, 72 | }, 73 | want: true, 74 | }, 75 | { 76 | name: "mismatch default", 77 | args: args{ 78 | targetCls: nil, 79 | testCls: &netv1.IngressClass{}, 80 | }, 81 | want: false, 82 | }, 83 | } 84 | for _, tt := range tests { 85 | t.Run(tt.name, func(t *testing.T) { 86 | if got := matchIngressClass(tt.args.targetCls, tt.args.testCls); got != tt.want { 87 | t.Errorf("matchIngressClass() = %v, want %v", got, tt.want) 88 | } 89 | }) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /internal/controllers/filter/namespace.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package filter 16 | 17 | import ( 18 | corev1 "k8s.io/api/core/v1" 19 | "sigs.k8s.io/controller-runtime/pkg/client" 20 | "sigs.k8s.io/controller-runtime/pkg/predicate" 21 | 22 | "github.com/bfenetworks/ingress-bfe/internal/option" 23 | ) 24 | 25 | func NamespaceFilter() predicate.Funcs { 26 | funcs := predicate.NewPredicateFuncs(func(obj client.Object) bool { 27 | if len(option.Opts.NamespaceList) == 1 && option.Opts.NamespaceList[0] == corev1.NamespaceAll { 28 | return true 29 | } 30 | for _, ns := range option.Opts.NamespaceList { 31 | if ns == obj.GetNamespace() { 32 | return true 33 | } 34 | } 35 | return false 36 | }) 37 | 38 | return funcs 39 | } 40 | -------------------------------------------------------------------------------- /internal/controllers/ingress/secret_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ingress 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | corev1 "k8s.io/api/core/v1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ctrl "sigs.k8s.io/controller-runtime" 24 | "sigs.k8s.io/controller-runtime/pkg/builder" 25 | "sigs.k8s.io/controller-runtime/pkg/client" 26 | "sigs.k8s.io/controller-runtime/pkg/log" 27 | "sigs.k8s.io/controller-runtime/pkg/manager" 28 | 29 | "github.com/bfenetworks/ingress-bfe/internal/bfeConfig" 30 | "github.com/bfenetworks/ingress-bfe/internal/controllers/filter" 31 | ) 32 | 33 | func AddSecretController(mgr manager.Manager, cb *bfeConfig.ConfigBuilder) error { 34 | reconciler := newSecretReconciler(mgr, cb) 35 | if err := reconciler.setupWithManager(mgr); err != nil { 36 | return fmt.Errorf("unable to create ingress controller") 37 | } 38 | 39 | return nil 40 | } 41 | 42 | // SecretReconciler reconciles a Secret object 43 | type SecretReconciler struct { 44 | BfeConfigBuilder *bfeConfig.ConfigBuilder 45 | 46 | client.Client 47 | Scheme *runtime.Scheme 48 | } 49 | 50 | func newSecretReconciler(mgr manager.Manager, cb *bfeConfig.ConfigBuilder) *SecretReconciler { 51 | return &SecretReconciler{ 52 | BfeConfigBuilder: cb, 53 | Client: mgr.GetClient(), 54 | Scheme: mgr.GetScheme(), 55 | } 56 | } 57 | 58 | func (r *SecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 59 | log := log.FromContext(ctx) 60 | log.V(1).Info("reconciling Secret", "api version", "corev1") 61 | 62 | secret := &corev1.Secret{} 63 | err := r.Get(ctx, client.ObjectKey{ 64 | Namespace: req.Namespace, 65 | Name: req.Name, 66 | }, secret) 67 | if err != nil { 68 | return ctrl.Result{}, nil 69 | } 70 | 71 | r.BfeConfigBuilder.UpdateSecret(secret) 72 | 73 | return ctrl.Result{}, nil 74 | } 75 | 76 | // setupWithManager sets up the controller with the Manager. 77 | func (r *SecretReconciler) setupWithManager(mgr ctrl.Manager) error { 78 | return ctrl.NewControllerManagedBy(mgr). 79 | For(&corev1.Secret{}, builder.WithPredicates(filter.NamespaceFilter())). 80 | Complete(r) 81 | } 82 | -------------------------------------------------------------------------------- /internal/option/ingress/options.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ingress 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | "path/filepath" 21 | "strings" 22 | "time" 23 | 24 | "k8s.io/apimachinery/pkg/types" 25 | ) 26 | 27 | const ( 28 | enableIngress = true 29 | 30 | configPath = "/bfe/conf/" 31 | bfeBinary = "/bfe/bin/bfe" 32 | reloadAddr = "localhost:8421" 33 | reloadInterval = 3 * time.Second 34 | reloadUrlPrefix = "http://%s/reload/" 35 | 36 | filePerm os.FileMode = 0744 37 | 38 | // used in ingress annotation as value of key kubernetes.io/ingress.class 39 | ingressClassName = "bfe" 40 | 41 | // used in IngressClass resource as value of controller 42 | controllerName = "bfe-networks.com/ingress-controller" 43 | 44 | // default backend 45 | defaultBackend = "" 46 | ) 47 | 48 | type Options struct { 49 | EnableIngress bool 50 | IngressClass string 51 | ControllerName string 52 | ReloadAddr string 53 | ReloadUrl string 54 | BfeBinary string 55 | ConfigPath string 56 | FilePerm os.FileMode 57 | ReloadInterval time.Duration 58 | DefaultBackend string 59 | } 60 | 61 | func NewOptions() *Options { 62 | return &Options{ 63 | EnableIngress: enableIngress, 64 | IngressClass: ingressClassName, 65 | ControllerName: controllerName, 66 | ReloadAddr: reloadAddr, 67 | BfeBinary: bfeBinary, 68 | ConfigPath: configPath, 69 | FilePerm: filePerm, 70 | ReloadInterval: reloadInterval, 71 | DefaultBackend: defaultBackend, 72 | } 73 | } 74 | 75 | func (opts *Options) Check() error { 76 | if !opts.EnableIngress { 77 | return nil 78 | } 79 | 80 | if len(opts.DefaultBackend) > 0 { 81 | names := strings.Split(opts.DefaultBackend, string(types.Separator)) 82 | if len(names) != 2 { 83 | return fmt.Errorf("invalid command line argument default-backend: %s", opts.DefaultBackend) 84 | } 85 | } 86 | if len(opts.BfeBinary) > 0 { 87 | opts.ConfigPath = filepath.Dir(filepath.Dir(opts.BfeBinary)) + "/conf" 88 | } 89 | 90 | if !strings.HasSuffix(opts.ConfigPath, "/") { 91 | opts.ConfigPath = opts.ConfigPath + "/" 92 | } 93 | 94 | opts.ReloadUrl = fmt.Sprintf(reloadUrlPrefix, opts.ReloadAddr) 95 | return nil 96 | } 97 | -------------------------------------------------------------------------------- /internal/option/options.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The BFE Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package option 16 | 17 | import ( 18 | "strings" 19 | 20 | corev1 "k8s.io/api/core/v1" 21 | 22 | "github.com/bfenetworks/ingress-bfe/internal/option/ingress" 23 | ) 24 | 25 | const ( 26 | ClusterName = "default" 27 | MetricsBindAddress = ":9080" 28 | HealthProbeBindAddress = ":9081" 29 | ) 30 | 31 | type Options struct { 32 | ClusterName string 33 | 34 | Namespaces string 35 | NamespaceList []string 36 | MetricsAddr string 37 | HealthProbeAddr string 38 | 39 | Ingress *ingress.Options 40 | } 41 | 42 | var ( 43 | Opts *Options 44 | ) 45 | 46 | func NewOptions() *Options { 47 | return &Options{ 48 | ClusterName: ClusterName, 49 | Namespaces: corev1.NamespaceAll, 50 | MetricsAddr: MetricsBindAddress, 51 | HealthProbeAddr: HealthProbeBindAddress, 52 | Ingress: ingress.NewOptions(), 53 | } 54 | } 55 | 56 | func SetOptions(option *Options) error { 57 | if err := option.Ingress.Check(); err != nil { 58 | return err 59 | } 60 | 61 | Opts = option 62 | Opts.NamespaceList = strings.Split(Opts.Namespaces, ",") 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2021 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | set -e 17 | if [ $# -lt 2 ]; then 18 | echo "error: number of argument should >= 2" 19 | exit 1 20 | fi 21 | 22 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 23 | 24 | CTL_BIN=$1 25 | BFE_BIN=$2 26 | 27 | BFE_NAME="$(basename $BFE_BIN)" 28 | BFE_ROOT_DIR="$(cd "$(dirname "$BFE_BIN")/.." && pwd -P)" 29 | CONF_DIR="$BFE_ROOT_DIR/conf" 30 | BFE_BIN_DIR="$BFE_ROOT_DIR/bin" 31 | 32 | shift 2 33 | ARGS="$@ -c $CONF_DIR " 34 | if [ -n "$INGRESS_LISTEN_NAMESPACE" ]; then 35 | ARGS=$ARGS"-n $INGRESS_LISTEN_NAMESPACE" 36 | fi 37 | 38 | cd ${BFE_BIN_DIR} && ./${BFE_NAME} -c ../conf -l ../log & 39 | sleep 1 40 | pgrep ${BFE_NAME} 41 | if [ $? -ne 0 ]; then 42 | exit 1 43 | fi 44 | 45 | ${CTL_BIN} $ARGS 46 | -------------------------------------------------------------------------------- /test/e2e/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Build 16 | FROM golang:1.16-alpine3.14 as builder 17 | 18 | WORKDIR /go/src/github.com/bfenetworks/ingress-bfe 19 | # Copy the Go Modules manifests 20 | COPY go.mod go.mod 21 | COPY go.sum go.sum 22 | # cache deps before building and copying source so that we don't need to re-download as much 23 | # and so that source changes don't invalidate our downloaded layer 24 | RUN go mod download 25 | 26 | # Copy the go source 27 | COPY . /go/src/github.com/bfenetworks/ingress-bfe 28 | 29 | # Build 30 | RUN make e2e_test 31 | 32 | FROM alpine3.14 33 | 34 | ENV RESULTS_DIR="/tmp/results" 35 | ENV WAIT_FOR_STATUS_TIMEOUT="5m" 36 | ENV TEST_TIMEOUT="5m" 37 | 38 | COPY --from=builder /go/src/github.com/bfenetworks/ingress-bfe/e2e_test / 39 | 40 | COPY features /features 41 | COPY run.sh / 42 | 43 | CMD [ "/run.sh" ] 44 | -------------------------------------------------------------------------------- /test/e2e/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | .DEFAULT_GOAL:=help 16 | 17 | MKDIR_P := mkdir -p 18 | RM_F := rm -rf 19 | 20 | 21 | PROGRAMS := \ 22 | e2e_test 23 | 24 | TAG ?= 0.0.1 25 | 26 | REGISTRY ?= local 27 | 28 | build: $(PROGRAMS) ## Build the e2e-test binary 29 | 30 | .PHONY: build-image 31 | build-image: ## Build the e2e-test image 32 | docker build -t $(REGISTRY)/e2e_test:$(TAG) . 33 | 34 | .PHONY: publish-image 35 | publish-image: 36 | docker push $(REGISTRY)/e2e_test:$(TAG) 37 | 38 | .PHONY: e2e_test 39 | e2e_test: check-go-version 40 | @CGO_ENABLED=0 go test -c -trimpath -ldflags="-buildid= -w" -o $@ . 41 | 42 | .PHONY: clean 43 | clean: ## Remove build artifacts 44 | $(RM_F) internal/pkg/assets/assets.go 45 | $(RM_F) $(PROGRAMS) 46 | 47 | .PHONY: codegen 48 | codegen: check-go-version ## Generate or update missing Go code defined in feature files 49 | @go run hack/codegen.go -update -dest-path=steps/conformance features/conformance 50 | 51 | .PHONY: verify-codegen 52 | verify-codegen: check-go-version ## Verify if generated Go code is in sync with feature files 53 | @go run hack/codegen.go -dest-path=steps/conformance features 54 | 55 | .PHONY: verify-gherkin 56 | verify-gherkin: check-go-version ## Verify format of gherkin feature files 57 | @hack/verify-gherkin.sh 58 | 59 | .PHONY: help 60 | help: ## Display this help 61 | @echo Targets: 62 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9._-]+:.*?## / {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort 63 | 64 | .PHONY: check-go-version 65 | check-go-version: 66 | @hack/check-go-version.sh 67 | -------------------------------------------------------------------------------- /test/e2e/README.md: -------------------------------------------------------------------------------- 1 | # BFE ingress controller e2e test 2 | 3 | This test follows K8s project [ingress-controller-conformance](https://github.com/kubernetes-sigs/ingress-controller-conformance), and add more test cases for ingress-bfe special features. 4 | 5 | ## How to run 6 | 7 | To run all e2e test cases, execute following command in ingress-bfe project's top directory: 8 | 9 | ``` 10 | $ make e2e-test 11 | ``` 12 | It would automatically start the whole testing with following procedures: 13 | 14 | - Build bfe-ingress-controller docker image 15 | - Prepare test environment, including spining up a local k8s cluster with [Kind](https://kind.sigs.k8s.io/), loading docker images, etc. All scripts used to prepare environment are located in [test/script](../script). 16 | - Execute test cases by running [run.sh](./run.sh), which actually build and execute program e2e_test. 17 | 18 | ## Contributing 19 | 20 | We encourage contributors write e2e test case for new feature needed to be merged into ingress-bfe. 21 | 22 | The test code is based on BDD testing framework [godog](https://github.com/cucumber/godog), a testing framework of [cucumber](https://cucumber.io/). It uses [Gherkin Syntax]( https://cucumber.io/docs/gherkin/reference/) to describe test case. 23 | 24 | Steps to add new test case as below: 25 | 26 | ### Step1: Create Gherkin feature 27 | 28 | * Create feature file to describe your test case. 29 | 30 | All feature files are under directory [test/e2e/features](./features). Please put your feature file into proper sub-directory. For example, features//.feature 31 | > Try to reuse steps from existing feature files if possible. 32 | 33 | ### Step2: Create steps definition 34 | 35 | * Generate steps.go for your case. Under directory test/e2e, run: 36 | 37 | ```bash 38 | $ go run hack/codegen.go -dest-path=steps/ features//.feature 39 | ``` 40 | 41 | 42 | * Edit generated code, implement all generated functions. If you reuse step description from other feature file, you can also reuse corresponding function from that `step.go` file in this step. 43 | 44 | ### Step3: Add Init function into e2e_test.go 45 | 46 | * In e2e_test.go, add generated feature file and InitializeScenario function into map `features`. 47 | 48 | ```go 49 | var ( 50 | features = map[string]InitialFunc{ 51 | "features/conformance/host_rules.feature": {hostrules.InitializeScenario, nil}, 52 | ... 53 | } 54 | ) 55 | 56 | ``` 57 | 58 | ### Step4: Build and run 59 | 60 | 61 | 62 | * Build e2e_test: 63 | 64 | ```bash 65 | $ make build 66 | ``` 67 | 68 | * Run your case, using `--feature` to specify the feature file. 69 | 70 | ```bash 71 | $ ./e2e_test --feature features//.feature 72 | ``` 73 | > Before running, your testing environment must be ready. 74 | 75 | * Run all cases 76 | ```bash 77 | $ ./run.sh 78 | ``` 79 | -------------------------------------------------------------------------------- /test/e2e/features/conformance/default_backend.feature: -------------------------------------------------------------------------------- 1 | @sig-network @conformance @release-1.22 2 | Feature: Default backend 3 | An Ingress with no rules sends all traffic to the single default backend. 4 | The default backend is part of the Ingress resource spec field `defaultBackend`. 5 | 6 | If none of the hosts or paths match the HTTP request in the 7 | Ingress objects, the traffic is routed to your default backend. 8 | 9 | Background: 10 | Given a new random namespace 11 | Given an Ingress resource named "default-backend" with this spec: 12 | """ 13 | defaultBackend: 14 | service: 15 | name: echo-service 16 | port: 17 | number: 3000 18 | """ 19 | Then The Ingress status shows the IP address or FQDN where it is exposed 20 | 21 | Scenario Outline: An Ingress with no rules should send all requests to the default backend 22 | When I send a "" request to http://""/"" 23 | Then the response status-code must be 200 24 | And the response must be served by the "echo-service" service 25 | And the response proto must be "HTTP/1.1" 26 | And the response headers must contain with matching 27 | | key | value | 28 | | Content-Length | * | 29 | | Content-Type | * | 30 | | Date | * | 31 | | Server | * | 32 | And the request method must be "" 33 | And the request path must be "" 34 | And the request proto must be "HTTP/1.1" 35 | And the request headers must contain with matching 36 | | key | value | 37 | | User-Agent | Go-http-client/1.1 | 38 | 39 | Examples: 40 | | method | host | path | 41 | | GET | my-host | | 42 | | GET | my-host | sub-path | 43 | | POST | some-host | | 44 | | PUT | | resource | 45 | | DELETE | some-host | resource | 46 | | PATCH | my-host | resource | 47 | -------------------------------------------------------------------------------- /test/e2e/features/conformance/host_rules.feature: -------------------------------------------------------------------------------- 1 | @sig-network @conformance @release-1.22 2 | Feature: Host rules 3 | An Ingress may define routing rules based on the request host. 4 | 5 | If the HTTP request host matches one of the hosts in the 6 | Ingress objects, the traffic is routed to its backend service. 7 | 8 | Background: 9 | Given a new random namespace 10 | Given a self-signed TLS secret named "conformance-tls" for the "foo.bar.com" hostname 11 | Given an Ingress resource 12 | """ 13 | apiVersion: networking.k8s.io/v1 14 | kind: Ingress 15 | metadata: 16 | name: host-rules 17 | spec: 18 | tls: 19 | - hosts: 20 | - foo.bar.com 21 | secretName: conformance-tls 22 | rules: 23 | - host: "*.foo.com" 24 | http: 25 | paths: 26 | - path: / 27 | pathType: Prefix 28 | backend: 29 | service: 30 | name: wildcard-foo-com 31 | port: 32 | number: 8080 33 | 34 | - host: foo.bar.com 35 | http: 36 | paths: 37 | - path: / 38 | pathType: Prefix 39 | backend: 40 | service: 41 | name: foo-bar-com 42 | port: 43 | number: 80 44 | 45 | """ 46 | Then The Ingress status shows the IP address or FQDN where it is exposed 47 | 48 | 49 | Scenario: An Ingress with a host rule should send TLS traffic to the matching backend service 50 | (host foo.bar.com matches request foo.bar.com) 51 | 52 | When I send a "GET" request to "https://foo.bar.com" 53 | Then the secure connection must verify the "foo.bar.com" hostname 54 | And the response status-code must be 200 55 | And the response must be served by the "foo-bar-com" service 56 | And the request host must be "foo.bar.com" 57 | 58 | Scenario: An Ingress with a host rule should send traffic to the matching backend service 59 | (host foo.bar.com matches request foo.bar.com) 60 | 61 | When I send a "GET" request to "http://foo.bar.com" 62 | And the response status-code must be 200 63 | And the response must be served by the "foo-bar-com" service 64 | And the request host must be "foo.bar.com" 65 | 66 | Scenario: An Ingress with a host rule should not route traffic when hostname does not match 67 | (host foo.bar.com does not match request subdomain.bar.com) 68 | 69 | When I send a "GET" request to "http://subdomain.bar.com" 70 | Then the response status-code must be 500 71 | 72 | Scenario: An Ingress with a wildcard host rule should send traffic to the matching backend service 73 | (Matches based on shared suffix) 74 | 75 | When I send a "GET" request to "http://bar.foo.com" 76 | Then the response status-code must be 200 77 | And the response must be served by the "wildcard-foo-com" service 78 | And the request host must be "bar.foo.com" 79 | 80 | Scenario: An Ingress with a wildcard host rule should not route traffic matching on more than a single dns label 81 | (No match, wildcard only covers a single DNS label) 82 | 83 | When I send a "GET" request to "http://baz.bar.foo.com" 84 | Then the response status-code must be 500 85 | 86 | Scenario: An Ingress with a wildcard host rule should not route traffic matching no dns label 87 | (No match, wildcard only covers a single DNS label) 88 | 89 | When I send a "GET" request to "http://foo.com" 90 | Then the response status-code must be 500 91 | -------------------------------------------------------------------------------- /test/e2e/features/conformance/ingress_class.feature: -------------------------------------------------------------------------------- 1 | @sig-network @conformance @release-1.22 2 | Feature: Ingress class 3 | Ingresses can be implemented by different controllers, often with different configuration. 4 | Each Ingress definition could specify a class, a reference to an IngressClass resource that contains 5 | additional configuration including the name of the controller that should implement the class. 6 | 7 | https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class 8 | 9 | Scenario: An Ingress with an invalid ingress class should not send traffic to the matching backend service 10 | Given an Ingress resource in a new random namespace 11 | """ 12 | apiVersion: networking.k8s.io/v1 13 | kind: Ingress 14 | metadata: 15 | name: test-ingress-class 16 | spec: 17 | ingressClassName: some-invalid-class-name 18 | rules: 19 | - host: "ingress-class" 20 | http: 21 | paths: 22 | - path: / 23 | pathType: Prefix 24 | backend: 25 | service: 26 | name: ingress-class-prefix 27 | port: 28 | number: 8080 29 | 30 | """ 31 | Then The Ingress status should not contain the IP address or FQDN 32 | -------------------------------------------------------------------------------- /test/e2e/features/conformance/load_balancing.feature: -------------------------------------------------------------------------------- 1 | @sig-network @conformance @release-1.22 2 | Feature: Load Balancing 3 | An Ingress exposing a backend service with multiple replicas should use all the pods available 4 | The feature sessionAffinity is not configured in the backend service https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#service-v1-core 5 | 6 | Background: 7 | Given an Ingress resource in a new random namespace 8 | """ 9 | apiVersion: networking.k8s.io/v1 10 | kind: Ingress 11 | metadata: 12 | name: path-rules 13 | spec: 14 | rules: 15 | - host: "load-balancing" 16 | http: 17 | paths: 18 | - path: / 19 | pathType: Prefix 20 | backend: 21 | service: 22 | name: echo-service 23 | port: 24 | number: 8080 25 | 26 | """ 27 | Then The Ingress status shows the IP address or FQDN where it is exposed 28 | Then The backend deployment "echo-service" for the ingress resource is scaled to 10 29 | 30 | Scenario Outline: An Ingress should send all requests to the backend 31 | When I send 100 requests to "http://load-balancing" 32 | Then all the responses status-code must be 200 and the response body should contain the IP address of 10 different Kubernetes pods 33 | -------------------------------------------------------------------------------- /test/e2e/features/rules/path_err.feature: -------------------------------------------------------------------------------- 1 | @ingress.rule @release-1.22 2 | Feature: Path error rules 3 | An Ingress status error when given error ingress. 4 | 5 | Scenario: An Ingress with path rules a status should be error and not send traffic to the matching backend service 6 | (path rule a) 7 | Given an Ingress resource in a new random namespace should not create 8 | """ 9 | apiVersion: networking.k8s.io/v1 10 | kind: Ingress 11 | metadata: 12 | name: path-err-rules 13 | spec: 14 | rules: 15 | - host: "exact-path-rules-cookie-uid" 16 | http: 17 | paths: 18 | - path: a 19 | pathType: Exact 20 | backend: 21 | service: 22 | name: foo-exact 23 | port: 24 | number: 3000 25 | """ 26 | 27 | Scenario: An Ingress with path rules null status should be error and not send traffic to the matching backend service 28 | (path rule null) 29 | Given an Ingress resource in a new random namespace should not create 30 | """ 31 | apiVersion: networking.k8s.io/v1 32 | kind: Ingress 33 | metadata: 34 | name: path-err-rules 35 | spec: 36 | rules: 37 | - host: "exact-path-rules-cookie-uid" 38 | http: 39 | paths: 40 | - path: 41 | pathType: Exact 42 | backend: 43 | service: 44 | name: foo-exact 45 | port: 46 | number: 3000 47 | """ 48 | -------------------------------------------------------------------------------- /test/e2e/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bfenetworks/ingress-bfe/test/e2e 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cucumber/gherkin-go/v11 v11.0.0 7 | github.com/cucumber/godog v0.12.3 8 | github.com/cucumber/messages-go/v10 v10.0.3 9 | github.com/cucumber/messages-go/v16 v16.0.1 // indirect 10 | github.com/iancoleman/orderedmap v0.1.0 11 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 12 | k8s.io/api v0.19.2 13 | k8s.io/apimachinery v0.19.2 14 | k8s.io/client-go v0.19.2 15 | k8s.io/klog/v2 v2.3.0 16 | sigs.k8s.io/yaml v1.2.0 17 | ) 18 | -------------------------------------------------------------------------------- /test/e2e/hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright YEAR The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /test/e2e/hack/boilerplate/boilerplate.py.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright YEAR The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | -------------------------------------------------------------------------------- /test/e2e/hack/boilerplate/boilerplate.sh.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /test/e2e/hack/check-go-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2020 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | if [ -n "$DEBUG" ]; then 18 | set -x 19 | fi 20 | 21 | set -o errexit 22 | set -o nounset 23 | set -o pipefail 24 | 25 | MINIMUM_GO_VERSION=go1.15 26 | 27 | if [[ -z "$(command -v go)" ]]; then 28 | echo " 29 | Can't find 'go' in PATH, please fix and retry. 30 | See http://golang.org/doc/install for installation instructions. 31 | " 32 | exit 1 33 | fi 34 | 35 | IFS=" " read -ra go_version <<< "$(go version)" 36 | 37 | if [[ "${MINIMUM_GO_VERSION}" != $(echo -e "${MINIMUM_GO_VERSION}\n${go_version[2]}" | sort -s -t. -k 1,1 -k 2,2n -k 3,3n | head -n1) && "${go_version[2]}" != "devel" ]]; then 38 | echo " 39 | Detected go version: ${go_version[*]}. 40 | ingress-nginx requires ${MINIMUM_GO_VERSION} or greater. 41 | 42 | Please install ${MINIMUM_GO_VERSION} or later. 43 | " 44 | exit 1 45 | fi 46 | -------------------------------------------------------------------------------- /test/e2e/hack/codegen.tmpl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The BFE Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package {{ .Package }} 18 | 19 | import ( 20 | "github.com/cucumber/godog" 21 | "github.com/cucumber/messages-go/v16" 22 | 23 | "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/kubernetes" 24 | tstate "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/state" 25 | ) 26 | 27 | var ( 28 | state *tstate.Scenario 29 | ) 30 | 31 | // IMPORTANT: Steps definitions are generated and should not be modified 32 | // by hand but rather through make codegen. DO NOT EDIT. 33 | 34 | // InitializeScenario configures the Feature to test 35 | func InitializeScenario(ctx *godog.ScenarioContext) { {{- range .NewFunctions }} 36 | ctx.Step({{ backticked .Expr | unescape }}, {{ .Name }}){{end}} 37 | 38 | ctx.BeforeScenario(func(*godog.Scenario) { 39 | state = tstate.New() 40 | }) 41 | 42 | ctx.AfterScenario(func(*messages.Pickle, error) { 43 | // delete namespace an all the content 44 | _ = kubernetes.DeleteNamespace(kubernetes.KubeClient, state.Namespace) 45 | }) 46 | } 47 | {{ range .NewFunctions }} 48 | func {{ .Name }}{{ argsFromMap .Args false }} error { 49 | return godog.ErrPending 50 | } 51 | {{ end }} 52 | -------------------------------------------------------------------------------- /test/e2e/hack/kube-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Some useful colors. 18 | if [[ -z "${color_start-}" ]]; then 19 | declare -r color_start="\033[" 20 | declare -r color_red="${color_start}0;31m" 21 | declare -r color_yellow="${color_start}0;33m" 22 | declare -r color_green="${color_start}0;32m" 23 | declare -r color_norm="${color_start}0m" 24 | fi 25 | 26 | # Returns the server version as MMmmpp, with MM as the major 27 | # component, mm the minor component, and pp as the patch 28 | # revision. e.g. 0.7.1 is echoed as 701, and 1.0.11 would be 29 | # 10011. (This makes for easy integer comparison in bash.) 30 | function kube_server_version() { 31 | local server_version 32 | local major 33 | local minor 34 | local patch 35 | 36 | # This sed expression is the POSIX BRE to match strings like: 37 | # Server Version: &version.Info{Major:"0", Minor:"7+", GitVersion:"v0.7.0-dirty", GitCommit:"ad44234f7152e9c66bc2853575445c7071335e57", GitTreeState:"dirty"} 38 | # and capture the GitVersion portion (which has the patch level) 39 | server_version=$(${KUBECTL} --match-server-version=false version | grep "Server Version:") 40 | read major minor patch < <( 41 | echo ${server_version} | \ 42 | sed "s/.*GitVersion:\"v\([0-9]\{1,\}\)\.\([0-9]\{1,\}\)\.\([0-9]\{1,\}\).*/\1 \2 \3/") 43 | printf "%02d%02d%02d" ${major} ${minor} ${patch} | sed 's/^0*//' 44 | } 45 | -------------------------------------------------------------------------------- /test/e2e/hack/verify-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 22 | source "${KUBE_ROOT}/hack/kube-env.sh" 23 | 24 | SILENT=true 25 | 26 | function is-excluded { 27 | for e in $EXCLUDE; do 28 | if [[ $1 -ef ${BASH_SOURCE} ]]; then 29 | return 30 | fi 31 | if [[ $1 -ef "$KUBE_ROOT/hack/$e" ]]; then 32 | return 33 | fi 34 | done 35 | return 1 36 | } 37 | 38 | while getopts ":v" opt; do 39 | case $opt in 40 | v) 41 | SILENT=false 42 | ;; 43 | \?) 44 | echo "Invalid flag: -$OPTARG" >&2 45 | exit 1 46 | ;; 47 | esac 48 | done 49 | 50 | if $SILENT ; then 51 | echo "Running in the silent mode, run with -v if you want to see script logs." 52 | fi 53 | 54 | EXCLUDE="verify-all.sh verify-codegen.sh" 55 | 56 | ret=0 57 | for t in `ls $KUBE_ROOT/hack/verify-*.sh` 58 | do 59 | if is-excluded $t ; then 60 | echo "Skipping $t" 61 | continue 62 | fi 63 | if $SILENT ; then 64 | echo -e "Verifying $t" 65 | if bash "$t" &> /dev/null; then 66 | echo -e "${color_green}SUCCESS${color_norm}" 67 | else 68 | echo -e "${color_red}FAILED${color_norm}" 69 | ret=1 70 | fi 71 | else 72 | bash "$t" || ret=1 73 | fi 74 | done 75 | 76 | exit $ret 77 | 78 | # ex: ts=2 sw=2 et filetype=sh 79 | -------------------------------------------------------------------------------- /test/e2e/hack/verify-boilerplate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 22 | 23 | boilerDir="${KUBE_ROOT}/hack/boilerplate" 24 | boiler="${boilerDir}/boilerplate.py" 25 | 26 | files_need_boilerplate=($(${boiler} "$@")) 27 | 28 | # Run boilerplate check 29 | if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then 30 | for file in "${files_need_boilerplate[@]}"; do 31 | echo "Boilerplate header is wrong for: ${file}" 32 | done 33 | 34 | exit 1 35 | fi 36 | -------------------------------------------------------------------------------- /test/e2e/hack/verify-gherkin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # GoFmt apparently is changing @ head... 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 24 | 25 | if ! command -v reformat-gherkin --version &> /dev/null; then 26 | echo "Please install reformat-gherkin running \"pip install reformat-gherkin\"" 27 | exit 1 28 | fi 29 | 30 | reformat-gherkin --check ${KUBE_ROOT}/features 31 | -------------------------------------------------------------------------------- /test/e2e/hack/verify-gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # GoFmt apparently is changing @ head... 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 24 | 25 | cd "${KUBE_ROOT}" 26 | 27 | find_files() { 28 | find . -not \( \ 29 | \( \ 30 | -wholename './.git' \ 31 | -o -wholename '*/vendor/*' \ 32 | -o -wholename '*bindata.go' \ 33 | \) -prune \ 34 | \) -name '*.go' 35 | } 36 | 37 | GOFMT="gofmt -s" 38 | bad_files=$(find_files | xargs $GOFMT -l) 39 | if [[ -n "${bad_files}" ]]; then 40 | echo "!!! '$GOFMT' needs to be run on the following files: " 41 | echo "${bad_files}" 42 | exit 1 43 | fi 44 | -------------------------------------------------------------------------------- /test/e2e/hack/verify-golint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 22 | 23 | if ! command -v golint &> /dev/null; then 24 | go get golang.org/x/lint/golint 25 | fi 26 | 27 | cd "${KUBE_ROOT}" 28 | 29 | PACKAGES=($(go list ./test/...)) 30 | bad_files=() 31 | for package in "${PACKAGES[@]}"; do 32 | out=$(golint -min_confidence=0.9 "${package}" | grep -v -E '(should not use dot imports)' || :) 33 | if [[ -n "${out}" ]]; then 34 | bad_files+=("${out}") 35 | fi 36 | done 37 | if [[ "${#bad_files[@]}" -ne 0 ]]; then 38 | echo "!!! golint problems: " 39 | echo "${bad_files[@]}" 40 | exit 1 41 | fi 42 | 43 | # ex: ts=2 sw=2 et filetype=sh 44 | -------------------------------------------------------------------------------- /test/e2e/images/echoserver/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Build 16 | FROM golang:1.16-alpine3.14 as builder 17 | 18 | ENV CGO_ENABLED=0 19 | 20 | WORKDIR /echoserver/ 21 | 22 | COPY echoserver.go . 23 | 24 | RUN GO111MODULE=off go build -trimpath -ldflags="-buildid= -s -w" -o echoserver . 25 | 26 | # Use distroless as minimal base image to package the binary 27 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 28 | FROM alpine:3.14 29 | WORKDIR / 30 | COPY --from=builder /echoserver / 31 | 32 | ENTRYPOINT ["/echoserver"] 33 | -------------------------------------------------------------------------------- /test/e2e/images/echoserver/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | TAG ?= 0.0.1 16 | 17 | REGISTRY ?= local 18 | IMAGE = echoserver 19 | 20 | .PHONY: build-image 21 | build-image: ## Build the ingress conformance image 22 | docker build -t $(REGISTRY)/$(IMAGE):$(TAG) . 23 | 24 | .PHONY: publish-image 25 | publish-image: 26 | docker push $(REGISTRY)/$(IMAGE):$(TAG) 27 | -------------------------------------------------------------------------------- /test/e2e/images/echoserver/echoserver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bfenetworks/ingress-bfe/593a473ce6016f41d99de24722008423e5085322/test/e2e/images/echoserver/echoserver -------------------------------------------------------------------------------- /test/e2e/images/reports/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # build stage 16 | FROM node:lts-alpine 17 | 18 | WORKDIR /app 19 | 20 | COPY src /app 21 | 22 | RUN npm install --production 23 | 24 | CMD ["node", "/app/index.js"] 25 | -------------------------------------------------------------------------------- /test/e2e/images/reports/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | TAG ?= 0.0.1 16 | 17 | REGISTRY ?= local 18 | IMAGE = reports-builder 19 | 20 | .PHONY: build-image 21 | build-image: ## Build the e2e test report image 22 | docker build -t $(REGISTRY)/$(IMAGE):$(TAG) . 23 | 24 | .PHONY: publish-image 25 | publish-image: 26 | docker push $(REGISTRY)/$(IMAGE):$(TAG) 27 | -------------------------------------------------------------------------------- /test/e2e/images/reports/README.md: -------------------------------------------------------------------------------- 1 | # Report builder for conformance tests 2 | 3 | ### Environment variables: 4 | 5 | #### Mandatory 6 | 7 | | Variable | Description | 8 | | ------------- | ------------- | 9 | | INPUT_DIRECTORY | Directory that contains the cucumber json files | 10 | | OUTPUT_DIRECTORY | Directory where the reports will be generated | 11 | 12 | #### Optional 13 | 14 | | Variable | Description | 15 | | ------------- | ------------- | 16 | | INGRESS_CONTROLLER | Information about the ingress controller | 17 | | CONTROLLER_VERSION | ingress controller version | 18 | 19 | ## Building 20 | 21 | ```console 22 | make 23 | ``` 24 | 25 | ### Generation of reports 26 | 27 | ```console 28 | docker run \ 29 | -e BUILD=$(git rev-parse --short HEAD) \ 30 | -e INPUT_DIRECTORY=/input \ 31 | -e OUTPUT_DIRECTORY=/output \ 32 | -v $PWD:/input:ro \ 33 | -v $PWD/output:/output \ 34 | local/reports-builder:0.0 35 | ``` 36 | 37 | ### Display 38 | 39 | The reports are plain HTML files. The file located in `OUTPUT_DIRECTORY/index.html` renders the initial page. 40 | 41 | Using any web server capable of render html is enough. 42 | Like: 43 | 44 | ```console 45 | cd $OUTPUT_DIRECTORY 46 | 47 | python -m http.server 8000 48 | Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 49 | 50 | ``` 51 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/.gitignore: -------------------------------------------------------------------------------- 1 | output 2 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | commonjs: true 4 | es2020: true 5 | extends: 6 | - airbnb-base 7 | parserOptions: 8 | ecmaVersion: 11 9 | rules: {} 10 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Wim Selles 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/README.MD: -------------------------------------------------------------------------------- 1 | Cucumber HTML Reporter 2 | =============================== 3 | 4 | Based on [multiple-cucumber-html-reporter](github/wswebcreation/multiple-cucumber-html-reporter) 5 | 6 | ## Credits 7 | 8 | In the search for a reporting tools for Cucumber I found a few tools that helped me a lot: 9 | 10 | - [multiple-cucumber-html-reporter](github/wswebcreation/multiple-cucumber-html-reporter) 11 | - [cucumber-html-repository](https://github.com/gkushang/cucumber-html-reporter) 12 | - [cucumber-html-report](https://github.com/leinonen/cucumber-html-report) 13 | - [cucumber-protractor-report](https://github.com/JesterXL/cucumber-protractor-report) 14 | - [grunt-protractor-cucumber-html-report](https://github.com/robhil/grunt-protractor-cucumber-html-report) 15 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/lib/collect-jsons.js: -------------------------------------------------------------------------------- 1 | const { readFileSync, statSync } = require('fs-extra'); 2 | const { findJsonFiles, formatToLocalIso } = require('./utils'); 3 | const { parseFeatureHooks, parseMetadata } = require('./parse.cucumber.data'); 4 | 5 | module.exports = function collectJSONS(options) { 6 | const jsonOutput = []; 7 | const files = findJsonFiles(options.jsonDir); 8 | 9 | if (files.length === 0) { 10 | console.log(`WARNING: No JSON files found in '${options.jsonDir}'. NO REPORT CAN BE CREATED!`); 11 | return []; 12 | } 13 | 14 | files.map((file) => { 15 | let data; 16 | // Cucumber json can be empty, it's likely being created by another process (#47) 17 | // or the data could not be a valid JSON-file 18 | try { 19 | data = JSON.parse(readFileSync(file).toString()); 20 | } catch (e) { 21 | data = []; 22 | console.log(`WARNING: File: '${file}' had no valid JSON data due to error:'${e}'. CONTENT WAS NOT LOADED!`); 23 | } 24 | 25 | const jsonData = Array.isArray(data) ? data : [data]; 26 | const stats = statSync(file); 27 | const reportTime = formatToLocalIso(stats.birthtime); 28 | 29 | jsonData.map((json) => { 30 | json = parseMetadata(json, options.metadata); 31 | 32 | if (options.displayReportTime) { 33 | json.metadata = { 34 | ...json.metadata, 35 | ...{ reportTime }, 36 | }; 37 | } 38 | 39 | // Only check the feature hooks if there are elements (fail safe) 40 | const { elements } = json; 41 | 42 | if (elements) { 43 | json.elements = elements.map((scenario) => { 44 | const { before, after } = scenario; 45 | 46 | if (before) { 47 | scenario.steps = parseFeatureHooks(before, 'Before') 48 | .concat(scenario.steps); 49 | } 50 | if (after) { 51 | scenario.steps = scenario.steps 52 | .concat(parseFeatureHooks(after, 'After')); 53 | } 54 | 55 | return scenario; 56 | }); 57 | } 58 | 59 | jsonOutput.push(json); 60 | }); 61 | }); 62 | 63 | return jsonOutput; 64 | }; 65 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-cucumber-html-reporter", 3 | "version": "1.18.0", 4 | "description": "Generate beautiful Cucumber reports for multiple instances purposes", 5 | "keywords": [ 6 | "cucumber", 7 | "html", 8 | "test report", 9 | "multiple-cucumber-html-reporter", 10 | "html report", 11 | "json to html" 12 | ], 13 | "main": "lib/generate-report.js", 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/wswebcreation/multiple-cucumber-html-reporter.git" 18 | }, 19 | "author": "wswebcreation", 20 | "homepage": "https://github.com/wswebcreation/multiple-cucumber-html-reporter#readme", 21 | "dependencies": { 22 | "ejs": "^3.1.3", 23 | "fs-extra": "^9.0.1", 24 | "js-base64": "^3.4.1", 25 | "moment": "^2.27.0" 26 | }, 27 | "devDependencies": { 28 | "coveralls": "^3.1.0", 29 | "eslint": "^7.7.0", 30 | "eslint-config-airbnb-base": "^14.2.0", 31 | "eslint-plugin-import": "^2.22.0", 32 | "jest": "^26.2.1", 33 | "np": "^6.3.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/templates/components/features-overview.chart.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
Features
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | <%if(suite.totalFeaturesCount.ambiguous.count > 0){ %> 28 | 29 | 32 | 33 | 34 | <%} %> 35 | <%if(suite.totalFeaturesCount.notDefined.count > 0){ %> 36 | 37 | 40 | 41 | 42 | <%} %> 43 | <%if(suite.totalFeaturesCount.pending.count > 0){ %> 44 | 45 | 48 | 49 | 50 | <%} %> 51 | <%if(suite.totalFeaturesCount.skipped.count > 0){ %> 52 | 53 | 56 | 57 | 58 | <%} %> 59 | 60 |
StatusProgress
17 |

Passed

18 |
<%- suite.totalFeaturesCount.passed.percentage %>%
23 |

Failed

24 |
<%- suite.totalFeaturesCount.failed.percentage %>%
30 |

Ambiguous

31 |
<%- suite.totalFeaturesCount.ambiguous.percentage %>%
38 |

Not Defined

39 |
<%- suite.totalFeaturesCount.notDefined.percentage %>%
46 |

Pending

47 |
<%- suite.totalFeaturesCount.pending.percentage %>%
54 |

Skipped

55 |
<%- suite.totalFeaturesCount.skipped.percentage %>%
61 |
62 |
63 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/templates/components/scenarios-overview.chart.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
Scenarios
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 25 | <%if (scenarios.ambiguous.count > 0) { %> 26 | 27 | 28 | 31 | 32 | <%} %><%if (scenarios.notDefined.count > 0) { %> 33 | 34 | 37 | 38 | <%} %><%if (scenarios.pending.count > 0) { %> 39 | 40 | 43 | 44 | <%} %><%if (scenarios.skipped.count > 0) { %> 45 | 46 | 49 | 50 | <%} %> 51 | 52 |
StatusProgress
17 |

Passed

18 |
<%- scenarios.passed.percentage %>%
23 |

Failed

24 |
<%- scenarios.failed.percentage %>%
29 |

Ambiguous

30 |
<%- scenarios.ambiguous.percentage %>%
35 |

Not defined

36 |
<%- scenarios.notDefined.percentage %>%
41 |

Pending

42 |
<%- scenarios.pending.percentage %>%
47 |

Skipped

48 |
<%- scenarios.skipped.percentage %>%
53 |
54 |
55 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/cucumber-html-reporter/templates/generic.js: -------------------------------------------------------------------------------- 1 | $('body').tooltip({ 2 | selector: '[data-toggle="tooltip"]' 3 | }); -------------------------------------------------------------------------------- /test/e2e/images/reports/src/index.js: -------------------------------------------------------------------------------- 1 | const report = require("./cucumber-html-reporter"); 2 | const assert = require("assert"); 3 | 4 | assert(process.env.INPUT_DIRECTORY, "Environment variable INPUT_DIRECTORY is not optional"); 5 | assert(process.env.OUTPUT_DIRECTORY, "Environment variable OUTPUT_DIRECTORY is not optional"); 6 | 7 | report.generate({ 8 | jsonDir: process.env.INPUT_DIRECTORY, 9 | reportPath: process.env.OUTPUT_DIRECTORY, 10 | pageFooter: '

BFE ingress controller e2e test

', 11 | ingress: { 12 | controller: process.env.INGRESS_CONTROLLER || 'N/A', 13 | version: process.env.CONTROLLER_VERSION || 'N/A' 14 | }, 15 | buildTime: process.env.BUILD 16 | }); 17 | -------------------------------------------------------------------------------- /test/e2e/images/reports/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ingress-conformance-reports", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "ejs": "^3.1.5", 6 | "fs-extra": "^9.0.1", 7 | "js-base64": "^3.4.5", 8 | "moment": "^2.27.0" 9 | }, 10 | "scripts": { 11 | "run": "node index" 12 | }, 13 | "license": "Apache-2.0" 14 | } 15 | -------------------------------------------------------------------------------- /test/e2e/pkg/files/files.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package files 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "os" 23 | ) 24 | 25 | // Read tries to retrieve the desired file content from 26 | // one of the registered file sources. 27 | func Read(path string) ([]byte, error) { 28 | if exists := Exists(path); !exists { 29 | return nil, fmt.Errorf("file %v does not exists", path) 30 | } 31 | 32 | data, err := ioutil.ReadFile(path) 33 | if err != nil { 34 | return nil, fmt.Errorf("fatal error retrieving test file %s: %s", path, err) 35 | } 36 | 37 | return data, nil 38 | } 39 | 40 | // Exists checks whether a file could be read. Unexpected errors 41 | // are handled by calling the fail function, which then should 42 | // abort the current test. 43 | func Exists(path string) bool { 44 | _, err := os.Stat(path) 45 | if os.IsNotExist(err) { 46 | return false 47 | } 48 | 49 | return true 50 | } 51 | 52 | // IsDir reports whether path is a directory 53 | func IsDir(path string) bool { 54 | info, err := os.Stat(path) 55 | if os.IsNotExist(err) { 56 | return false 57 | } 58 | 59 | return info.IsDir() 60 | } 61 | -------------------------------------------------------------------------------- /test/e2e/pkg/kubernetes/templates/templates.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package templates 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | text_template "text/template" 23 | ) 24 | 25 | var k8sTemplates = map[string]string{ 26 | "deployment": ` 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: {{ .Name }} 31 | spec: 32 | replicas: 1 33 | strategy: 34 | type: RollingUpdate 35 | selector: 36 | matchLabels: 37 | app: {{ .MatchLabels }} 38 | template: 39 | metadata: 40 | labels: 41 | app: {{ .Labels }} 42 | spec: 43 | containers: 44 | - name: ingress-conformance-echo 45 | image: {{ .Image }} 46 | env: 47 | - name: POD_NAME 48 | valueFrom: 49 | fieldRef: 50 | fieldPath: metadata.name 51 | - name: NAMESPACE 52 | valueFrom: 53 | fieldRef: 54 | fieldPath: metadata.namespace 55 | - name: INGRESS_NAME 56 | value: {{ .Ingress }} 57 | - name: SERVICE_NAME 58 | value: {{ .Service }} 59 | ports: 60 | - name: {{ .PortName }} 61 | containerPort: 3000 62 | livenessProbe: 63 | httpGet: 64 | path: /health 65 | port: 3000 66 | scheme: HTTP 67 | initialDelaySeconds: 1 68 | periodSeconds: 1 69 | timeoutSeconds: 1 70 | successThreshold: 1 71 | failureThreshold: 10 72 | readinessProbe: 73 | httpGet: 74 | path: /health 75 | port: 3000 76 | scheme: HTTP 77 | initialDelaySeconds: 1 78 | periodSeconds: 1 79 | timeoutSeconds: 1 80 | successThreshold: 1 81 | failureThreshold: 10 82 | `, 83 | "service": ` 84 | apiVersion: v1 85 | kind: Service 86 | metadata: 87 | name: {{ .Name }} 88 | spec: 89 | type: NodePort 90 | selector: 91 | app: {{ .Selector }} 92 | ports: 93 | - port: {{ .Port }} 94 | targetPort: 3000 95 | `, 96 | } 97 | 98 | var templates = map[string]*text_template.Template{} 99 | 100 | // Load parses templates required to deploy Kubernetes objects 101 | func Load() error { 102 | for name, template := range k8sTemplates { 103 | tmpl, err := text_template.New(name).Parse(template) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | templates[name] = tmpl 109 | } 110 | 111 | return nil 112 | } 113 | 114 | // Render executes a parsed template to the specified data object 115 | func Render(name string, data interface{}) (string, error) { 116 | tmpl, ok := templates[name] 117 | if !ok { 118 | return "", fmt.Errorf("there is no template with name %v", name) 119 | } 120 | 121 | var tpl bytes.Buffer 122 | err := tmpl.Execute(&tpl, data) 123 | if err != nil { 124 | return "", err 125 | } 126 | 127 | return tpl.String(), nil 128 | } 129 | -------------------------------------------------------------------------------- /test/e2e/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 The BFE Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -ex 18 | 19 | trap TERM 20 | 21 | cd "$(dirname "$0")" 22 | 23 | RESULTS_DIR="${RESULTS_DIR:-$PWD/result}" 24 | if [[ -d $RESULTS_DIR ]]; then 25 | rm -rf $RESULTS_DIR/* 26 | else 27 | mkdir $RESULTS_DIR 28 | fi 29 | 30 | make build 31 | 32 | CUCUMBER_OUTPUT_FORMAT="${CUCUMBER_OUTPUT_FORMAT:-pretty}" 33 | WAIT_FOR_STATUS_TIMEOUT="${WAIT_FOR_STATUS_TIMEOUT:-5m}" 34 | TEST_TIMEOUT="${TEST_TIMEOUT:-0}" 35 | TEST_PARALLEL="${TEST_PARALLEL:-5}" 36 | 37 | ./e2e_test \ 38 | --output-directory="${RESULTS_DIR}" \ 39 | --feature="${CUCUMBER_FEATURE}" \ 40 | --format="${CUCUMBER_OUTPUT_FORMAT}" \ 41 | --wait-time-for-ingress-status="${WAIT_FOR_STATUS_TIMEOUT}" \ 42 | --wait-time-for-ready="${WAIT_FOR_STATUS_TIMEOUT}" \ 43 | --test.timeout="${TEST_TIMEOUT}" \ 44 | --feature-parallel="${TEST_PARALLEL}" 45 | ret=$? 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /test/e2e/steps/conformance/ingressclass/steps.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The BFE Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ingressclass 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/cucumber/godog" 23 | "github.com/cucumber/messages-go/v16" 24 | 25 | "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/kubernetes" 26 | tstate "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/state" 27 | ) 28 | 29 | var ( 30 | state *tstate.Scenario 31 | ) 32 | 33 | // IMPORTANT: Steps definitions are generated and should not be modified 34 | // by hand but rather through make codegen. DO NOT EDIT. 35 | 36 | // InitializeScenario configures the Feature to test 37 | func InitializeScenario(ctx *godog.ScenarioContext) { 38 | ctx.Step(`^an Ingress resource in a new random namespace$`, anIngressResourceInANewRandomNamespace) 39 | ctx.Step(`^The Ingress status should not contain the IP address or FQDN$`, theIngressStatusShouldNotContainTheIPAddressOrFQDN) 40 | 41 | ctx.BeforeScenario(func(*godog.Scenario) { 42 | state = tstate.New() 43 | }) 44 | 45 | ctx.AfterScenario(func(*messages.Pickle, error) { 46 | // delete namespace an all the content 47 | _ = kubernetes.DeleteNamespace(kubernetes.KubeClient, state.Namespace) 48 | }) 49 | } 50 | 51 | func anIngressResourceInANewRandomNamespace(spec *godog.DocString) error { 52 | ns, err := kubernetes.NewNamespace(kubernetes.KubeClient) 53 | if err != nil { 54 | return err 55 | } 56 | 57 | state.Namespace = ns 58 | 59 | ingress, err := kubernetes.IngressFromManifest(state.Namespace, spec.Content) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | err = kubernetes.DeploymentsFromIngress(kubernetes.KubeClient, ingress) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | err = kubernetes.NewIngress(kubernetes.KubeClient, state.Namespace, ingress) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | state.IngressName = ingress.GetName() 75 | 76 | return nil 77 | } 78 | 79 | func theIngressStatusShouldNotContainTheIPAddressOrFQDN() error { 80 | _, err := kubernetes.WaitForIngressAddress(kubernetes.KubeClient, state.Namespace, state.IngressName) 81 | if err == nil { 82 | return fmt.Errorf("waiting for Ingress status should not return an IP address or FQDN") 83 | } 84 | 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /test/e2e/steps/rules/patherr/steps.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The BFE Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package patherr 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/cucumber/godog" 23 | "github.com/cucumber/messages-go/v16" 24 | 25 | "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/kubernetes" 26 | tstate "github.com/bfenetworks/ingress-bfe/test/e2e/pkg/state" 27 | ) 28 | 29 | var ( 30 | state *tstate.Scenario 31 | ) 32 | 33 | // IMPORTANT: Steps definitions are generated and should not be modified 34 | // by hand but rather through make codegen. DO NOT EDIT. 35 | 36 | // InitializeScenario configures the Feature to test 37 | func InitializeScenario(ctx *godog.ScenarioContext) { 38 | ctx.Step(`^an Ingress resource in a new random namespace should not create$`, anIngressResourceInANewRandomNamespaceShouldNotCreate) 39 | 40 | ctx.BeforeScenario(func(*godog.Scenario) { 41 | state = tstate.New() 42 | }) 43 | 44 | ctx.AfterScenario(func(*messages.Pickle, error) { 45 | // delete namespace an all the content 46 | _ = kubernetes.DeleteNamespace(kubernetes.KubeClient, state.Namespace) 47 | }) 48 | } 49 | 50 | func anIngressResourceInANewRandomNamespaceShouldNotCreate(spec *godog.DocString) error { 51 | ns, err := kubernetes.NewNamespace(kubernetes.KubeClient) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | state.Namespace = ns 57 | 58 | ingress, err := kubernetes.IngressFromManifest(state.Namespace, spec.Content) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | err = kubernetes.DeploymentsFromIngress(kubernetes.KubeClient, ingress) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | err = kubernetes.NewIngress(kubernetes.KubeClient, state.Namespace, ingress) 69 | if err == nil { 70 | return fmt.Errorf("create ingress should return error") 71 | } 72 | 73 | state.IngressName = ingress.GetName() 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /test/script/controller-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: bfe-controller-service 5 | namespace: ingress-bfe 6 | labels: 7 | app.kubernetes.io/name: bfe-ingress-controller 8 | app.kubernetes.io/instance: bfe-ingress-controller 9 | spec: 10 | type: NodePort 11 | selector: 12 | app.kubernetes.io/name: bfe-ingress-controller 13 | app.kubernetes.io/instance: bfe-ingress-controller 14 | ports: 15 | - name: http 16 | port: 8080 17 | targetPort: 8080 18 | nodePort: 30000 19 | - name: https 20 | port: 8443 21 | targetPort: 8443 22 | nodePort: 30001 23 | -------------------------------------------------------------------------------- /test/script/deploy-controller.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -e 16 | 17 | download_kubectl(){ 18 | if [[ "$OSTYPE" == "linux-gnu"* ]]; then 19 | # linux 20 | echo "linux" 21 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" 22 | 23 | elif [[ "$OSTYPE" == "darwin"* ]]; then 24 | # Mac 25 | if [[ $(arch) == 'arm64' ]]; then 26 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl" 27 | 28 | else 29 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl" 30 | fi 31 | else 32 | echo "unsupported os type: " "$OSTYPE" 33 | exit 1 34 | fi 35 | 36 | chmod +x ./kubectl 37 | 38 | } 39 | 40 | cd "$(dirname "$0")" 41 | VERSION=$1 42 | 43 | IMAGE="bfenetworks/bfe-ingress-controller:"$VERSION 44 | 45 | if [[ "$(docker images -q $IMAGE 2> /dev/null)" == "" ]]; then 46 | echo "image does not exist:" "$IMAGE" 47 | exit 1 48 | fi 49 | 50 | if [[ ! -f kubectl ]]; then 51 | download_kubectl 52 | fi 53 | 54 | # update yaml to version 55 | sed "s#image: .*\$#image: $IMAGE#g" ../../examples/controller-all.yaml > controller-all.yaml 56 | 57 | ./kubectl apply -f controller-all.yaml 58 | ./kubectl apply -f controller-svc.yaml -f ingressclass.yaml 59 | 60 | -------------------------------------------------------------------------------- /test/script/ingressclass.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: IngressClass 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | name: bfe 7 | namespace: ingress-bfe 8 | annotations: 9 | ingressclass.kubernetes.io/is-default-class: "true" 10 | spec: 11 | controller: bfe-networks.com/ingress-controller 12 | -------------------------------------------------------------------------------- /test/script/kind-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | nodes: 4 | - role: control-plane 5 | kubeadmConfigPatches: 6 | - | 7 | kind: InitConfiguration 8 | nodeRegistration: 9 | kubeletExtraArgs: 10 | node-labels: "ingress-ready=true" 11 | controllerManager: 12 | extraArgs: 13 | namespace-sync-period: 10s 14 | concurrent-deployment-syncs: "30" 15 | deployment-controller-sync-period: 10s 16 | extraPortMappings: 17 | - containerPort: 30000 18 | hostPort: 30000 19 | protocol: TCP 20 | - containerPort: 30001 21 | hostPort: 30001 22 | protocol: TCP 23 | - role: worker 24 | -------------------------------------------------------------------------------- /test/script/kind-create-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -ex 16 | 17 | 18 | download_kind(){ 19 | if [[ "$OSTYPE" == "linux-gnu"* ]]; then 20 | # linux 21 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 22 | 23 | elif [[ "$OSTYPE" == "darwin"* ]]; then 24 | # Mac 25 | if [[ $(arch) == 'arm64' ]]; then 26 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-darwin-arm64 27 | else 28 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-darwin-amd64 29 | fi 30 | else 31 | echo "unsupported os type: " "$OSTYPE" 32 | exit 1 33 | fi 34 | chmod +x ./kind 35 | } 36 | 37 | cd "$(dirname "$0")" 38 | 39 | if [[ ! -f kind ]]; then 40 | download_kind 41 | fi 42 | 43 | # check if cluster exist 44 | if ./kind get clusters | grep -Fxq "kind"; then 45 | exit 0 46 | fi 47 | 48 | ./kind create cluster --config=./kind-config.yaml 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/script/kind-delete-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -e 16 | 17 | cd "$(dirname "$0")" 18 | 19 | ./kind delete cluster 20 | -------------------------------------------------------------------------------- /test/script/kind-load-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 The BFE Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -e 16 | 17 | cd "$(dirname "$0")" 18 | 19 | # load bfe-ingress-controller image 20 | VERSION=$1 21 | IMAGE="bfenetworks/bfe-ingress-controller:"$VERSION 22 | 23 | if [[ "$(docker images -q $IMAGE 2> /dev/null)" == "" ]]; then 24 | echo "image does not exist:" "$IMAGE" 25 | exit 1 26 | fi 27 | 28 | ./kind load docker-image $IMAGE 29 | 30 | # build and load backend image (echoserver) 31 | IMAGE="local/echoserver:0.0.1" 32 | 33 | if [[ "$(docker images -q $IMAGE 2> /dev/null)" == "" ]]; then 34 | (cd ../e2e/images/echoserver; make build-image) 35 | fi 36 | 37 | ./kind load docker-image $IMAGE 38 | --------------------------------------------------------------------------------