diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6f48169bb..b01448af0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,11 +3,11 @@ PLEASE READ THIS MESSAGE. Documentation fixes or enhancements: - for Traefik v2: use branch v2.10 -- for Traefik v3: use branch master +- for Traefik v3: use branch v3.0 Bug fixes: - for Traefik v2: use branch v2.10 -- for Traefik v3: use branch master +- for Traefik v3: use branch v3.0 Enhancements: - for Traefik v2: we only accept bug fixes diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 69de25cf4..483085825 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -7,7 +7,7 @@ on: env: GO_VERSION: '1.20' - GOLANGCI_LINT_VERSION: v1.51.2 + GOLANGCI_LINT_VERSION: v1.52.2 MISSSPELL_VERSION: v0.4.0 IN_DOCKER: "" diff --git a/.golangci.yml b/.golangci.yml index c8baa7f6b..3af93d19e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,9 +6,10 @@ run: linters-settings: govet: - check-shadowing: false - golint: - min-confidence: 0 + enable-all: true + disable: + - shadow + - fieldalignment gocyclo: min-complexity: 14 goconst: @@ -33,40 +34,112 @@ linters-settings: keywords: - FIXME importas: - corev1: k8s.io/api/core/v1 - networkingv1beta1: k8s.io/api/networking/v1beta1 - extensionsv1beta1: k8s.io/api/extensions/v1beta1 - metav1: k8s.io/apimachinery/pkg/apis/meta/v1 - kubeerror: k8s.io/apimachinery/pkg/api/errors - composeapi: github.com/docker/compose/v2/pkg/api + no-unaliased: true + alias: + - alias: composeapi + pkg: github.com/docker/compose/v2/pkg/api + + # Standard Kubernetes rewrites: + - alias: corev1 + pkg: "k8s.io/api/core/v1" + - alias: netv1 + pkg: "k8s.io/api/networking/v1" + - alias: netv1beta1 + pkg: "k8s.io/api/networking/v1beta1" + - alias: admv1 + pkg: "k8s.io/api/admission/v1" + - alias: admv1beta1 + pkg: "k8s.io/api/admission/v1beta1" + - alias: extv1beta1 + pkg: "k8s.io/api/extensions/v1beta1" + - alias: metav1 + pkg: "k8s.io/apimachinery/pkg/apis/meta/v1" + - alias: ktypes + pkg: "k8s.io/apimachinery/pkg/types" + - alias: kerror + pkg: "k8s.io/apimachinery/pkg/api/errors" + - alias: kclientset + pkg: "k8s.io/client-go/kubernetes" + - alias: kinformers + pkg: "k8s.io/client-go/informers" + - alias: ktesting + pkg: "k8s.io/client-go/testing" + - alias: kschema + pkg: "k8s.io/apimachinery/pkg/runtime/schema" + - alias: kscheme + pkg: "k8s.io/client-go/kubernetes/scheme" + - alias: kversion + pkg: "k8s.io/apimachinery/pkg/version" + - alias: kubefake + pkg: "k8s.io/client-go/kubernetes/fake" + - alias: discoveryfake + pkg: "k8s.io/client-go/discovery/fake" + + # Kubernetes Gateway rewrites: + - alias: gateclientset + pkg: "sigs.k8s.io/gateway-api/pkg/client/clientset/gateway/versioned" + - alias: gateinformers + pkg: "sigs.k8s.io/gateway-api/pkg/client/informers/gateway/externalversions" + - alias: gatev1alpha2 + pkg: "sigs.k8s.io/gateway-api/apis/v1alpha2" + + # Traefik Kubernetes rewrites: + - alias: containousv1alpha1 + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikcontainous/v1alpha1" + - alias: traefikv1alpha1 + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + - alias: traefikclientset + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned" + - alias: traefikinformers + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions" + - alias: traefikscheme + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/scheme" + - alias: traefikcrdfake + pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake" + tagalign: + align: false + sort: true + order: + - description + - json + - toml + - yaml + - yml + - label + - label-slice-as-struct + - file + - kv + - export revive: rules: - name: struct-tag - rules: - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + disabled: true + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + disabled: true + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + disabled: true + - name: unreachable-code + - name: redefines-builtin-id gomoddirectives: replace-allow-list: - github.com/abbot/go-http-auth @@ -183,3 +256,7 @@ issues: text: "Function 'loadConfigurationFromCRD' has too many statements" linters: - funlen + - path: pkg/provider/kubernetes/gateway/client_mock_test.go + text: 'unusedwrite: unused write to field' + linters: + - govet diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 95ea73ed1..f463b9f9d 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -25,7 +25,7 @@ global_job_config: - export "PATH=${GOPATH}/bin:${PATH}" - mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin" - export GOPROXY=https://proxy.golang.org,direct - - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.50.0 + - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.52.2 - curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin" - checkout - cache restore traefik-$(checksum go.sum) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc9a911ca..76d40012f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## [v2.10.0-rc2](https://github.com/traefik/traefik/tree/v2.10.0-rc2) (2023-04-07) +[All Commits](https://github.com/traefik/traefik/compare/v2.10.0-rc1...v2.10.0-rc2) + +**Enhancements:** +- **[webui]** Display period setting of the RateLimit middleware in the webui ([#9822](https://github.com/traefik/traefik/pull/9822) by [smatyas](https://github.com/smatyas)) + +**Bug fixes:** +- **[docker]** Only warn about missing docker network when network_mode is not host or container ([#9799](https://github.com/traefik/traefik/pull/9799) by [sentriz](https://github.com/sentriz)) +- **[k8s/ingress,k8s]** chore: bump k8s.io/client-go from v0.22.1 to v0.26.3 ([#9808](https://github.com/traefik/traefik/pull/9808) by [ldez](https://github.com/ldez)) +- **[plugins]** Update Yaegi to v0.15.1 ([#9815](https://github.com/traefik/traefik/pull/9815) by [ldez](https://github.com/ldez)) + +**Documentation:** +- **[docker]** Update wording - add link descriptions ([#9816](https://github.com/traefik/traefik/pull/9816) by [svx](https://github.com/svx)) +- **[middleware]** Add accessControlAllowHeaders example ([#9810](https://github.com/traefik/traefik/pull/9810) by [yingshaoxo](https://github.com/yingshaoxo)) +- Update Call To Actions ([#9824](https://github.com/traefik/traefik/pull/9824) by [svx](https://github.com/svx)) +- Improve concepts page ([#9813](https://github.com/traefik/traefik/pull/9813) by [svx](https://github.com/svx)) +- Update wording ([#9811](https://github.com/traefik/traefik/pull/9811) by [svx](https://github.com/svx)) + +## [v2.9.10](https://github.com/traefik/traefik/tree/v2.9.10) (2023-04-06) +[All Commits](https://github.com/traefik/traefik/compare/v2.9.9...v2.9.10) + ## [v2.10.0-rc1](https://github.com/traefik/traefik/tree/v2.10.0-rc1) (2023-03-22) [All Commits](https://github.com/traefik/traefik/compare/b3f162a8a61d89beaa9edc8adc12cc4cb3e1de0f...v2.10.0-rc1) diff --git a/Makefile b/Makefile index 0c957b003..8de756967 100644 --- a/Makefile +++ b/Makefile @@ -189,7 +189,7 @@ generate-genconf: .PHONY: release-packages release-packages: generate-webui build-dev-image rm -rf dist - $(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) goreleaser release --skip-publish -p 4 --timeout="90m" + $(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) goreleaser release --skip-publish -p 2 --timeout="90m" $(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) tar cfz dist/traefik-${VERSION}.src.tar.gz \ --exclude-vcs \ --exclude .idea \ diff --git a/build.Dockerfile b/build.Dockerfile index 6d4ba8625..ce037bbfd 100644 --- a/build.Dockerfile +++ b/build.Dockerfile @@ -13,7 +13,7 @@ RUN mkdir -p /usr/local/bin \ | tar -xzC /usr/local/bin --transform 's#^.+/##x' # Download golangci-lint binary to bin folder in $GOPATH -RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.50.0 +RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.52.2 # Download misspell binary to bin folder in $GOPATH RUN curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.4.0 diff --git a/docs/content/contributing/advocating.md b/docs/content/contributing/advocating.md index 785c97156..c7bbaacd7 100644 --- a/docs/content/contributing/advocating.md +++ b/docs/content/contributing/advocating.md @@ -9,7 +9,7 @@ Spread the Love & Tell Us about It {: .subtitle } Traefik Proxy was started by the community for the community. -You can contribute to the Traefik community in three main ways: +You can contribute to the Traefik community in three main ways: **Spread the word!** Guides, videos, blog posts, how-to articles, and showing off your network design all help spread the word about Traefik Proxy and teach others in the community how to best implement it. @@ -28,4 +28,4 @@ Luckily, as an open source community, our users can help by [building awesome fe We are a big community, so we do need to prioritize a bit. That is why we use the tag `contributor/wanted` to let you know which pull requests will make it to the front of the queue for design support and review. Feel free to grab one of these and run with it. -Top contributors get unique swag to celebrate. +Top contributors get unique swag to celebrate. diff --git a/docs/content/contributing/data-collection.md b/docs/content/contributing/data-collection.md index cb047d8fe..f68f329cc 100644 --- a/docs/content/contributing/data-collection.md +++ b/docs/content/contributing/data-collection.md @@ -10,8 +10,8 @@ Understanding How Traefik is Being Used ## Configuration Example -Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways. -For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us so we can benefit from your experience and use cases. +Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways. +For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us, so we can benefit from your experience and use cases. !!! example "Enabling Data Collection" @@ -34,9 +34,7 @@ For this very reason, the sendAnonymousUsage option is mandatory: we want you to ## Collected Data -This feature comes from the public proposal [here](https://github.com/traefik/traefik/issues/2369). - -This feature is activated when using Traefik Pilot to better understand the community's need, and also to get information about plug-ins popularity. +This feature comes from this [public proposal](https://github.com/traefik/traefik/issues/2369). In order to help us learn more about how Traefik is being used and improve it, we collect anonymous usage statistics from running instances. Those data help us prioritize our developments and focus on what's important for our users (for example, which provider is popular, and which is not). @@ -47,7 +45,7 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col - the Traefik version number - a hash of the configuration -- an **anonymized version** of the static configuration (token, user name, password, URL, IP, domain, email, etc, are removed). +- an **anonymized version** of the static configuration (token, username, password, URL, IP, domain, email, etc., are removed). !!! info @@ -101,4 +99,4 @@ providers: If you want to dig into more details, here is the source code of the collecting system: [collector.go](https://github.com/traefik/traefik/blob/master/pkg/collector/collector.go) -By default we anonymize all configuration fields, except fields tagged with `export=true`. +By default, we anonymize all configuration fields, except fields tagged with `export=true`. diff --git a/docs/content/contributing/maintainers-guidelines.md b/docs/content/contributing/maintainers-guidelines.md index b1d2a0432..049bd92e8 100644 --- a/docs/content/contributing/maintainers-guidelines.md +++ b/docs/content/contributing/maintainers-guidelines.md @@ -11,7 +11,7 @@ Note: the document is a work in progress. Welcome to the Traefik Community. This document describes how to be part of the core team -as well as various responsibilities +together with various responsibilities and guidelines for Traefik maintainers. We are strongly promoting a philosophy of openness and sharing, and firmly standing against the elitist closed approach. @@ -20,7 +20,7 @@ and wants to be part of that journey! ## Onboarding Process -If you consider joining our community please drop us a line using Twitter or leave a note in the issue. +If you consider joining our community, please drop us a line using Twitter or leave a note in the issue. We will schedule a quick call to meet you and learn more about your motivation. During the call, the team will discuss the process of becoming a maintainer. We will be happy to answer any questions and explain all your doubts. @@ -53,7 +53,7 @@ but we can suggest you start with activities such as: Each of the issues that are labeled as bug/possible bug/confirmed requires a reproducible use case. You can help in creating a reproducible use case if it has not been added to the issue or use the sample code provided by the reporter. - Typically, a simple docker compose should be enough to reproduce the issue. + Typically, a simple Docker Compose should be enough to reproduce the issue. - Code contribution. - Documentation contribution. - Technical documentation is one of the most important components of the product. @@ -61,7 +61,7 @@ but we can suggest you start with activities such as: using the official documentation, is a game changer. - You will be listed on our Maintainers GitHub page - as well as on our website in the section [maintainers](maintainers.md). + and on our website in the section [maintainers](maintainers.md). - We will be promoting you on social channels (mostly on Twitter). ## Governance @@ -71,7 +71,7 @@ but we can suggest you start with activities such as: ## Communicating - All of our maintainers are added to Slack #traefik-maintainers channel that belongs to Traefik labs workspace. - Having the team in one place helps us to communicate effectively. + Having the team in one place helps us to communicate effectively. You can reach Traefik core developers directly, which offers the possibility to discuss issues, pull requests, enhancements more efficiently and get the feedback almost immediately. @@ -112,9 +112,9 @@ maintainers' activity and involvement will be reviewed on a regular basis. - Be able to put yourself in users’ shoes. - Be open-minded and respectful with other maintainers and other community members. -- Keep the communication public - +- Keep the communication public - if anyone tries to communicate with you directly, - ask him politely to move the conversation to a public communication channel. + ask politely to move the conversation to a public communication channel. - Stay away from defensive comments. - Please try to express your thoughts clearly enough and note that some of us are not native English speakers. @@ -122,7 +122,7 @@ maintainers' activity and involvement will be reviewed on a regular basis. none of us is able to predict your thoughts. - There are a lot of use cases of using Traefik and even more issues that are difficult to reproduce. - If the issue can’t be replicated due to a lack of reproducible case (a simple docker compose should be enough) - + If the issue can’t be replicated due to a lack of reproducible case (a simple Docker Compose should be enough) - set your time limits while working on the issue and express clearly that you were not able to replicate it. You can come back later to that case. diff --git a/docs/content/contributing/submitting-issues.md b/docs/content/contributing/submitting-issues.md index 9a06c3e99..89826aac9 100644 --- a/docs/content/contributing/submitting-issues.md +++ b/docs/content/contributing/submitting-issues.md @@ -9,10 +9,10 @@ Help Us Help You! {: .subtitle } Issues are perfect for requesting a feature/enhancement or reporting a suspected bug. -We use the [GitHub issue tracker](https://github.com/traefik/traefik/issues) to keep track of issues in Traefik. +We use the [GitHub issue tracker](https://github.com/traefik/traefik/issues) to keep track of issues in Traefik. The process of sorting and checking the issues is a daunting task, and requires a lot of work (more than an hour a day ... just for sorting). -To help us (and other community members) quickly and easily understand what you need, +To help us (and other community members) quickly and effortlessly understand what you need, be sure to follow the guidelines below. !!! important "Getting Help Vs Reporting an Issue" @@ -33,16 +33,17 @@ Examples: ## Feature Request -Traefik is an open source project and aims to be the best edge router possible. +Traefik is an open source project and aims to be the best edge router possible. Remember when asking for new features that these must be useful to the majority (and not only useful in edge case scenarios, or hack-like setups). Follow the [issue template](https://github.com/traefik/traefik/blob/master/.github/ISSUE_TEMPLATE/feature-request.yml) as much as possible. Do your best to explain what you're looking for, and why it would improve Traefik for everyone. Be detailed and share the use-case(s) to allow us to see the value of your feature request as quickly as possible. -Features with a lot of positive interaction (claps, +1s, conversation about how this would impact them) indicate higher community interest and help us to prioritize. -If you are interested in creating a PR for your feature request, let us know in the the issue so we can work with you. +Features with a lot of positive interaction (claps, +1s, conversation about how this would impact them) indicate higher community interest and help us to prioritize. + +If you are interested in creating a PR for your feature request, let us know in the issue, so we can work with you. It can take a lot of work to make sure a PR can integrate with our existing code and planning with the team ahead of time can make sure that your PR can be accepted and merged quickly. ## Issues or Possible Bug Reports @@ -50,13 +51,13 @@ It can take a lot of work to make sure a PR can integrate with our existing code Follow the [issue template](https://github.com/traefik/traefik/blob/master/.github/ISSUE_TEMPLATE/bug_report.yml) as much as possible. Explain the conditions in which you encountered the issue; what is your context? -Share any logs you may have and make sure to share the steps it takes to reproduce your issue or bug. +Share any logs you may have, and make sure to share the steps it takes to reproduce your issue or bug. Remain as clear and concise as possible. -Take time to polish the format of your message so we'll enjoy reading it and working on it. +Take time to polish the format of your message, so we'll enjoy reading it and working on it. Help your readers focus on what matters and help them understand the structure of your message (see the [GitHub Markdown Syntax](https://docs.github.com/en/get-started/writing-on-github)). ## International English -Every maintainer / Traefik user is not a native English speaker, so if you feel sometimes that some messages sound rude, remember that it probably is a language barrier problem from someone willing to help you. +Every maintainer / Traefik user is not a native English speaker, so if you sometimes feel that some messages sound rude, remember that it probably is a language barrier problem from someone willing to help you. diff --git a/docs/content/contributing/submitting-pull-requests.md b/docs/content/contributing/submitting-pull-requests.md index 855c04cf4..2e6a666fb 100644 --- a/docs/content/contributing/submitting-pull-requests.md +++ b/docs/content/contributing/submitting-pull-requests.md @@ -5,22 +5,22 @@ description: "Looking to contribute to Traefik Proxy? This guide will show you t # Before You Submit a Pull Request -This guide is for contributors who already have a pull request to submit. -If you are looking for information on setting up your developer environment -and creating code to contribute to Traefik Proxy or related projects, +This guide is for contributors who already have a pull request to submit. +If you are looking for information on setting up your developer environment +and creating code to contribute to Traefik Proxy or related projects, see the [development guide](https://docs.traefik.io/contributing/building-testing/). -Looking for a way to contribute to Traefik Proxy? -Check out this list of [Priority Issues](https://github.com/traefik/traefik/labels/contributor%2Fwanted), -the [Good First Issue](https://github.com/traefik/traefik/labels/contributor%2Fgood-first-issue) list, +Looking for a way to contribute to Traefik Proxy? +Check out this list of [Priority Issues](https://github.com/traefik/traefik/labels/contributor%2Fwanted), +the [Good First Issue](https://github.com/traefik/traefik/labels/contributor%2Fgood-first-issue) list, or the list of [confirmed bugs](https://github.com/traefik/traefik/labels/kind%2Fbug%2Fconfirmed) waiting to be remedied. ## How We Prioritize -We wish we could review every pull request right away. -Unfortunately, our team has to prioritize pull requests (PRs) for review -(but we are welcoming new [maintainers](https://github.com/traefik/traefik/blob/master/docs/content/contributing/maintainers-guidelines.md) to speed this up, -so if you are interested, check it out and apply). +We wish we could review every pull request right away. +Unfortunately, our team has to prioritize pull requests (PRs) for review +(but we are welcoming new [maintainers](https://github.com/traefik/traefik/blob/master/docs/content/contributing/maintainers-guidelines.md) to speed this up, +if you are interested, check it out and apply). The PRs we are able to handle fastest are: @@ -30,20 +30,20 @@ The PRs we are able to handle fastest are: PRs that take more time to address include: -* Enhancements or Features without the `contributor/wanted` tag. - -If you have an idea for an enhancement or feature that you would like to build, -[create an issue](https://github.com/traefik/traefik/issues/new/choose) for it first -and tell us you are interested in writing the PR. -If an issue already exists, definitely comment on it to tell us you are interested in creating a PR. +* Enhancements or Features without the `contributor/wanted` tag. + +If you have an idea for an enhancement or feature that you would like to build, +[create an issue](https://github.com/traefik/traefik/issues/new/choose) for it first +and tell us you are interested in writing the PR. +If an issue already exists, definitely comment on it to tell us you are interested in creating a PR. + +This will allow us to communicate directly and let you know if it is something we would accept. + +It also allows us to make sure you have all the information you need during the design phase +so that it can be reviewed and merged quickly. + +Read more about the [Triage process](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md) in the docs. -This will allow us to communicate directly and let you know if it is something we would accept. -It also allows us to make sure you have all the information you need during the design phase -so that it can be reviewed and merged quickly. - -If you have questions about the Triage process, -[read more here](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md). - ## The Pull Request Submit Process Merging a PR requires the following steps to be completed before it is merged automatically. @@ -63,8 +63,8 @@ Merging a PR requires the following steps to be completed before it is merged au ## Pull Request Review Cycle -You can read about our Triage Process [here](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md), -but in short, it looks like this: +Learn about our [Triage Process](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md), +in short, it looks like this: * We triage every new PR or comment before entering it into the review process. * We ensure that all prerequisites for review have been met. @@ -76,20 +76,20 @@ but in short, it looks like this: * Code Review. * We review the code in-depth and run tests. * We may ask for changes here. - * During code review, we ask that you be reasonably responsive, - if a PR languishes in code review it is at risk of rejection, + * During code review, we ask that you be reasonably responsive, + if a PR languishes in code review it is at risk of rejection, or we may take ownership of the PR and the contributor will become a co-author. -* Merge. +* Merge. * Success! !!! note - Occasionally, we may freeze our codebase when working towards a specific feature or goal that could impact other development. + Occasionally, we may freeze our codebase when working towards a specific feature or goal that could impact other development. During this time, your pull request could remain unmerged while the release work is completed. ## Run Local Verifications -You must run these local verifications before you submit your pull request to predict the pass or failure of continuous integration. +You must run these local verifications before you submit your pull request to predict the pass or failure of continuous integration. Your PR will not be reviewed until these are green on the CI. * `make validate` @@ -98,10 +98,10 @@ Your PR will not be reviewed until these are green on the CI. ## The Testing and Merge Workflow -Pull Requests are managed by the bot [Myrmica Lobicornis](https://github.com/traefik/lobicornis). -This bot is responsible for verifying GitHub Checks (CI, Tests, etc), mergability, and minimum reviews. -In addition, it rebases or merges with the base PR branch if needed. -It performs several other housekeeping items +Pull Requests are managed by the bot [Myrmica Lobicornis](https://github.com/traefik/lobicornis). +This bot is responsible for verifying GitHub Checks (CI, Tests, etc), mergability, and minimum reviews. +In addition, it rebases or merges with the base PR branch if needed. +It performs several other housekeeping items and you can read more about those on the [README](https://github.com/traefik/lobicornis) for Lobicornis. The maintainer giving the final LGTM must add the `status/3-needs-merge` label to trigger the merge bot. @@ -110,7 +110,7 @@ By default, a squash-rebase merge will be carried out. The status `status/4-merge-in-progress` is only used by the bot. -If the bot is not able to perform the merge, the label `bot/need-human-merge` is added. +If the bot is not able to perform the merge, the label `bot/need-human-merge` is added. In such a situation, solve the conflicts/CI/... and then remove the label `bot/need-human-merge`. To prevent the bot from automatically merging a PR, add the label `bot/no-merge`. @@ -126,23 +126,23 @@ This label can be used when: ## Why Was My Pull Request Closed? -Traefik Proxy is made by the community for the community, -as such the goal is to engage the community to make Traefik the best reverse proxy available. -Part of this goal is maintaining a lean codebase and ensuring code velocity. +Traefik Proxy is made by the community for the community, +as such the goal is to engage the community to make Traefik the best reverse proxy available. +Part of this goal is maintaining a lean codebase and ensuring code velocity. unfortunately, this means that sometimes we will not be able to merge a pull request. -Because we respect the work you did, you will always be told why we are closing your pull request. -If you do not agree with our decision, do not worry; closed pull requests are easy to recreate, +Because we respect the work you did, you will always be told why we are closing your pull request. +If you do not agree with our decision, do not worry; closed pull requests are effortless to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened. Your pull request might be closed if: -* Your PR's design conflicts with our existing codebase in such a way that Merging is not an option +* Your PR's design conflicts with our existing codebase in such a way that merging is not an option and the work needed to make your pull request usable is too high. * To prevent this, make sure you created an issue first and think about including Traefik Proxy maintainers in your design phase to minimize conflicts. * Your PR is for an enhancement or feature that we will not use. - * Please remember to create an issue for any pull request **before** you create a PR + * Please remember to create an issue for any pull request **before** you create a PR to ensure that your goal is something we can merge and that you have any design insight you might need from the team. * Your PR has been waiting for feedback from the contributor for over 90 days. @@ -150,54 +150,54 @@ Your pull request might be closed if: A few factors affect how long your pull request might wait for review. -We must prioritize which PRs we focus on. -Our first priority is PRs we have identified as having high community engagement and broad applicability. -We put our top priorities on our roadmap and you can identify them by the `contributor/wanted` tag. -These PRs will enter our review process the fastest. +We must prioritize which PRs we focus on. +Our first priority is PRs we have identified as having high community engagement and broad applicability. +We put our top priorities on our roadmap, and you can identify them by the `contributor/wanted` tag. +These PRs will enter our review process the fastest. -Our second priority is bug fixes. -Especially for bugs that have already been tagged with `bug/confirmed`. +Our second priority is bug fixes. +Especially for bugs that have already been tagged with `bug/confirmed`. These reviews enter the process quickly. -If your PR does not meet the criteria above, -it will take longer for us to review as any PRs that do meet the criteria above will be prioritized. +If your PR does not meet the criteria above, +it will take longer for us to review, as any PRs that do meet the criteria above will be prioritized. -Additionally, during the last few weeks of a milestone, we stop reviewing PRs to reduce churn and stabilize. -We will resume after the release. +Additionally, during the last few weeks of a milestone, we stop reviewing PRs to reduce churn and stabilize. +We will resume after the release. -The second major reason that we deprioritize your PR is that you are not following best practices. +The second major reason that we deprioritize your PR is that you are not following best practices. The most common failures to follow best practices are: -* You did not create an issue for the PR you wish to make. - If you do not create an issue before submitting your PR, - we will not be able to answer any design questions and let you know how likely your PR is to be merged. +* You did not create an issue for the PR you wish to make. + If you do not create an issue before submitting your PR, + we will not be able to answer any design questions and let you know how likely your PR is to be merged. * You created pull requests that are too large to review. * Break your pull requests up. - If you can extract whole ideas from your pull request and send those as pull requests of their own, - you should do that instead. - It is better to have many pull requests addressing one thing than one pull request addressing many things. - * Traefik Proxy is a fast-moving codebase — lock in your changes ASAP with your small pull request, + If you can extract whole ideas from your pull request and send those as pull requests of their own, + you should do that instead. + It is better to have many pull requests addressing one thing than one pull request addressing many things. + * Traefik Proxy is a fast-moving codebase — lock in your changes ASAP with your small pull request, and make merges be someone else's problem. - We want every pull request to be useful on its own, + We want every pull request to be useful on its own, so use your best judgment on what should be a pull request vs. a commit. * You did not comment well. * Comment everything. -Please remember that we are working internationally, cross-culturally, and with different use-cases. +Please remember that we are working internationally, cross-culturally, and with different use-cases. Your reviewer will not intuitively understand the problem the same way you do or solve it the same way you would. -This is why every change you make must be explained and your strategy for coding must also be explained. +This is why every change you make must be explained, and your strategy for coding must also be explained. * Your tests were inadequate or absent. - * If you do not know how to test your PR, please ask! + * If you do not know how to test your PR, please ask! We will be happy to help you or suggest appropriate test cases. -If you have already followed the best practices and your PR still has not received a response, +If you have already followed the best practices and your PR still has not received a response, here are some things you can do to move the process along: -* If you have fixed all the issues from a review, - remember to re-request a review (using the designated button) to let your reviewer know that you are ready. - You can choose to comment with the changes you made. +* If you have fixed all the issues from a review, + remember to re-request a review (using the designated button) to let your reviewer know that you are ready. + You can choose to comment with the changes you made. * Ping `@tfny` if you have not been assigned to a reviewer. For more information on best practices, try these links: @@ -209,23 +209,23 @@ For more information on best practices, try these links: ## It's OK to Push Back -Sometimes reviewers make mistakes. -It is OK to push back on changes your reviewer requested. +Sometimes reviewers make mistakes. +It is OK to push back on changes your reviewer requested. If you have a good reason for doing something a certain way, you are absolutely allowed to debate the merits of a requested change. Both the reviewer and reviewee should strive to discuss these issues in a polite and respectful manner. -You might be overruled, but you might also prevail. +You might be overruled, but you might also prevail. We are pretty reasonable people. Another phenomenon of open-source projects (where anyone can comment on any issue) is the dog-pile - -your pull request gets so many comments from so many people it becomes hard to follow. -In this situation, you can ask the primary reviewer (assignee) whether they want you to fork a new pull request -to clear out all the comments. -You do not have to fix every issue raised by every person who feels like commenting, +your pull request gets so many comments from so many people it becomes hard to follow. +In this situation, you can ask the primary reviewer (assignee) whether they want you to fork a new pull request +to clear out all the comments. +You do not have to fix every issue raised by every person who feels like commenting, but you should answer reasonable comments with an explanation. ## Common Sense and Courtesy -No document can take the place of common sense and good taste. -Use your best judgment, while you put a bit of thought into how your work can be made easier to review. -If you do these things your pull requests will get merged with less friction. +No document can take the place of common sense and good taste. +Use your best judgment, while you put a bit of thought into how your work can be made easier to review. +If you do these things, your pull requests will get merged with less friction. diff --git a/docs/content/contributing/submitting-security-issues.md b/docs/content/contributing/submitting-security-issues.md index 71bbd7724..5a59408a2 100644 --- a/docs/content/contributing/submitting-security-issues.md +++ b/docs/content/contributing/submitting-security-issues.md @@ -12,7 +12,7 @@ You can subscribe sending a mail to security+subscribe@traefik.io or on [the onl ## CVE -Reported vulnerabilities can be found on +Reported vulnerabilities can be found on [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=traefik). ## Report a Vulnerability diff --git a/docs/content/getting-started/concepts.md b/docs/content/getting-started/concepts.md index ea0119837..2e99906a3 100644 --- a/docs/content/getting-started/concepts.md +++ b/docs/content/getting-started/concepts.md @@ -1,19 +1,34 @@ --- -title: "Traefik Concepts Documentation" -description: "Get started with Traefik Proxy. Read the technical documentation for an introduction into the key concepts behind our open source edge router." +title: Concepts +description: Traefik - base concepts and main features --- # Concepts -Everything You Need to Know -{: .subtitle } +This page explains the base concepts of Traefik. + +--- + +## Introduction + +Traefik is based on the concept of EntryPoints, Routers, Middelwares and Services. + +The main features include dynamic configuration, automatic service discovery, and support for multiple backends and protocols. + +1. [EntryPoints](../routing/entrypoints.md "Link to docs about EntryPoints"): EntryPoints are the network entry points into Traefik. They define the port which will receive the packets, and whether to listen for TCP or UDP. + +2. [Routers](../routing/routers/index.md "Link to docs about routers"): A router is in charge of connecting incoming requests to the services that can handle them. + +3. [Middlewares](../middlewares/overview.md "Link to docs about middlewares"): Attached to the routers, middlewares can modify the requests or responses before they are sent to your service + +4. [Services](../routing/services/index.md "Link to docs about services"): Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests. ## Edge Router -Traefik is an _Edge Router_, it means that it's the door to your platform, and that it intercepts and routes every incoming request: -it knows all the logic and every rule that determine which services handle which requests (based on the [path](../routing/routers/index.md#rule), the [host](../routing/routers/index.md#rule), [headers](../routing/routers/index.md#rule), [and so on](../routing/routers/index.md#rule) ...). +Traefik is an *Edge Router*, it means that it's the door to your platform, and that it intercepts and routes every incoming request: +it knows all the logic and every [rule](../routing/routers/index.md#rule "Link to docs about routing rules") that determine which services handle which requests (based on the *path*, the *host*, *headers*, etc.). -![The Door to Your Infrastructure](../assets/img/traefik-concepts-1.png) +![The Door to Your Infrastructure](../assets/img/traefik-concepts-1.png "Picture explaining the infrastructure") ## Auto Service Discovery @@ -21,7 +36,7 @@ Where traditionally edge routers (or reverse proxies) need a configuration file Deploying your services, you attach information that tells Traefik the characteristics of the requests the services can handle. -![Decentralized Configuration](../assets/img/traefik-concepts-2.png) +![Decentralized Configuration](../assets/img/traefik-concepts-2.png "Picture about Decentralized Configuration") It means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time. Similarly, when a service is removed from the infrastructure, the corresponding route is deleted accordingly. @@ -30,14 +45,16 @@ You no longer need to create and synchronize configuration files cluttered with !!! info "Many different rules" - In the example above, we used the request [path](../routing/routers/index.md#rule) to determine which service was in charge, but of course you can use many other different [rules](../routing/routers/index.md#rule). + In the example above, we used the request [path rule](../routing/routers/index.md#rule "Link to docs about routing rules") to determine which service was in charge. + Certainly, you can use many other different [rules](../routing/routers/index.md#rule "Link to docs about routing rules"). !!! info "Updating the requests" - In the [middleware](../middlewares/overview.md) section, you can learn about how to update the requests before forwarding them to the services. + In the [middleware](../middlewares/overview.md "Link to middleware documentation") section, you can learn about how to update the requests before forwarding them to the services. !!! question "How does Traefik discover the services?" - Traefik is able to use your cluster API to discover the services and read the attached information. In Traefik, these connectors are called [providers](../providers/overview.md) because they _provide_ the configuration to Traefik. To learn more about them, read the [provider overview](../providers/overview.md) section. + Traefik is able to use your cluster API to discover the services and read the attached information. + In Traefik, these connectors are called [providers](../providers/overview.md "Link to overview about Traefik providers") because they *provide* the configuration to Traefik. {!traefik-for-business-applications.md!} diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index 640e0098a..ebd9af1f1 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -308,121 +308,121 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used For complete details, refer to your provider's _Additional configuration_ link. -| Provider Name | Provider Code | Environment Variables | | -|----------------------------------------------------------------------------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| -| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) | -| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) | -| [all-inkl](https://all-inkl.com) | `allinkl` | `ALL_INKL_LOGIN`, `ALL_INKL_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/allinkl) | -| [ArvanCloud](https://www.arvancloud.com/en) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) | -| [Auroradns](https://www.pcextreme.com/dns-health-checks) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) | -| [Autodns](https://www.internetx.com/domains/autodns/) | `autodns` | `AUTODNS_API_USER`, `AUTODNS_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/autodns) | -| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | [Additional configuration](https://go-acme.github.io/lego/dns/azure) | -| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) | -| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) | -| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) | -| [Civo](https://www.civo.com/) | `civo` | `CIVO_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/civo) | -| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) | -| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) | -| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) | -| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) | -| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) | -| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) | -| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) | -| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) | -| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) | -| [dnsHome.de](https://www.dnshome.de) | `dnsHomede` | `DNSHOMEDE_CREDENTIALS` | [Additional configuration](https://go-acme.github.io/lego/dns/dnshomede) | -| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) | -| [DNSPod](https://www.dnspod.com/) | `dnspod` | `DNSPOD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dnspod) | -| [Domain Offensive (do.de)](https://www.do.de/) | `dode` | `DODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/dode) | -| [Domeneshop](https://domene.shop) | `domeneshop` | `DOMENESHOP_API_TOKEN`, `DOMENESHOP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/domeneshop) | -| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dreamhost) | -| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/duckdns) | -| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/dyn) | -| [Dynu](https://www.dynu.com) | `dynu` | `DYNU_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dynu) | -| [EasyDNS](https://easydns.com/) | `easydns` | `EASYDNS_TOKEN`, `EASYDNS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/easydns) | -| [EdgeDNS](https://www.akamai.com/) | `edgedns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) | -| [Epik](https://www.epik.com) | `epik` | `EPIK_SIGNATURE` | [Additional configuration](https://go-acme.github.io/lego/dns/epik) | -| [Exoscale](https://www.exoscale.com) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/exoscale) | -| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) | -| [Freemyip.com](https://freemyip.com) | `freemyip` | `FREEMYIP_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/freemyip) | -| [G-Core Lab](https://gcorelabs.com/dns/) | `gcore` | `GCORE_PERMANENT_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/gcore) | -| [Gandi v5](https://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandiv5) | -| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandi) | -| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) | -| [GoDaddy](https://godaddy.com/) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) | -| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) | -| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) | -| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) | -| [Hosttech](https://www.hosttech.eu) | `hosttech` | `HOSTTECH_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hosttech) | -| [Hurricane Electric](https://dns.he.net) | `hurricane` | `HURRICANE_TOKENS` [^6] | [Additional configuration](https://go-acme.github.io/lego/dns/hurricane) | -| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) | -| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) | -| [IIJ DNS Platform Service](https://www.iij.ad.jp) | `iijdpf` | `IIJ_DPF_API_TOKEN` , `IIJ_DPF_DPM_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iijdpf) | -| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) | -| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USERNAME`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) | -| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) | -| [Internet.bs](https://internetbs.net) | `internetbs` | `INTERNET_BS_API_KEY`, `INTERNET_BS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/internetbs) | -| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) | -| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) | -| [iwantmyname](https://iwantmyname.com) | `iwantmyname` | `IWANTMYNAME_USERNAME` , `IWANTMYNAME_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/iwantmyname) | -| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) | -| [Liara](https://liara.ir) | `liara` | `LIARA_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/liara) | -| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) | -| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) | -| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) | -| [Loopia](https://loopia.com/) | `loopia` | `LOOPIA_API_PASSWORD`, `LOOPIA_API_USER` | [Additional configuration](https://go-acme.github.io/lego/dns/loopia) | -| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) | -| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) | -| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) | -| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) | -| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) | -| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) | -| [NearlyFreeSpeech.NET](https://www.nearlyfreespeech.net/) | `nearlyfreespeech` | `NEARLYFREESPEECH_API_KEY`, `NEARLYFREESPEECH_LOGIN` | [Additional configuration](https://go-acme.github.io/lego/dns/nearlyfreespeech) | -| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) | -| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) | -| [Nicmanager](https://www.nicmanager.com) | `nicmanager` | `NICMANAGER_API_EMAIL`, `NICMANAGER_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/nicmanager) | -| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/nifcloud) | -| [Njalla](https://njal.la) | `njalla` | `NJALLA_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/njalla) | -| [NS1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) | -| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/otc) | -| [Openstack Designate](https://docs.openstack.org/designate) | `designate` | `OS_AUTH_URL`, `OS_USERNAME`, `OS_PASSWORD`, `OS_TENANT_NAME`, `OS_REGION_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/designate) | -| [Oracle Cloud](https://cloud.oracle.com/home) | `oraclecloud` | `OCI_COMPARTMENT_OCID`, `OCI_PRIVKEY_FILE`, `OCI_PRIVKEY_PASS`, `OCI_PUBKEY_FINGERPRINT`, `OCI_REGION`, `OCI_TENANCY_OCID`, `OCI_USER_OCID` | [Additional configuration](https://go-acme.github.io/lego/dns/oraclecloud) | -| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ovh) | -| [Porkbun](https://porkbun.com/) | `porkbun` | `PORKBUN_SECRET_API_KEY`, `PORKBUN_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/porkbun) | -| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/pdns) | -| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rackspace) | -| [reg.ru](https://www.reg.ru) | `regru` | `REGRU_USERNAME`, `REGRU_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/regru) | -| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/rfc2136) | -| [RimuHosting](https://rimuhosting.com) | `rimuhosting` | `RIMUHOSTING_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rimuhosting) | -| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | [Additional configuration](https://go-acme.github.io/lego/dns/route53) | -| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/sakuracloud) | -| [Scaleway](https://www.scaleway.com) | `scaleway` | `SCALEWAY_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/scaleway) | -| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) | -| [Servercow](https://servercow.de) | `servercow` | `SERVERCOW_USERNAME`, `SERVERCOW_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/servercow) | -| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) | -| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) | -| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/stackpath) | -| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) | -| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) | -| [UKFast SafeDNS](https://www.ans.co.uk/cloud-and-infrastructure/dedicated-servers/dns-management/) | `safedns` | `SAFEDNS_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/safedns) | -| [Ultradns](https://neustarsecurityservices.com/dns-services) | `ultradns` | `ULTRADNS_USERNAME`, `ULTRADNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/ultradns) | -| [Variomedia](https://www.variomedia.de/) | `variomedia` | `VARIOMEDIA_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/variomedia) | -| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/vegadns) | -| [Vercel](https://vercel.com) | `vercel` | `VERCEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vercel) | -| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) | -| [VinylDNS](https://www.vinyldns.io) | `vinyldns` | `VINYLDNS_ACCESS_KEY`, `VINYLDNS_SECRET_KEY`, `VINYLDNS_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/vinyldns) | -| [VK Cloud](https://mcs.mail.ru/) | `vkcloud` | `VK_CLOUD_PASSWORD`, `VK_CLOUD_PROJECT_ID`, `VK_CLOUD_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/vkcloud) | -| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) | -| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) | -| [Websupport](https://websupport.sk) | `websupport` | `WEBSUPPORT_API_KEY`, `WEBSUPPORT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/websupport) | -| [WEDOS](https://www.wedos.com) | `wedos` | `WEDOS_USERNAME`, `WEDOS_WAPI_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/wedos) | -| [Yandex Cloud](https://cloud.yandex.com/en/) | `yandexcloud` | `YANDEX_CLOUD_FOLDER_ID`, `YANDEX_CLOUD_IAM_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandexcloud) | -| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) | -| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) | -| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) | -| External Program | `exec` | `EXEC_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/exec) | -| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) | -| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press Enter. | | +| Provider Name | Provider Code | Environment Variables | | +|--------------------------------------------------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| +| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) | +| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) | +| [all-inkl](https://all-inkl.com) | `allinkl` | `ALL_INKL_LOGIN`, `ALL_INKL_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/allinkl) | +| [ArvanCloud](https://www.arvancloud.com/en) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) | +| [Auroradns](https://www.pcextreme.com/dns-health-checks) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) | +| [Autodns](https://www.internetx.com/domains/autodns/) | `autodns` | `AUTODNS_API_USER`, `AUTODNS_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/autodns) | +| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | [Additional configuration](https://go-acme.github.io/lego/dns/azure) | +| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) | +| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) | +| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) | +| [Civo](https://www.civo.com/) | `civo` | `CIVO_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/civo) | +| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) | +| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) | +| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) | +| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) | +| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) | +| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) | +| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) | +| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) | +| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) | +| [dnsHome.de](https://www.dnshome.de) | `dnsHomede` | `DNSHOMEDE_CREDENTIALS` | [Additional configuration](https://go-acme.github.io/lego/dns/dnshomede) | +| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) | +| [DNSPod](https://www.dnspod.com/) | `dnspod` | `DNSPOD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dnspod) | +| [Domain Offensive (do.de)](https://www.do.de/) | `dode` | `DODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/dode) | +| [Domeneshop](https://domene.shop) | `domeneshop` | `DOMENESHOP_API_TOKEN`, `DOMENESHOP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/domeneshop) | +| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dreamhost) | +| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/duckdns) | +| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/dyn) | +| [Dynu](https://www.dynu.com) | `dynu` | `DYNU_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dynu) | +| [EasyDNS](https://easydns.com/) | `easydns` | `EASYDNS_TOKEN`, `EASYDNS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/easydns) | +| [EdgeDNS](https://www.akamai.com/) | `edgedns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) | +| [Epik](https://www.epik.com) | `epik` | `EPIK_SIGNATURE` | [Additional configuration](https://go-acme.github.io/lego/dns/epik) | +| [Exoscale](https://www.exoscale.com) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/exoscale) | +| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) | +| [Freemyip.com](https://freemyip.com) | `freemyip` | `FREEMYIP_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/freemyip) | +| [G-Core Lab](https://gcorelabs.com/dns/) | `gcore` | `GCORE_PERMANENT_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/gcore) | +| [Gandi v5](https://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandiv5) | +| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandi) | +| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) | +| [GoDaddy](https://www.godaddy.com) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) | +| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) | +| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) | +| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) | +| [Hosttech](https://www.hosttech.eu) | `hosttech` | `HOSTTECH_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hosttech) | +| [Hurricane Electric](https://dns.he.net) | `hurricane` | `HURRICANE_TOKENS` [^6] | [Additional configuration](https://go-acme.github.io/lego/dns/hurricane) | +| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) | +| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) | +| [IIJ DNS Platform Service](https://www.iij.ad.jp) | `iijdpf` | `IIJ_DPF_API_TOKEN` , `IIJ_DPF_DPM_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iijdpf) | +| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) | +| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USERNAME`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) | +| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) | +| [Internet.bs](https://internetbs.net) | `internetbs` | `INTERNET_BS_API_KEY`, `INTERNET_BS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/internetbs) | +| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) | +| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) | +| [iwantmyname](https://iwantmyname.com) | `iwantmyname` | `IWANTMYNAME_USERNAME` , `IWANTMYNAME_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/iwantmyname) | +| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) | +| [Liara](https://liara.ir) | `liara` | `LIARA_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/liara) | +| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) | +| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) | +| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) | +| [Loopia](https://loopia.com/) | `loopia` | `LOOPIA_API_PASSWORD`, `LOOPIA_API_USER` | [Additional configuration](https://go-acme.github.io/lego/dns/loopia) | +| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) | +| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) | +| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) | +| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) | +| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) | +| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) | +| [NearlyFreeSpeech.NET](https://www.nearlyfreespeech.net/) | `nearlyfreespeech` | `NEARLYFREESPEECH_API_KEY`, `NEARLYFREESPEECH_LOGIN` | [Additional configuration](https://go-acme.github.io/lego/dns/nearlyfreespeech) | +| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) | +| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) | +| [Nicmanager](https://www.nicmanager.com) | `nicmanager` | `NICMANAGER_API_EMAIL`, `NICMANAGER_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/nicmanager) | +| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/nifcloud) | +| [Njalla](https://njal.la) | `njalla` | `NJALLA_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/njalla) | +| [NS1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) | +| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/otc) | +| [Openstack Designate](https://docs.openstack.org/designate) | `designate` | `OS_AUTH_URL`, `OS_USERNAME`, `OS_PASSWORD`, `OS_TENANT_NAME`, `OS_REGION_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/designate) | +| [Oracle Cloud](https://cloud.oracle.com/home) | `oraclecloud` | `OCI_COMPARTMENT_OCID`, `OCI_PRIVKEY_FILE`, `OCI_PRIVKEY_PASS`, `OCI_PUBKEY_FINGERPRINT`, `OCI_REGION`, `OCI_TENANCY_OCID`, `OCI_USER_OCID` | [Additional configuration](https://go-acme.github.io/lego/dns/oraclecloud) | +| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ovh) | +| [Porkbun](https://porkbun.com/) | `porkbun` | `PORKBUN_SECRET_API_KEY`, `PORKBUN_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/porkbun) | +| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/pdns) | +| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rackspace) | +| [reg.ru](https://www.reg.ru) | `regru` | `REGRU_USERNAME`, `REGRU_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/regru) | +| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/rfc2136) | +| [RimuHosting](https://rimuhosting.com) | `rimuhosting` | `RIMUHOSTING_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rimuhosting) | +| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | [Additional configuration](https://go-acme.github.io/lego/dns/route53) | +| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/sakuracloud) | +| [Scaleway](https://www.scaleway.com) | `scaleway` | `SCALEWAY_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/scaleway) | +| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) | +| [Servercow](https://servercow.de) | `servercow` | `SERVERCOW_USERNAME`, `SERVERCOW_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/servercow) | +| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) | +| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) | +| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/stackpath) | +| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) | +| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) | +| [UKFast SafeDNS](https://docs.ukfast.co.uk/domains/safedns/index.html) | `safedns` | `SAFEDNS_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/safedns) | +| [Ultradns](https://neustarsecurityservices.com/dns-services) | `ultradns` | `ULTRADNS_USERNAME`, `ULTRADNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/ultradns) | +| [Variomedia](https://www.variomedia.de/) | `variomedia` | `VARIOMEDIA_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/variomedia) | +| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/vegadns) | +| [Vercel](https://vercel.com) | `vercel` | `VERCEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vercel) | +| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) | +| [VinylDNS](https://www.vinyldns.io) | `vinyldns` | `VINYLDNS_ACCESS_KEY`, `VINYLDNS_SECRET_KEY`, `VINYLDNS_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/vinyldns) | +| [VK Cloud](https://mcs.mail.ru/) | `vkcloud` | `VK_CLOUD_PASSWORD`, `VK_CLOUD_PROJECT_ID`, `VK_CLOUD_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/vkcloud) | +| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) | +| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) | +| [Websupport](https://websupport.sk) | `websupport` | `WEBSUPPORT_API_KEY`, `WEBSUPPORT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/websupport) | +| [WEDOS](https://www.wedos.com) | `wedos` | `WEDOS_USERNAME`, `WEDOS_WAPI_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/wedos) | +| [Yandex Cloud](https://cloud.yandex.com/en/) | `yandexcloud` | `YANDEX_CLOUD_FOLDER_ID`, `YANDEX_CLOUD_IAM_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandexcloud) | +| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) | +| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) | +| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) | +| External Program | `exec` | `EXEC_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/exec) | +| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) | +| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press Enter. | | [^1]: More information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/). [^2]: [Providing credentials to your application](https://cloud.google.com/docs/authentication/production). diff --git a/docs/content/https/tls.md b/docs/content/https/tls.md index 075c562c5..296e9b484 100644 --- a/docs/content/https/tls.md +++ b/docs/content/https/tls.md @@ -501,15 +501,17 @@ spec: Traefik supports mutual authentication, through the `clientAuth` section. -For authentication policies that require verification of the client certificate, the certificate authority for the certificate should be set in `clientAuth.caFiles`. +For authentication policies that require verification of the client certificate, the certificate authority for the certificates should be set in `clientAuth.caFiles`. + +In Kubernetes environment, CA certificate can be set in `clientAuth.secretNames`. See [TLSOption resource](../../routing/providers/kubernetes-crd#kind-tlsoption) for more details. The `clientAuth.clientAuthType` option governs the behaviour as follows: - `NoClientCert`: disregards any client certificate. - `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided. -- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles`. -- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles`. Otherwise proceeds without any certificate. -- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles`. +- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. +- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. Otherwise proceeds without any certificate. +- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. ```yaml tab="File (YAML)" # Dynamic configuration diff --git a/docs/content/includes/traefik-for-business-applications.md b/docs/content/includes/traefik-for-business-applications.md index bbc2a602a..c07d1a41d 100644 --- a/docs/content/includes/traefik-for-business-applications.md +++ b/docs/content/includes/traefik-for-business-applications.md @@ -2,15 +2,10 @@ !!! question "Using Traefik for Business Applications?" - If you are using Traefik for commercial applications, - consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/). - You can use it as your: + If you are using Traefik in your organization, consider [Traefik Enterprise](https://traefik.io/traefik-enterprise/). You can use it as your: + - [API Gateway](https://traefik.io/solutions/api-gateway/) - [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/) - [Docker Swarm Ingress Controller](https://traefik.io/solutions/docker-swarm-ingress/) - - [API Gateway](https://traefik.io/solutions/api-gateway/) - Traefik Enterprise enables centralized access management, - distributed Let's Encrypt, - and other advanced capabilities. - Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo). + Traefik Enterprise simplifies the discovery, security, and deployment of APIs and microservices across any environment. See it in action in [this short video walkthrough](https://info.traefik.io/watch-traefikee-demo). diff --git a/docs/content/index.md b/docs/content/index.md index 3ee028a79..9d737145c 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -24,10 +24,8 @@ Developing Traefik, our main goal is to make it simple to use, and we're sure yo !!! info - Join our user friendly and active [Community Forum](https://community.traefik.io) to discuss, learn, and connect with the traefik community. - - Using Traefik for commercial applications? - Consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/) of Traefik as your [Kubernetes Ingress](https://traefik.io/solutions/kubernetes-ingress/), - your [Docker Swarm Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/), - or your [API gateway](https://traefik.io/solutions/api-gateway/). - Get started with a [free 30-day trial](https://info.traefik.io/get-traefik-enterprise-free-for-30-days). + Join our user friendly and active [Community Forum]((https://community.traefik.io "Link to Traefik Community Forum") to discuss, learn, and connect with the traefik community. + + Using Traefik in your organization? Consider [Traefik Enterprise](https://traefik.io/traefik-enterprise/ "Lino to Traefik Enterprise"), our unified API Gateway and Ingress that simplifies the discovery, security, and deployment of APIs and microservices across any environment. + + See it in action in [this short video walkthrough](https://info.traefik.io/watch-traefikee-demo "Link to video walkthrough"). diff --git a/docs/content/middlewares/http/headers.md b/docs/content/middlewares/http/headers.md index de39548cb..f0dc6e7c2 100644 --- a/docs/content/middlewares/http/headers.md +++ b/docs/content/middlewares/http/headers.md @@ -166,11 +166,14 @@ http: CORS (Cross-Origin Resource Sharing) headers can be added and configured in a manner similar to the custom headers above. This functionality allows for more advanced security features to quickly be set. If CORS headers are set, then the middleware does not pass preflight requests to any service, -instead the response will be generated and sent back to the client directly. +instead the response will be generated and sent back to the client directly. +Please note that the example below is by no means authoritative or exhaustive, +and should not be used as is for production. ```yaml tab="Docker" labels: - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT" + - "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*" - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org" - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100" - "traefik.http.middlewares.testheader.headers.addvaryheader=true" @@ -187,6 +190,7 @@ spec: - "GET" - "OPTIONS" - "PUT" + accessControlAllowHeaders: "*" accessControlAllowOriginList: - "https://foo.bar.org" - "https://example.org" @@ -196,6 +200,7 @@ spec: ```yaml tab="Consul Catalog" - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT" +- "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*" - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org" - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100" - "traefik.http.middlewares.testheader.headers.addvaryheader=true" @@ -210,6 +215,7 @@ http: - GET - OPTIONS - PUT + accessControlAllowHeaders: "*" accessControlAllowOriginList: - https://foo.bar.org - https://example.org @@ -221,6 +227,7 @@ http: [http.middlewares] [http.middlewares.testHeader.headers] accessControlAllowMethods= ["GET", "OPTIONS", "PUT"] + accessControlAllowHeaders= "*" accessControlAllowOriginList = ["https://foo.bar.org","https://example.org"] accessControlMaxAge = 100 addVaryHeader = true diff --git a/docs/content/user-guides/docker-compose/basic-example/index.md b/docs/content/user-guides/docker-compose/basic-example/index.md index 0e2bf4964..affedba37 100644 --- a/docs/content/user-guides/docker-compose/basic-example/index.md +++ b/docs/content/user-guides/docker-compose/basic-example/index.md @@ -1,12 +1,12 @@ --- title: "Traefik Docker Documentation" -description: "This guide covers a basic docker-compose file exposing a simple service using the docker provider in Traefik Proxy. Read the technical documentation." +description: "This guide covers a Docker Compose file exposing a service using the Docker provider in Traefik Proxy. Read the technical documentation." --- -# Docker-compose basic example +# Docker Compose example -In this section we quickly go over a basic docker-compose file exposing a simple service using the docker provider. -This will also be used as a starting point for the other docker-compose guides. +In this section, we quickly go over a Docker Compose file exposing a service using the Docker provider. +This will also be used as a starting point for the other Docker Compose guides. ## Setup @@ -19,9 +19,9 @@ This will also be used as a starting point for the other docker-compose guides. ??? Networking The Traefik container has to be attached to the same network as the containers to be exposed. - If no networks are specified in the docker-compose file, Docker creates a default one that allows Traefik to reach the containers defined in the same file. - You can [customize the network](https://docs.docker.com/compose/networking/#specify-custom-networks) as described in the example below. - You can use a [pre-existing network](https://docs.docker.com/compose/networking/#use-a-pre-existing-network) too. + If no networks are specified in the Docker Compose file, Docker creates a default one that allows Traefik to reach the containers defined in the same file. + You can [customize the network](https://docs.docker.com/compose/networking/#specify-custom-networks "Link to docs about custom networks with Docker Compose") as described in the example below. + You can use a [pre-existing network](https://docs.docker.com/compose/networking/#use-a-pre-existing-network "Link to Docker Compose networking docs") too. ```yaml version: "3.3" @@ -49,7 +49,7 @@ This will also be used as a starting point for the other docker-compose guides. - Run `docker-compose up -d` within the folder where you created the previous file. - Wait a bit and visit `http://your_own_domain` to confirm everything went fine. You should see the output of the whoami service. Something similar to: - + ```text Hostname: d7f919e54651 IP: 127.0.0.1 @@ -69,9 +69,9 @@ This will also be used as a starting point for the other docker-compose guides. ## Details -- As an example we use [whoami](https://github.com/traefik/whoami) (a tiny Go server that prints os information and HTTP request to output) which was used to define our `simple-service` container. +- As an example, we use [whoami](https://github.com/traefik/whoami "Link to the GitHub repo of whoami") (a tiny Go server that prints OS information and HTTP request to output) which was used to define our `simple-service` container. -- We define an entry point, along with the exposure of the matching port within docker-compose, which basically allow us to "open and accept" HTTP traffic: +- We define an entry point, along with the exposure of the matching port within Docker Compose, which allow us to "open and accept" HTTP traffic: ```yaml command: @@ -95,8 +95,8 @@ ports: !!! Note - If you are working on a remote server, you can use the following command to display configuration (require `curl` & `jq`): - + If you are working on a remote server, you can use the following command to display configuration (require `curl` & `jq`): + ```bash curl -s 127.0.0.1:8080/api/rawdata | jq . ``` @@ -106,7 +106,7 @@ ports: ```yaml traefik: command: - # Enabling docker provider + # Enabling Docker provider - "--providers.docker=true" # Do not expose containers unless explicitly told so - "--providers.docker.exposedbydefault=false" diff --git a/docs/scripts/verify.sh b/docs/scripts/verify.sh index 970d18988..44835ce79 100755 --- a/docs/scripts/verify.sh +++ b/docs/scripts/verify.sh @@ -22,7 +22,7 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \ --alt_ignore="/traefikproxy-vertical-logo-color.svg/" \ --http_status_ignore="0,500,501,503" \ --file_ignore="/404.html/" \ - --url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/,/www.wedos.com/,/www.reg.ru/" \ + --url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/,/www.wedos.com/,/www.reg.ru/,/www.godaddy.com/,/internetbs.net/" \ '{}' 1>/dev/null ## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration diff --git a/go.mod b/go.mod index a083b62ce..518004282 100644 --- a/go.mod +++ b/go.mod @@ -55,8 +55,8 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pires/go-proxyproto v0.6.1 github.com/pmezard/go-difflib v1.0.0 - github.com/prometheus/client_golang v1.12.2-0.20220704083116-e8f91604d835 - github.com/prometheus/client_model v0.2.0 + github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_model v0.3.0 github.com/quic-go/quic-go v0.33.0 github.com/rs/zerolog v1.28.0 github.com/sirupsen/logrus v1.9.0 @@ -65,13 +65,13 @@ require ( github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2 github.com/traefik/paerser v0.2.0 - github.com/traefik/yaegi v0.15.0 + github.com/traefik/yaegi v0.15.1 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/uber/jaeger-lib v2.2.0+incompatible github.com/unrolled/render v1.0.2 github.com/unrolled/secure v1.0.9 github.com/vdemeester/shakers v0.1.0 - github.com/vulcand/oxy/v2 v2.0.0-20230227135449-a0e9f7ff1040 + github.com/vulcand/oxy/v2 v2.0.0-20230417082832-03de175b3822 github.com/vulcand/predicate v1.2.0 go.elastic.co/apm v1.13.1 go.elastic.co/apm/module/apmot v1.13.1 @@ -97,11 +97,11 @@ require ( gopkg.in/DataDog/dd-trace-go.v1 v1.43.1 gopkg.in/fsnotify.v1 v1.4.7 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.25.0 - k8s.io/apiextensions-apiserver v0.25.0 - k8s.io/apimachinery v0.25.0 - k8s.io/client-go v0.25.0 - k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed + k8s.io/api v0.26.3 + k8s.io/apiextensions-apiserver v0.26.3 + k8s.io/apimachinery v0.26.3 + k8s.io/client-go v0.26.3 + k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 mvdan.cc/xurls/v2 v2.1.0 sigs.k8s.io/gateway-api v0.4.0 ) @@ -131,8 +131,6 @@ require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/Microsoft/hcsshim v0.8.24 // indirect github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/Shopify/sarama v1.23.1 // indirect github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect @@ -175,11 +173,11 @@ require ( github.com/elastic/go-licenser v0.3.1 // indirect github.com/elastic/go-sysinfo v1.1.1 // indirect github.com/elastic/go-windows v1.0.0 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/exoscale/egoscale v0.90.0 // indirect github.com/fatih/color v1.13.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fvbommel/sortorder v1.0.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.1 // indirect @@ -188,7 +186,7 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect @@ -236,7 +234,7 @@ require ( github.com/huandu/xstrings v1.3.3 // indirect github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea // indirect @@ -289,7 +287,7 @@ require ( github.com/nrdcg/goinwx v0.8.1 // indirect github.com/nrdcg/namesilo v0.2.1 // indirect github.com/nrdcg/porkbun v0.1.1 // indirect - github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.4.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.4 // indirect @@ -299,8 +297,8 @@ require ( github.com/philhofer/fwd v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pquerna/otp v1.3.0 // indirect - github.com/prometheus/common v0.35.0 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.2.1 // indirect github.com/quic-go/qtls-go1-20 v0.1.1 // indirect @@ -318,7 +316,7 @@ require ( github.com/softlayer/softlayer-go v1.0.6 // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.4.0 // indirect + github.com/spf13/cobra v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect @@ -340,9 +338,9 @@ require ( github.com/zeebo/errs v1.2.2 // indirect go.elastic.co/apm/module/apmhttp v1.13.1 // indirect go.elastic.co/fastjson v1.1.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect - go.etcd.io/etcd/client/v3 v3.5.4 // indirect + go.etcd.io/etcd/api/v3 v3.5.5 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect + go.etcd.io/etcd/client/v3 v3.5.5 // indirect go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.34.0 // indirect @@ -371,8 +369,8 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect - k8s.io/klog/v2 v2.70.1 // indirect - k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect nhooyr.io/websocket v1.8.7 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect diff --git a/go.sum b/go.sum index baf987523..3941cfe17 100644 --- a/go.sum +++ b/go.sum @@ -192,10 +192,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= @@ -495,7 +493,7 @@ github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobe github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= @@ -625,8 +623,8 @@ github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/El github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -666,8 +664,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= @@ -729,8 +727,9 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= @@ -1127,8 +1126,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.7.0 h1:QgP5mlBE9sGnzplpnf96pr+p7uqlIlL4W2GAP3n+XZg= github.com/influxdata/influxdb-client-go/v2 v2.7.0/go.mod h1:Y/0W1+TZir7ypoQZYd2IrnVOKB3Tq6oegAQeSVN/+EU= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= @@ -1489,8 +1489,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= -github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1504,7 +1504,7 @@ github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+t github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1614,16 +1614,17 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2-0.20220704083116-e8f91604d835 h1:sYuFGkrz0PtewSFk0Bg7p7jjiiklc6FUIWz+mFGQfD0= -github.com/prometheus/client_golang v1.12.2-0.20220704083116-e8f91604d835/go.mod h1:RjnYTcBFM8s+WRft6oBqj4p5OgXJASPw5UFiI7w+GSs= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -1637,8 +1638,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khmFBE= -github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1654,8 +1655,9 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/qri-io/jsonpointer v0.1.0/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64= github.com/qri-io/jsonschema v0.1.1/go.mod h1:QpzJ6gBQ0GYgGmh7mDQ1YsvvhSgE4rYj0k8t5MBOmUY= @@ -1765,8 +1767,8 @@ github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1839,8 +1841,8 @@ github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305 h1:y/1cL5AL2oRcfz github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305/go.mod h1:gXOLibKqQTRAVuVZ9gX7G9Ykky8ll8yb4slxsEMoY0c= github.com/traefik/paerser v0.2.0 h1:zqCLGSXoNlcBd+mzqSCLjon/I6phqIjeJL2xFB2ysgQ= github.com/traefik/paerser v0.2.0/go.mod h1:afzaVcgF8A+MpTnPG4wBr4whjanCSYA6vK5RwaYVtRc= -github.com/traefik/yaegi v0.15.0 h1:ScDDfQXTT75rKvcsMcP84rOxHsZ8b6NiQJyGocGDB7g= -github.com/traefik/yaegi v0.15.0/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0= +github.com/traefik/yaegi v0.15.1 h1:YA5SbaL6HZA0Exh9T/oArRHqGN2HQ+zgmCY7dkoTXu4= +github.com/traefik/yaegi v0.15.1/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0= github.com/transip/gotransip/v6 v6.17.0 h1:2RCyqYqz5+Ej8z96EyE4sf6tQrrfEBaFDO0LliSl6+8= github.com/transip/gotransip/v6 v6.17.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= @@ -1887,8 +1889,8 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/vulcand/oxy/v2 v2.0.0-20230227135449-a0e9f7ff1040 h1:L+nLher4530BUkyOpxxBsl2SLbrD4fSlDH5rGZ8DRBM= -github.com/vulcand/oxy/v2 v2.0.0-20230227135449-a0e9f7ff1040/go.mod h1:A2voDnpONyqdplUDK0lt5y4XHLiBXPBw7iQES8+ZWRw= +github.com/vulcand/oxy/v2 v2.0.0-20230417082832-03de175b3822 h1:DXLWOIMPcQV+bxCFhBYSY5AIGP4DGvXH6qkwsg82YYY= +github.com/vulcand/oxy/v2 v2.0.0-20230417082832-03de175b3822/go.mod h1:A2voDnpONyqdplUDK0lt5y4XHLiBXPBw7iQES8+ZWRw= github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50= github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= @@ -1950,14 +1952,14 @@ go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/api/v3 v3.5.5 h1:BX4JIbQ7hl7+jL+g+2j5UAr0o1bctCm6/Ct+ArBGkf0= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.5 h1:9S0JUVvmrVl7wCF39iTQthdaaNIiAaQbmK75ogO6GU8= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.etcd.io/etcd/client/v3 v3.5.5 h1:q++2WTJbUgpQu4B6hCuT7VkdwaTP7Qz6Daak3WzbrlI= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -2385,6 +2387,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2819,11 +2822,11 @@ k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= -k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0= -k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk= +k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= +k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= -k8s.io/apiextensions-apiserver v0.25.0 h1:CJ9zlyXAbq0FIW8CD7HHyozCMBpDSiH7EdrSTCZcZFY= -k8s.io/apiextensions-apiserver v0.25.0/go.mod h1:3pAjZiN4zw7R8aZC5gR0y3/vCkGlAjCazcg1me8iB/E= +k8s.io/apiextensions-apiserver v0.26.3 h1:5PGMm3oEzdB1W/FTMgGIDmm100vn7IaUP5er36dB+YE= +k8s.io/apiextensions-apiserver v0.26.3/go.mod h1:jdA5MdjNWGP+njw1EKMZc64xAT5fIhN6VJrElV3sfpQ= k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190806215851-162a2dabc72f/go.mod h1:+ntn62igV2hyNj7/0brOvXSMONE2KxcePkSxK7/9FFQ= k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= @@ -2834,8 +2837,8 @@ k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MA k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= -k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= +k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= @@ -2849,8 +2852,8 @@ k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= -k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= -k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= +k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= +k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= @@ -2877,16 +2880,16 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.10.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= -k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= @@ -2894,8 +2897,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= -k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1EoULdbQBcAeNJkY= +k8s.io/utils v0.0.0-20230313181309-38a27ef9d749/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA= mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go index 4f3df4d8a..de8a2d955 100644 --- a/pkg/config/dynamic/http_config.go +++ b/pkg/config/dynamic/http_config.go @@ -220,8 +220,8 @@ func (r *ResponseForwarding) SetDefaults() { // Server holds the server configuration. type Server struct { URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"` - Scheme string `toml:"-" json:"-" yaml:"-" file:"-"` - Port string `toml:"-" json:"-" yaml:"-" file:"-"` + Scheme string `json:"-" toml:"-" yaml:"-" file:"-"` + Port string `json:"-" toml:"-" yaml:"-" file:"-"` } // SetDefaults Default values for a Server. @@ -282,7 +282,7 @@ type Spiffe struct { // IDs defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain). IDs []string `description:"Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain)." json:"ids,omitempty" toml:"ids,omitempty" yaml:"ids,omitempty"` // TrustDomain defines the allowed SPIFFE trust domain. - TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" yaml:"trustDomain,omitempty" toml:"trustDomain,omitempty"` + TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" toml:"trustDomain,omitempty" yaml:"trustDomain,omitempty"` } // +k8s:deepcopy-gen=true diff --git a/pkg/config/dynamic/middlewares.go b/pkg/config/dynamic/middlewares.go index 748a205bc..6ab6e5a05 100644 --- a/pkg/config/dynamic/middlewares.go +++ b/pkg/config/dynamic/middlewares.go @@ -382,7 +382,7 @@ func (s *IPStrategy) Get() (ip.Strategy, error) { type IPAllowList struct { // SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"` - IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"` + IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"` } // +k8s:deepcopy-gen=true diff --git a/pkg/config/dynamic/plugins.go b/pkg/config/dynamic/plugins.go index a44236695..6df68b242 100644 --- a/pkg/config/dynamic/plugins.go +++ b/pkg/config/dynamic/plugins.go @@ -1,22 +1,26 @@ package dynamic -import "k8s.io/apimachinery/pkg/runtime" +import ( + "encoding/json" + "fmt" + "reflect" +) // +k8s:deepcopy-gen=false // PluginConf holds the plugin configuration. -type PluginConf map[string]interface{} +type PluginConf map[string]any -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +// DeepCopyInto is a deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PluginConf) DeepCopyInto(out *PluginConf) { if in == nil { *out = nil } else { - *out = runtime.DeepCopyJSON(*in) + *out = deepCopyJSON(*in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConf. +// DeepCopy is a deepcopy function, copying the receiver, creating a new PluginConf. func (in *PluginConf) DeepCopy() *PluginConf { if in == nil { return nil @@ -25,3 +29,49 @@ func (in *PluginConf) DeepCopy() *PluginConf { in.DeepCopyInto(out) return out } + +// inspired by https://github.com/kubernetes/apimachinery/blob/53ecdf01b997ca93c7db7615dfe7b27ad8391983/pkg/runtime/converter.go#L607 +func deepCopyJSON(x map[string]any) map[string]any { + return deepCopyJSONValue(x).(map[string]any) +} + +func deepCopyJSONValue(x any) any { + switch x := x.(type) { + case map[string]any: + if x == nil { + // Typed nil - an any that contains a type map[string]any with a value of nil + return x + } + clone := make(map[string]any, len(x)) + for k, v := range x { + clone[k] = deepCopyJSONValue(v) + } + return clone + case []any: + if x == nil { + // Typed nil - an any that contains a type []any with a value of nil + return x + } + clone := make([]any, len(x)) + for i, v := range x { + clone[i] = deepCopyJSONValue(v) + } + return clone + case string, int64, bool, float64, nil, json.Number: + return x + default: + v := reflect.ValueOf(x) + + if v.NumMethod() == 0 { + panic(fmt.Errorf("cannot deep copy %T", x)) + } + + method := v.MethodByName("DeepCopy") + if method.Kind() == reflect.Invalid { + panic(fmt.Errorf("cannot deep copy %T", x)) + } + + call := method.Call(nil) + return call[0].Interface() + } +} diff --git a/pkg/config/dynamic/plugins_test.go b/pkg/config/dynamic/plugins_test.go new file mode 100644 index 000000000..6021362dd --- /dev/null +++ b/pkg/config/dynamic/plugins_test.go @@ -0,0 +1,75 @@ +package dynamic + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +type FakeConfig struct { + Name string `json:"name"` +} + +// DeepCopyInto is a deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FakeConfig) DeepCopyInto(out *FakeConfig) { + *out = *in +} + +// DeepCopy is a deepcopy function, copying the receiver, creating a new AddPrefix. +func (in *FakeConfig) DeepCopy() *FakeConfig { + if in == nil { + return nil + } + out := new(FakeConfig) + in.DeepCopyInto(out) + return out +} + +type Foo struct { + Name string +} + +func TestPluginConf_DeepCopy_mapOfStruct(t *testing.T) { + f := &FakeConfig{Name: "bir"} + p := PluginConf{ + "fii": f, + } + + clone := p.DeepCopy() + assert.Equal(t, &p, clone) + + f.Name = "bur" + + assert.NotEqual(t, &p, clone) +} + +func TestPluginConf_DeepCopy_map(t *testing.T) { + m := map[string]interface{}{ + "name": "bar", + } + p := PluginConf{ + "config": map[string]interface{}{ + "foo": m, + }, + } + + clone := p.DeepCopy() + assert.Equal(t, &p, clone) + + p["one"] = "a" + m["two"] = "b" + + assert.NotEqual(t, &p, clone) +} + +func TestPluginConf_DeepCopy_panic(t *testing.T) { + p := &PluginConf{ + "config": map[string]interface{}{ + "foo": &Foo{Name: "gigi"}, + }, + } + + assert.Panics(t, func() { + p.DeepCopy() + }) +} diff --git a/pkg/config/dynamic/tcp_config.go b/pkg/config/dynamic/tcp_config.go index e4639a1ea..7789c5169 100644 --- a/pkg/config/dynamic/tcp_config.go +++ b/pkg/config/dynamic/tcp_config.go @@ -101,7 +101,7 @@ func (l *TCPServersLoadBalancer) Mergeable(loadBalancer *TCPServersLoadBalancer) // TCPServer holds a TCP Server configuration. type TCPServer struct { Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"` - Port string `toml:"-" json:"-" yaml:"-"` + Port string `json:"-" toml:"-" yaml:"-"` TLS bool `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"` } diff --git a/pkg/config/dynamic/udp_config.go b/pkg/config/dynamic/udp_config.go index e6a711e86..9e601a2df 100644 --- a/pkg/config/dynamic/udp_config.go +++ b/pkg/config/dynamic/udp_config.go @@ -78,5 +78,5 @@ func (l *UDPServersLoadBalancer) Mergeable(loadBalancer *UDPServersLoadBalancer) // UDPServer defines a UDP server configuration. type UDPServer struct { Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"` - Port string `toml:"-" json:"-" yaml:"-" file:"-"` + Port string `json:"-" toml:"-" yaml:"-" file:"-"` } diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 05051ff54..2b2afb386 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -114,7 +114,7 @@ type ServersTransport struct { // Spiffe holds the SPIFFE configuration. type Spiffe struct { IDs []string `description:"Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain)." json:"ids,omitempty" toml:"ids,omitempty" yaml:"ids,omitempty"` - TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" yaml:"trustDomain,omitempty" toml:"trustDomain,omitempty"` + TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" toml:"trustDomain,omitempty" yaml:"trustDomain,omitempty"` } // TCPServersTransport options to configure communication between Traefik and the servers. @@ -191,13 +191,13 @@ func (a *LifeCycle) SetDefaults() { type Tracing struct { ServiceName string `description:"Set the name for this service." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"` SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)." json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty" export:"true"` - Jaeger *jaeger.Config `description:"Settings for Jaeger." json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Elastic *elastic.Config `description:"Settings for Elastic." json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - OpenTelemetry *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"openTelemetry,omitempty" toml:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Jaeger *jaeger.Config `description:"Settings for Jaeger." json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Elastic *elastic.Config `description:"Settings for Elastic." json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + OpenTelemetry *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"openTelemetry,omitempty" toml:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } // SetDefaults sets the default values. @@ -210,12 +210,12 @@ func (t *Tracing) SetDefaults() { type Providers struct { ProvidersThrottleDuration ptypes.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." json:"providersThrottleDuration,omitempty" toml:"providersThrottleDuration,omitempty" yaml:"providersThrottleDuration,omitempty" export:"true"` - Docker *docker.Provider `description:"Enable Docker backend with default settings." json:"docker,omitempty" toml:"docker,omitempty" yaml:"docker,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Docker *docker.Provider `description:"Enable Docker backend with default settings." json:"docker,omitempty" toml:"docker,omitempty" yaml:"docker,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` File *file.Provider `description:"Enable File backend with default settings." json:"file,omitempty" toml:"file,omitempty" yaml:"file,omitempty" export:"true"` - KubernetesIngress *ingress.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesIngress,omitempty" toml:"kubernetesIngress,omitempty" yaml:"kubernetesIngress,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - KubernetesCRD *crd.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesCRD,omitempty" toml:"kubernetesCRD,omitempty" yaml:"kubernetesCRD,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - KubernetesGateway *gateway.Provider `description:"Enable Kubernetes gateway api provider with default settings." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Rest *rest.Provider `description:"Enable Rest backend with default settings." json:"rest,omitempty" toml:"rest,omitempty" yaml:"rest,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + KubernetesIngress *ingress.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesIngress,omitempty" toml:"kubernetesIngress,omitempty" yaml:"kubernetesIngress,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + KubernetesCRD *crd.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesCRD,omitempty" toml:"kubernetesCRD,omitempty" yaml:"kubernetesCRD,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + KubernetesGateway *gateway.Provider `description:"Enable Kubernetes gateway api provider with default settings." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Rest *rest.Provider ` description:"Enable Rest backend with default settings." json:"rest,omitempty" toml:"rest,omitempty" yaml:"rest,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` ConsulCatalog *consulcatalog.ProviderBuilder `description:"Enable ConsulCatalog backend with default settings." json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Nomad *nomad.ProviderBuilder `description:"Enable Nomad backend with default settings." json:"nomad,omitempty" toml:"nomad,omitempty" yaml:"nomad,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Ecs *ecs.Provider `description:"Enable AWS ECS backend with default settings." json:"ecs,omitempty" toml:"ecs,omitempty" yaml:"ecs,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go index 53ff07fe1..6095b32f5 100644 --- a/pkg/provider/docker/config.go +++ b/pkg/provider/docker/config.go @@ -310,6 +310,7 @@ func (p *Provider) getIPPort(ctx context.Context, container dockerData, serverPo func (p Provider) getIPAddress(ctx context.Context, container dockerData) string { logger := log.Ctx(ctx) + netNotFound := false if container.ExtraConf.Docker.Network != "" { settings := container.NetworkSettings if settings.Networks != nil { @@ -318,7 +319,8 @@ func (p Provider) getIPAddress(ctx context.Context, container dockerData) string return network.Addr } - logger.Warn().Msgf("Could not find network named '%s' for container '%s'! Maybe you're missing the project's prefix in the label? Defaulting to first available network.", container.ExtraConf.Docker.Network, container.Name) + netNotFound = true + logger.Warn().Msgf("Could not find network named %q for container %q. Maybe you're missing the project's prefix in the label?", container.ExtraConf.Docker.Network, container.Name) } } @@ -367,6 +369,9 @@ func (p Provider) getIPAddress(ctx context.Context, container dockerData) string } for _, network := range container.NetworkSettings.Networks { + if netNotFound { + logger.Warn().Msgf("Defaulting to first available network (%q) for container %q.", network, container.Name) + } return network.Addr } diff --git a/pkg/provider/kubernetes/crd/client.go b/pkg/provider/kubernetes/crd/client.go index 44e0cb29c..d52588536 100644 --- a/pkg/provider/kubernetes/crd/client.go +++ b/pkg/provider/kubernetes/crd/client.go @@ -9,17 +9,17 @@ import ( "time" "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikclientset "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned" + traefikinformers "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" "github.com/traefik/traefik/v3/pkg/version" corev1 "k8s.io/api/core/v1" - kubeerror "k8s.io/apimachinery/pkg/api/errors" + kerror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" + kinformers "k8s.io/client-go/informers" + kclientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) @@ -31,17 +31,17 @@ const resyncPeriod = 10 * time.Minute // The stores can then be accessed via the Get* functions. type Client interface { WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) - GetIngressRoutes() []*v1alpha1.IngressRoute - GetIngressRouteTCPs() []*v1alpha1.IngressRouteTCP - GetIngressRouteUDPs() []*v1alpha1.IngressRouteUDP - GetMiddlewares() []*v1alpha1.Middleware - GetMiddlewareTCPs() []*v1alpha1.MiddlewareTCP - GetTraefikService(namespace, name string) (*v1alpha1.TraefikService, bool, error) - GetTraefikServices() []*v1alpha1.TraefikService - GetTLSOptions() []*v1alpha1.TLSOption - GetServersTransports() []*v1alpha1.ServersTransport - GetServersTransportTCPs() []*v1alpha1.ServersTransportTCP - GetTLSStores() []*v1alpha1.TLSStore + GetIngressRoutes() []*traefikv1alpha1.IngressRoute + GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP + GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP + GetMiddlewares() []*traefikv1alpha1.Middleware + GetMiddlewareTCPs() []*traefikv1alpha1.MiddlewareTCP + GetTraefikService(namespace, name string) (*traefikv1alpha1.TraefikService, bool, error) + GetTraefikServices() []*traefikv1alpha1.TraefikService + GetTLSOptions() []*traefikv1alpha1.TLSOption + GetServersTransports() []*traefikv1alpha1.ServersTransport + GetServersTransportTCPs() []*traefikv1alpha1.ServersTransportTCP + GetTLSStores() []*traefikv1alpha1.TLSStore GetService(namespace, name string) (*corev1.Service, bool, error) GetSecret(namespace, name string) (*corev1.Secret, bool, error) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) @@ -49,12 +49,12 @@ type Client interface { // TODO: add tests for the clientWrapper (and its methods) itself. type clientWrapper struct { - csCrd versioned.Interface - csKube kubernetes.Interface + csCrd traefikclientset.Interface + csKube kclientset.Interface - factoriesCrd map[string]externalversions.SharedInformerFactory - factoriesKube map[string]informers.SharedInformerFactory - factoriesSecret map[string]informers.SharedInformerFactory + factoriesCrd map[string]traefikinformers.SharedInformerFactory + factoriesKube map[string]kinformers.SharedInformerFactory + factoriesSecret map[string]kinformers.SharedInformerFactory labelSelector string @@ -71,12 +71,12 @@ func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { runtime.GOARCH, ) - csCrd, err := versioned.NewForConfig(c) + csCrd, err := traefikclientset.NewForConfig(c) if err != nil { return nil, err } - csKube, err := kubernetes.NewForConfig(c) + csKube, err := kclientset.NewForConfig(c) if err != nil { return nil, err } @@ -84,13 +84,13 @@ func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { return newClientImpl(csKube, csCrd), nil } -func newClientImpl(csKube kubernetes.Interface, csCrd versioned.Interface) *clientWrapper { +func newClientImpl(csKube kclientset.Interface, csCrd traefikclientset.Interface) *clientWrapper { return &clientWrapper{ csCrd: csCrd, csKube: csKube, - factoriesCrd: make(map[string]externalversions.SharedInformerFactory), - factoriesKube: make(map[string]informers.SharedInformerFactory), - factoriesSecret: make(map[string]informers.SharedInformerFactory), + factoriesCrd: make(map[string]traefikinformers.SharedInformerFactory), + factoriesKube: make(map[string]kinformers.SharedInformerFactory), + factoriesSecret: make(map[string]kinformers.SharedInformerFactory), } } @@ -163,24 +163,63 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< } for _, ns := range namespaces { - factoryCrd := externalversions.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, externalversions.WithNamespace(ns), externalversions.WithTweakListOptions(matchesLabelSelector)) - factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().Middlewares().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().MiddlewareTCPs().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().IngressRouteTCPs().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().IngressRouteUDPs().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().TLSOptions().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().ServersTransports().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().ServersTransportTCPs().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().TLSStores().Informer().AddEventHandler(eventHandler) - factoryCrd.Traefik().V1alpha1().TraefikServices().Informer().AddEventHandler(eventHandler) + factoryCrd := traefikinformers.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, traefikinformers.WithNamespace(ns), traefikinformers.WithTweakListOptions(matchesLabelSelector)) + _, err := factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().Middlewares().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().MiddlewareTCPs().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().IngressRouteTCPs().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().IngressRouteUDPs().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().TLSOptions().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().ServersTransports().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().ServersTransportTCPs().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().TLSStores().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryCrd.Traefik().V1alpha1().TraefikServices().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } - factoryKube := informers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, informers.WithNamespace(ns)) - factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) - factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns)) + _, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } - factorySecret := informers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, informers.WithNamespace(ns), informers.WithTweakListOptions(notOwnedByHelm)) - factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm)) + _, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } c.factoriesCrd[ns] = factoryCrd c.factoriesKube[ns] = factoryKube @@ -216,8 +255,8 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< return eventCh, nil } -func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute { - var result []*v1alpha1.IngressRoute +func (c *clientWrapper) GetIngressRoutes() []*traefikv1alpha1.IngressRoute { + var result []*traefikv1alpha1.IngressRoute for ns, factory := range c.factoriesCrd { ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(labels.Everything()) @@ -230,8 +269,8 @@ func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute { return result } -func (c *clientWrapper) GetIngressRouteTCPs() []*v1alpha1.IngressRouteTCP { - var result []*v1alpha1.IngressRouteTCP +func (c *clientWrapper) GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP { + var result []*traefikv1alpha1.IngressRouteTCP for ns, factory := range c.factoriesCrd { ings, err := factory.Traefik().V1alpha1().IngressRouteTCPs().Lister().List(labels.Everything()) @@ -244,8 +283,8 @@ func (c *clientWrapper) GetIngressRouteTCPs() []*v1alpha1.IngressRouteTCP { return result } -func (c *clientWrapper) GetIngressRouteUDPs() []*v1alpha1.IngressRouteUDP { - var result []*v1alpha1.IngressRouteUDP +func (c *clientWrapper) GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP { + var result []*traefikv1alpha1.IngressRouteUDP for ns, factory := range c.factoriesCrd { ings, err := factory.Traefik().V1alpha1().IngressRouteUDPs().Lister().List(labels.Everything()) @@ -258,8 +297,8 @@ func (c *clientWrapper) GetIngressRouteUDPs() []*v1alpha1.IngressRouteUDP { return result } -func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware { - var result []*v1alpha1.Middleware +func (c *clientWrapper) GetMiddlewares() []*traefikv1alpha1.Middleware { + var result []*traefikv1alpha1.Middleware for ns, factory := range c.factoriesCrd { middlewares, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(labels.Everything()) @@ -272,8 +311,8 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware { return result } -func (c *clientWrapper) GetMiddlewareTCPs() []*v1alpha1.MiddlewareTCP { - var result []*v1alpha1.MiddlewareTCP +func (c *clientWrapper) GetMiddlewareTCPs() []*traefikv1alpha1.MiddlewareTCP { + var result []*traefikv1alpha1.MiddlewareTCP for ns, factory := range c.factoriesCrd { middlewares, err := factory.Traefik().V1alpha1().MiddlewareTCPs().Lister().List(labels.Everything()) @@ -287,7 +326,7 @@ func (c *clientWrapper) GetMiddlewareTCPs() []*v1alpha1.MiddlewareTCP { } // GetTraefikService returns the named service from the given namespace. -func (c *clientWrapper) GetTraefikService(namespace, name string) (*v1alpha1.TraefikService, bool, error) { +func (c *clientWrapper) GetTraefikService(namespace, name string) (*traefikv1alpha1.TraefikService, bool, error) { if !c.isWatchedNamespace(namespace) { return nil, false, fmt.Errorf("failed to get service %s/%s: namespace is not within watched namespaces", namespace, name) } @@ -298,8 +337,8 @@ func (c *clientWrapper) GetTraefikService(namespace, name string) (*v1alpha1.Tra return service, exist, err } -func (c *clientWrapper) GetTraefikServices() []*v1alpha1.TraefikService { - var result []*v1alpha1.TraefikService +func (c *clientWrapper) GetTraefikServices() []*traefikv1alpha1.TraefikService { + var result []*traefikv1alpha1.TraefikService for ns, factory := range c.factoriesCrd { traefikServices, err := factory.Traefik().V1alpha1().TraefikServices().Lister().List(labels.Everything()) @@ -313,8 +352,8 @@ func (c *clientWrapper) GetTraefikServices() []*v1alpha1.TraefikService { } // GetServersTransports returns all ServersTransport. -func (c *clientWrapper) GetServersTransports() []*v1alpha1.ServersTransport { - var result []*v1alpha1.ServersTransport +func (c *clientWrapper) GetServersTransports() []*traefikv1alpha1.ServersTransport { + var result []*traefikv1alpha1.ServersTransport for ns, factory := range c.factoriesCrd { serversTransports, err := factory.Traefik().V1alpha1().ServersTransports().Lister().List(labels.Everything()) @@ -328,8 +367,8 @@ func (c *clientWrapper) GetServersTransports() []*v1alpha1.ServersTransport { } // GetServersTransportTCPs returns all ServersTransportTCP. -func (c *clientWrapper) GetServersTransportTCPs() []*v1alpha1.ServersTransportTCP { - var result []*v1alpha1.ServersTransportTCP +func (c *clientWrapper) GetServersTransportTCPs() []*traefikv1alpha1.ServersTransportTCP { + var result []*traefikv1alpha1.ServersTransportTCP for ns, factory := range c.factoriesCrd { serversTransports, err := factory.Traefik().V1alpha1().ServersTransportTCPs().Lister().List(labels.Everything()) @@ -343,8 +382,8 @@ func (c *clientWrapper) GetServersTransportTCPs() []*v1alpha1.ServersTransportTC } // GetTLSOptions returns all TLS options. -func (c *clientWrapper) GetTLSOptions() []*v1alpha1.TLSOption { - var result []*v1alpha1.TLSOption +func (c *clientWrapper) GetTLSOptions() []*traefikv1alpha1.TLSOption { + var result []*traefikv1alpha1.TLSOption for ns, factory := range c.factoriesCrd { options, err := factory.Traefik().V1alpha1().TLSOptions().Lister().List(labels.Everything()) @@ -358,8 +397,8 @@ func (c *clientWrapper) GetTLSOptions() []*v1alpha1.TLSOption { } // GetTLSStores returns all TLS stores. -func (c *clientWrapper) GetTLSStores() []*v1alpha1.TLSStore { - var result []*v1alpha1.TLSStore +func (c *clientWrapper) GetTLSStores() []*traefikv1alpha1.TLSStore { + var result []*traefikv1alpha1.TLSStore for ns, factory := range c.factoriesCrd { stores, err := factory.Traefik().V1alpha1().TLSStores().Lister().List(labels.Everything()) @@ -435,7 +474,7 @@ func (c *clientWrapper) isWatchedNamespace(ns string) bool { // translateNotFoundError will translate a "not found" error to a boolean return // value which indicates if the resource exists and a nil error. func translateNotFoundError(err error) (bool, error) { - if kubeerror.IsNotFound(err) { + if kerror.IsNotFound(err) { return false, nil } return err == nil, err diff --git a/pkg/provider/kubernetes/crd/client_mock_test.go b/pkg/provider/kubernetes/crd/client_mock_test.go index 7509fc2ef..548966123 100644 --- a/pkg/provider/kubernetes/crd/client_mock_test.go +++ b/pkg/provider/kubernetes/crd/client_mock_test.go @@ -5,17 +5,17 @@ import ( "os" "path/filepath" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/kubernetes/scheme" + kscheme "k8s.io/client-go/kubernetes/scheme" ) var _ Client = (*clientMock)(nil) func init() { // required by k8s.MustParseYaml - err := v1alpha1.AddToScheme(scheme.Scheme) + err := traefikv1alpha1.AddToScheme(kscheme.Scheme) if err != nil { panic(err) } @@ -30,16 +30,16 @@ type clientMock struct { apiSecretError error apiEndpointsError error - ingressRoutes []*v1alpha1.IngressRoute - ingressRouteTCPs []*v1alpha1.IngressRouteTCP - ingressRouteUDPs []*v1alpha1.IngressRouteUDP - middlewares []*v1alpha1.Middleware - middlewareTCPs []*v1alpha1.MiddlewareTCP - tlsOptions []*v1alpha1.TLSOption - tlsStores []*v1alpha1.TLSStore - traefikServices []*v1alpha1.TraefikService - serversTransports []*v1alpha1.ServersTransport - serversTransportTCPs []*v1alpha1.ServersTransportTCP + ingressRoutes []*traefikv1alpha1.IngressRoute + ingressRouteTCPs []*traefikv1alpha1.IngressRouteTCP + ingressRouteUDPs []*traefikv1alpha1.IngressRouteUDP + middlewares []*traefikv1alpha1.Middleware + middlewareTCPs []*traefikv1alpha1.MiddlewareTCP + tlsOptions []*traefikv1alpha1.TLSOption + tlsStores []*traefikv1alpha1.TLSStore + traefikServices []*traefikv1alpha1.TraefikService + serversTransports []*traefikv1alpha1.ServersTransport + serversTransportTCPs []*traefikv1alpha1.ServersTransportTCP watchChan chan interface{} } @@ -60,25 +60,25 @@ func newClientMock(paths ...string) clientMock { c.services = append(c.services, o) case *corev1.Endpoints: c.endpoints = append(c.endpoints, o) - case *v1alpha1.IngressRoute: + case *traefikv1alpha1.IngressRoute: c.ingressRoutes = append(c.ingressRoutes, o) - case *v1alpha1.IngressRouteTCP: + case *traefikv1alpha1.IngressRouteTCP: c.ingressRouteTCPs = append(c.ingressRouteTCPs, o) - case *v1alpha1.IngressRouteUDP: + case *traefikv1alpha1.IngressRouteUDP: c.ingressRouteUDPs = append(c.ingressRouteUDPs, o) - case *v1alpha1.Middleware: + case *traefikv1alpha1.Middleware: c.middlewares = append(c.middlewares, o) - case *v1alpha1.MiddlewareTCP: + case *traefikv1alpha1.MiddlewareTCP: c.middlewareTCPs = append(c.middlewareTCPs, o) - case *v1alpha1.TraefikService: + case *traefikv1alpha1.TraefikService: c.traefikServices = append(c.traefikServices, o) - case *v1alpha1.TLSOption: + case *traefikv1alpha1.TLSOption: c.tlsOptions = append(c.tlsOptions, o) - case *v1alpha1.ServersTransport: + case *traefikv1alpha1.ServersTransport: c.serversTransports = append(c.serversTransports, o) - case *v1alpha1.ServersTransportTCP: + case *traefikv1alpha1.ServersTransportTCP: c.serversTransportTCPs = append(c.serversTransportTCPs, o) - case *v1alpha1.TLSStore: + case *traefikv1alpha1.TLSStore: c.tlsStores = append(c.tlsStores, o) case *corev1.Secret: c.secrets = append(c.secrets, o) @@ -91,27 +91,27 @@ func newClientMock(paths ...string) clientMock { return c } -func (c clientMock) GetIngressRoutes() []*v1alpha1.IngressRoute { +func (c clientMock) GetIngressRoutes() []*traefikv1alpha1.IngressRoute { return c.ingressRoutes } -func (c clientMock) GetIngressRouteTCPs() []*v1alpha1.IngressRouteTCP { +func (c clientMock) GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP { return c.ingressRouteTCPs } -func (c clientMock) GetIngressRouteUDPs() []*v1alpha1.IngressRouteUDP { +func (c clientMock) GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP { return c.ingressRouteUDPs } -func (c clientMock) GetMiddlewares() []*v1alpha1.Middleware { +func (c clientMock) GetMiddlewares() []*traefikv1alpha1.Middleware { return c.middlewares } -func (c clientMock) GetMiddlewareTCPs() []*v1alpha1.MiddlewareTCP { +func (c clientMock) GetMiddlewareTCPs() []*traefikv1alpha1.MiddlewareTCP { return c.middlewareTCPs } -func (c clientMock) GetTraefikService(namespace, name string) (*v1alpha1.TraefikService, bool, error) { +func (c clientMock) GetTraefikService(namespace, name string) (*traefikv1alpha1.TraefikService, bool, error) { for _, svc := range c.traefikServices { if svc.Namespace == namespace && svc.Name == name { return svc, true, nil @@ -121,27 +121,27 @@ func (c clientMock) GetTraefikService(namespace, name string) (*v1alpha1.Traefik return nil, false, nil } -func (c clientMock) GetTraefikServices() []*v1alpha1.TraefikService { +func (c clientMock) GetTraefikServices() []*traefikv1alpha1.TraefikService { return c.traefikServices } -func (c clientMock) GetTLSOptions() []*v1alpha1.TLSOption { +func (c clientMock) GetTLSOptions() []*traefikv1alpha1.TLSOption { return c.tlsOptions } -func (c clientMock) GetTLSStores() []*v1alpha1.TLSStore { +func (c clientMock) GetTLSStores() []*traefikv1alpha1.TLSStore { return c.tlsStores } -func (c clientMock) GetServersTransports() []*v1alpha1.ServersTransport { +func (c clientMock) GetServersTransports() []*traefikv1alpha1.ServersTransport { return c.serversTransports } -func (c clientMock) GetServersTransportTCPs() []*v1alpha1.ServersTransportTCP { +func (c clientMock) GetServersTransportTCPs() []*traefikv1alpha1.ServersTransportTCP { return c.serversTransportTCPs } -func (c clientMock) GetTLSOption(namespace, name string) (*v1alpha1.TLSOption, bool, error) { +func (c clientMock) GetTLSOption(namespace, name string) (*traefikv1alpha1.TLSOption, bool, error) { for _, option := range c.tlsOptions { if option.Namespace == namespace && option.Name == name { return option, true, nil diff --git a/pkg/provider/kubernetes/crd/client_test.go b/pkg/provider/kubernetes/crd/client_test.go index 5d64d08f7..5d71b6a78 100644 --- a/pkg/provider/kubernetes/crd/client_test.go +++ b/pkg/provider/kubernetes/crd/client_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - crdfake "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake" + traefikcrdfake "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubefake "k8s.io/client-go/kubernetes/fake" @@ -30,7 +30,7 @@ func TestClientIgnoresHelmOwnedSecrets(t *testing.T) { } kubeClient := kubefake.NewSimpleClientset(helmSecret, secret) - crdClient := crdfake.NewSimpleClientset() + crdClient := traefikcrdfake.NewSimpleClientset() client := newClientImpl(kubeClient, crdClient) diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 0cc0649cc..b3b3de51b 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -25,7 +25,7 @@ import ( "github.com/traefik/traefik/v3/pkg/job" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/provider" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" "github.com/traefik/traefik/v3/pkg/types" @@ -601,7 +601,7 @@ func getSecretValue(c Client, ns, urn string) (string, error) { return string(secretValue), nil } -func createCircuitBreakerMiddleware(circuitBreaker *v1alpha1.CircuitBreaker) (*dynamic.CircuitBreaker, error) { +func createCircuitBreakerMiddleware(circuitBreaker *traefikv1alpha1.CircuitBreaker) (*dynamic.CircuitBreaker, error) { if circuitBreaker == nil { return nil, nil } @@ -630,7 +630,7 @@ func createCircuitBreakerMiddleware(circuitBreaker *v1alpha1.CircuitBreaker) (*d return cb, nil } -func createRateLimitMiddleware(rateLimit *v1alpha1.RateLimit) (*dynamic.RateLimit, error) { +func createRateLimitMiddleware(rateLimit *traefikv1alpha1.RateLimit) (*dynamic.RateLimit, error) { if rateLimit == nil { return nil, nil } @@ -656,7 +656,7 @@ func createRateLimitMiddleware(rateLimit *v1alpha1.RateLimit) (*dynamic.RateLimi return rl, nil } -func createRetryMiddleware(retry *v1alpha1.Retry) (*dynamic.Retry, error) { +func createRetryMiddleware(retry *traefikv1alpha1.Retry) (*dynamic.Retry, error) { if retry == nil { return nil, nil } @@ -671,7 +671,7 @@ func createRetryMiddleware(retry *v1alpha1.Retry) (*dynamic.Retry, error) { return r, nil } -func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) { +func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *traefikv1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) { if errorPage == nil { return nil, nil, nil } @@ -696,7 +696,7 @@ func (p *Provider) createErrorPageMiddleware(client Client, namespace string, er return errorPageMiddleware, balancerServerHTTP, nil } -func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *v1alpha1.ForwardAuth) (*dynamic.ForwardAuth, error) { +func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traefikv1alpha1.ForwardAuth) (*dynamic.ForwardAuth, error) { if auth == nil { return nil, nil } @@ -787,7 +787,7 @@ func loadAuthTLSSecret(namespace, secretName string, k8sClient Client) (string, return getCertificateBlocks(secret, namespace, secretName) } -func createBasicAuthMiddleware(client Client, namespace string, basicAuth *v1alpha1.BasicAuth) (*dynamic.BasicAuth, error) { +func createBasicAuthMiddleware(client Client, namespace string, basicAuth *traefikv1alpha1.BasicAuth) (*dynamic.BasicAuth, error) { if basicAuth == nil { return nil, nil } @@ -834,7 +834,7 @@ func createBasicAuthMiddleware(client Client, namespace string, basicAuth *v1alp }, nil } -func createDigestAuthMiddleware(client Client, namespace string, digestAuth *v1alpha1.DigestAuth) (*dynamic.DigestAuth, error) { +func createDigestAuthMiddleware(client Client, namespace string, digestAuth *traefikv1alpha1.DigestAuth) (*dynamic.DigestAuth, error) { if digestAuth == nil { return nil, nil } @@ -909,7 +909,7 @@ func loadAuthCredentials(secret *corev1.Secret) ([]string, error) { return credentials, nil } -func createChainMiddleware(ctx context.Context, namespace string, chain *v1alpha1.Chain) *dynamic.Chain { +func createChainMiddleware(ctx context.Context, namespace string, chain *traefikv1alpha1.Chain) *dynamic.Chain { if chain == nil { return nil } @@ -1074,7 +1074,7 @@ func buildTLSStores(ctx context.Context, client Client) (map[string]tls.Store, m } // buildCertificates loads TLSStore certificates from secrets and sets them into tlsConfigs. -func buildCertificates(client Client, tlsStore, namespace string, certificates []v1alpha1.Certificate, tlsConfigs map[string]*tls.CertAndStores) error { +func buildCertificates(client Client, tlsStore, namespace string, certificates []traefikv1alpha1.Certificate, tlsConfigs map[string]*tls.CertAndStores) error { for _, c := range certificates { configKey := namespace + "/" + c.SecretName if _, tlsExists := tlsConfigs[configKey]; !tlsExists { diff --git a/pkg/provider/kubernetes/crd/kubernetes_http.go b/pkg/provider/kubernetes/crd/kubernetes_http.go index 66eb87dcd..bdaf48f67 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_http.go +++ b/pkg/provider/kubernetes/crd/kubernetes_http.go @@ -12,7 +12,7 @@ import ( "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/provider" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/tls" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -84,8 +84,8 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli serviceName := normalized if len(route.Services) > 1 { - spec := v1alpha1.TraefikServiceSpec{ - Weighted: &v1alpha1.WeightedRoundRobin{ + spec := traefikv1alpha1.TraefikServiceSpec{ + Weighted: &traefikv1alpha1.WeightedRoundRobin{ Services: route.Services, }, } @@ -155,7 +155,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli return conf } -func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace string, middlewares []v1alpha1.MiddlewareRef) ([]string, error) { +func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace string, middlewares []traefikv1alpha1.MiddlewareRef) ([]string, error) { var mds []string for _, mi := range middlewares { @@ -203,7 +203,7 @@ type configBuilder struct { // buildTraefikService creates the configuration for the traefik service defined in tService, // and adds it to the given conf map. -func (c configBuilder) buildTraefikService(ctx context.Context, tService *v1alpha1.TraefikService, conf map[string]*dynamic.Service) error { +func (c configBuilder) buildTraefikService(ctx context.Context, tService *traefikv1alpha1.TraefikService, conf map[string]*dynamic.Service) error { id := provider.Normalize(makeID(tService.Namespace, tService.Name)) if tService.Spec.Weighted != nil { @@ -217,7 +217,7 @@ func (c configBuilder) buildTraefikService(ctx context.Context, tService *v1alph // buildServicesLB creates the configuration for the load-balancer of services named id, and defined in tService. // It adds it to the given conf map. -func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tService v1alpha1.TraefikServiceSpec, id string, conf map[string]*dynamic.Service) error { +func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tService traefikv1alpha1.TraefikServiceSpec, id string, conf map[string]*dynamic.Service) error { var wrrServices []dynamic.WRRService for _, service := range tService.Weighted.Services { @@ -252,7 +252,7 @@ func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tS // buildMirroring creates the configuration for the mirroring service named id, and defined by tService. // It adds it to the given conf map. -func (c configBuilder) buildMirroring(ctx context.Context, tService *v1alpha1.TraefikService, id string, conf map[string]*dynamic.Service) error { +func (c configBuilder) buildMirroring(ctx context.Context, tService *traefikv1alpha1.TraefikService, id string, conf map[string]*dynamic.Service) error { fullNameMain, k8sService, err := c.nameAndService(ctx, tService.Namespace, tService.Spec.Mirroring.LoadBalancerSpec) if err != nil { return err @@ -291,7 +291,7 @@ func (c configBuilder) buildMirroring(ctx context.Context, tService *v1alpha1.Tr } // buildServersLB creates the configuration for the load-balancer of servers defined by svc. -func (c configBuilder) buildServersLB(namespace string, svc v1alpha1.LoadBalancerSpec) (*dynamic.Service, error) { +func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.LoadBalancerSpec) (*dynamic.Service, error) { servers, err := c.loadServers(namespace, svc) if err != nil { return nil, err @@ -344,7 +344,7 @@ func (c *configBuilder) makeServersTransportKey(parentNamespace string, serversT return provider.Normalize(makeID(parentNamespace, serversTransportName)), nil } -func (c configBuilder) loadServers(parentNamespace string, svc v1alpha1.LoadBalancerSpec) ([]dynamic.Server, error) { +func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.LoadBalancerSpec) ([]dynamic.Server, error) { strategy := svc.Strategy if strategy == "" { strategy = roundRobinStrategy @@ -452,7 +452,7 @@ func (c configBuilder) loadServers(parentNamespace string, svc v1alpha1.LoadBala // In addition, if the service is a Kubernetes one, // it generates and returns the configuration part for such a service, // so that the caller can add it to the global config map. -func (c configBuilder) nameAndService(ctx context.Context, parentNamespace string, service v1alpha1.LoadBalancerSpec) (string, *dynamic.Service, error) { +func (c configBuilder) nameAndService(ctx context.Context, parentNamespace string, service traefikv1alpha1.LoadBalancerSpec) (string, *dynamic.Service, error) { svcCtx := log.Ctx(ctx).With().Str(logs.ServiceName, service.Name).Logger().WithContext(ctx) namespace := namespaceOrFallback(service, parentNamespace) @@ -487,7 +487,7 @@ func splitSvcNameProvider(name string) (string, string) { return svc, pvd } -func fullServiceName(ctx context.Context, namespace string, service v1alpha1.LoadBalancerSpec, port intstr.IntOrString) string { +func fullServiceName(ctx context.Context, namespace string, service traefikv1alpha1.LoadBalancerSpec, port intstr.IntOrString) string { if (port.Type == intstr.Int && port.IntVal != 0) || (port.Type == intstr.String && port.StrVal != "") { return provider.Normalize(fmt.Sprintf("%s-%s-%s", namespace, service.Name, &port)) } @@ -508,7 +508,7 @@ func fullServiceName(ctx context.Context, namespace string, service v1alpha1.Loa return provider.Normalize(name) + providerNamespaceSeparator + pName } -func namespaceOrFallback(lb v1alpha1.LoadBalancerSpec, fallback string) string { +func namespaceOrFallback(lb traefikv1alpha1.LoadBalancerSpec, fallback string) string { if lb.Namespace != "" { return lb.Namespace } @@ -516,7 +516,7 @@ func namespaceOrFallback(lb v1alpha1.LoadBalancerSpec, fallback string) string { } // getTLSHTTP mutates tlsConfigs. -func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { +func getTLSHTTP(ctx context.Context, ingressRoute *traefikv1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { if ingressRoute.Spec.TLS == nil { return nil } diff --git a/pkg/provider/kubernetes/crd/kubernetes_tcp.go b/pkg/provider/kubernetes/crd/kubernetes_tcp.go index 374a2a7ab..b0759786f 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_tcp.go +++ b/pkg/provider/kubernetes/crd/kubernetes_tcp.go @@ -12,7 +12,7 @@ import ( "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/provider" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/tls" corev1 "k8s.io/api/core/v1" ) @@ -144,7 +144,7 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client return conf } -func (p *Provider) makeMiddlewareTCPKeys(ctx context.Context, ingRouteTCPNamespace string, middlewares []v1alpha1.ObjectReference) ([]string, error) { +func (p *Provider) makeMiddlewareTCPKeys(ctx context.Context, ingRouteTCPNamespace string, middlewares []traefikv1alpha1.ObjectReference) ([]string, error) { var mds []string for _, mi := range middlewares { @@ -173,7 +173,7 @@ func (p *Provider) makeMiddlewareTCPKeys(ctx context.Context, ingRouteTCPNamespa return mds, nil } -func (p *Provider) createLoadBalancerServerTCP(client Client, parentNamespace string, service v1alpha1.ServiceTCP) (*dynamic.TCPService, error) { +func (p *Provider) createLoadBalancerServerTCP(client Client, parentNamespace string, service traefikv1alpha1.ServiceTCP) (*dynamic.TCPService, error) { ns := parentNamespace if len(service.Namespace) > 0 { if !isNamespaceAllowed(p.AllowCrossNamespace, parentNamespace, service.Namespace) { @@ -213,7 +213,7 @@ func (p *Provider) createLoadBalancerServerTCP(client Client, parentNamespace st return tcpService, nil } -func (p *Provider) loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) { +func (p *Provider) loadTCPServers(client Client, namespace string, svc traefikv1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) { service, exists, err := client.GetService(namespace, svc.Name) if err != nil { return nil, err @@ -304,7 +304,7 @@ func (p *Provider) makeTCPServersTransportKey(parentNamespace string, serversTra } // getTLSTCP mutates tlsConfigs. -func getTLSTCP(ctx context.Context, ingressRoute *v1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { +func getTLSTCP(ctx context.Context, ingressRoute *traefikv1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { if ingressRoute.Spec.TLS == nil { return nil } diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index d09989ed7..7d051c3d2 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -14,8 +14,8 @@ import ( ptypes "github.com/traefik/paerser/types" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/provider" - crdfake "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikcrdfake "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" "github.com/traefik/traefik/v3/pkg/tls" "github.com/traefik/traefik/v3/pkg/types" @@ -6400,25 +6400,25 @@ func TestCrossNamespace(t *testing.T) { switch o := obj.(type) { case *corev1.Service, *corev1.Endpoints, *corev1.Secret: k8sObjects = append(k8sObjects, o) - case *v1alpha1.IngressRoute: + case *traefikv1alpha1.IngressRoute: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteTCP: + case *traefikv1alpha1.IngressRouteTCP: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteUDP: + case *traefikv1alpha1.IngressRouteUDP: crdObjects = append(crdObjects, o) - case *v1alpha1.Middleware: + case *traefikv1alpha1.Middleware: crdObjects = append(crdObjects, o) - case *v1alpha1.MiddlewareTCP: + case *traefikv1alpha1.MiddlewareTCP: crdObjects = append(crdObjects, o) - case *v1alpha1.TraefikService: + case *traefikv1alpha1.TraefikService: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSOption: + case *traefikv1alpha1.TLSOption: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSStore: + case *traefikv1alpha1.TLSStore: crdObjects = append(crdObjects, o) - case *v1alpha1.ServersTransport: + case *traefikv1alpha1.ServersTransport: crdObjects = append(crdObjects, o) - case *v1alpha1.ServersTransportTCP: + case *traefikv1alpha1.ServersTransportTCP: crdObjects = append(crdObjects, o) default: } @@ -6426,7 +6426,7 @@ func TestCrossNamespace(t *testing.T) { } kubeClient := kubefake.NewSimpleClientset(k8sObjects...) - crdClient := crdfake.NewSimpleClientset(crdObjects...) + crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...) client := newClientImpl(kubeClient, crdClient) @@ -6707,19 +6707,19 @@ func TestExternalNameService(t *testing.T) { switch o := obj.(type) { case *corev1.Service, *corev1.Endpoints, *corev1.Secret: k8sObjects = append(k8sObjects, o) - case *v1alpha1.IngressRoute: + case *traefikv1alpha1.IngressRoute: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteTCP: + case *traefikv1alpha1.IngressRouteTCP: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteUDP: + case *traefikv1alpha1.IngressRouteUDP: crdObjects = append(crdObjects, o) - case *v1alpha1.Middleware: + case *traefikv1alpha1.Middleware: crdObjects = append(crdObjects, o) - case *v1alpha1.TraefikService: + case *traefikv1alpha1.TraefikService: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSOption: + case *traefikv1alpha1.TLSOption: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSStore: + case *traefikv1alpha1.TLSStore: crdObjects = append(crdObjects, o) default: } @@ -6727,7 +6727,7 @@ func TestExternalNameService(t *testing.T) { } kubeClient := kubefake.NewSimpleClientset(k8sObjects...) - crdClient := crdfake.NewSimpleClientset(crdObjects...) + crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...) client := newClientImpl(kubeClient, crdClient) @@ -6920,19 +6920,19 @@ func TestNativeLB(t *testing.T) { switch o := obj.(type) { case *corev1.Service, *corev1.Endpoints, *corev1.Secret: k8sObjects = append(k8sObjects, o) - case *v1alpha1.IngressRoute: + case *traefikv1alpha1.IngressRoute: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteTCP: + case *traefikv1alpha1.IngressRouteTCP: crdObjects = append(crdObjects, o) - case *v1alpha1.IngressRouteUDP: + case *traefikv1alpha1.IngressRouteUDP: crdObjects = append(crdObjects, o) - case *v1alpha1.Middleware: + case *traefikv1alpha1.Middleware: crdObjects = append(crdObjects, o) - case *v1alpha1.TraefikService: + case *traefikv1alpha1.TraefikService: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSOption: + case *traefikv1alpha1.TLSOption: crdObjects = append(crdObjects, o) - case *v1alpha1.TLSStore: + case *traefikv1alpha1.TLSStore: crdObjects = append(crdObjects, o) default: } @@ -6940,7 +6940,7 @@ func TestNativeLB(t *testing.T) { } kubeClient := kubefake.NewSimpleClientset(k8sObjects...) - crdClient := crdfake.NewSimpleClientset(crdObjects...) + crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...) client := newClientImpl(kubeClient, crdClient) @@ -6964,7 +6964,6 @@ func TestNativeLB(t *testing.T) { func TestCreateBasicAuthCredentials(t *testing.T) { var k8sObjects []runtime.Object - var crdObjects []runtime.Object yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/basic_auth_secrets.yml")) if err != nil { panic(err) @@ -6980,7 +6979,7 @@ func TestCreateBasicAuthCredentials(t *testing.T) { } kubeClient := kubefake.NewSimpleClientset(k8sObjects...) - crdClient := crdfake.NewSimpleClientset(crdObjects...) + crdClient := traefikcrdfake.NewSimpleClientset() client := newClientImpl(kubeClient, crdClient) @@ -6989,13 +6988,13 @@ func TestCreateBasicAuthCredentials(t *testing.T) { eventCh, err := client.WatchAll([]string{"default"}, stopCh) require.NoError(t, err) - if k8sObjects != nil || crdObjects != nil { + if len(k8sObjects) != 0 { // just wait for the first event <-eventCh } // Testing for username/password components in basic-auth secret - basicAuth, secretErr := createBasicAuthMiddleware(client, "default", &v1alpha1.BasicAuth{Secret: "basic-auth-secret"}) + basicAuth, secretErr := createBasicAuthMiddleware(client, "default", &traefikv1alpha1.BasicAuth{Secret: "basic-auth-secret"}) require.NoError(t, secretErr) require.Len(t, basicAuth.Users, 1) @@ -7010,7 +7009,7 @@ func TestCreateBasicAuthCredentials(t *testing.T) { assert.True(t, auth.CheckSecret("password", hashedPassword)) // Testing for username/password components in htpasswd secret - basicAuth, secretErr = createBasicAuthMiddleware(client, "default", &v1alpha1.BasicAuth{Secret: "auth-secret"}) + basicAuth, secretErr = createBasicAuthMiddleware(client, "default", &traefikv1alpha1.BasicAuth{Secret: "auth-secret"}) require.NoError(t, secretErr) require.Len(t, basicAuth.Users, 2) diff --git a/pkg/provider/kubernetes/crd/kubernetes_udp.go b/pkg/provider/kubernetes/crd/kubernetes_udp.go index 5d0d02bb9..417e90d99 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_udp.go +++ b/pkg/provider/kubernetes/crd/kubernetes_udp.go @@ -9,7 +9,7 @@ import ( "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" - "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" + traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1" corev1 "k8s.io/api/core/v1" ) @@ -78,7 +78,7 @@ func (p *Provider) loadIngressRouteUDPConfiguration(ctx context.Context, client return conf } -func (p *Provider) createLoadBalancerServerUDP(client Client, parentNamespace string, service v1alpha1.ServiceUDP) (*dynamic.UDPService, error) { +func (p *Provider) createLoadBalancerServerUDP(client Client, parentNamespace string, service traefikv1alpha1.ServiceUDP) (*dynamic.UDPService, error) { ns := parentNamespace if len(service.Namespace) > 0 { if !isNamespaceAllowed(p.AllowCrossNamespace, parentNamespace, service.Namespace) { @@ -102,7 +102,7 @@ func (p *Provider) createLoadBalancerServerUDP(client Client, parentNamespace st return udpService, nil } -func (p *Provider) loadUDPServers(client Client, namespace string, svc v1alpha1.ServiceUDP) ([]dynamic.UDPServer, error) { +func (p *Provider) loadUDPServers(client Client, namespace string, svc traefikv1alpha1.ServiceUDP) ([]dynamic.UDPServer, error) { service, exists, err := client.GetService(namespace, svc.Name) if err != nil { return nil, err diff --git a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/register.go b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/register.go index e4c0d2c75..be2199db9 100644 --- a/pkg/provider/kubernetes/crd/traefikio/v1alpha1/register.go +++ b/pkg/provider/kubernetes/crd/traefikio/v1alpha1/register.go @@ -3,7 +3,7 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + kschema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName is the group name for Traefik. @@ -18,15 +18,15 @@ var ( ) // SchemeGroupVersion is group version used to register these objects. -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} +var SchemeGroupVersion = kschema.GroupVersion{Group: GroupName, Version: "v1alpha1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind. -func Kind(kind string) schema.GroupKind { +func Kind(kind string) kschema.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() } // Resource takes an unqualified resource and returns a Group qualified GroupResource. -func Resource(resource string) schema.GroupResource { +func Resource(resource string) kschema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } diff --git a/pkg/provider/kubernetes/gateway/client.go b/pkg/provider/kubernetes/gateway/client.go index 5ad1772bb..22a93dcda 100644 --- a/pkg/provider/kubernetes/gateway/client.go +++ b/pkg/provider/kubernetes/gateway/client.go @@ -9,16 +9,16 @@ import ( "github.com/rs/zerolog/log" corev1 "k8s.io/api/core/v1" - kubeerror "k8s.io/apimachinery/pkg/api/errors" + kerror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" + kinformers "k8s.io/client-go/informers" + kclientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "sigs.k8s.io/gateway-api/apis/v1alpha2" - "sigs.k8s.io/gateway-api/pkg/client/clientset/gateway/versioned" - "sigs.k8s.io/gateway-api/pkg/client/informers/gateway/externalversions" + gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gateclientset "sigs.k8s.io/gateway-api/pkg/client/clientset/gateway/versioned" + gateinformers "sigs.k8s.io/gateway-api/pkg/client/informers/gateway/externalversions" ) const resyncPeriod = 10 * time.Minute @@ -33,7 +33,7 @@ func (reh *resourceEventHandler) OnAdd(obj interface{}) { func (reh *resourceEventHandler) OnUpdate(oldObj, newObj interface{}) { switch oldObj.(type) { - case *v1alpha2.GatewayClass: + case *gatev1alpha2.GatewayClass: // Skip update for gateway classes. We only manage addition or deletion for this cluster-wide resource. return default: @@ -50,13 +50,13 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) { // The stores can then be accessed via the Get* functions. type Client interface { WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) - GetGatewayClasses() ([]*v1alpha2.GatewayClass, error) - UpdateGatewayStatus(gateway *v1alpha2.Gateway, gatewayStatus v1alpha2.GatewayStatus) error - UpdateGatewayClassStatus(gatewayClass *v1alpha2.GatewayClass, condition metav1.Condition) error - GetGateways() []*v1alpha2.Gateway - GetHTTPRoutes(namespaces []string) ([]*v1alpha2.HTTPRoute, error) - GetTCPRoutes(namespaces []string) ([]*v1alpha2.TCPRoute, error) - GetTLSRoutes(namespaces []string) ([]*v1alpha2.TLSRoute, error) + GetGatewayClasses() ([]*gatev1alpha2.GatewayClass, error) + UpdateGatewayStatus(gateway *gatev1alpha2.Gateway, gatewayStatus gatev1alpha2.GatewayStatus) error + UpdateGatewayClassStatus(gatewayClass *gatev1alpha2.GatewayClass, condition metav1.Condition) error + GetGateways() []*gatev1alpha2.Gateway + GetHTTPRoutes(namespaces []string) ([]*gatev1alpha2.HTTPRoute, error) + GetTCPRoutes(namespaces []string) ([]*gatev1alpha2.TCPRoute, error) + GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRoute, error) GetService(namespace, name string) (*corev1.Service, bool, error) GetSecret(namespace, name string) (*corev1.Secret, bool, error) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) @@ -64,14 +64,14 @@ type Client interface { } type clientWrapper struct { - csGateway versioned.Interface - csKube kubernetes.Interface + csGateway gateclientset.Interface + csKube kclientset.Interface - factoryNamespace informers.SharedInformerFactory - factoryGatewayClass externalversions.SharedInformerFactory - factoriesGateway map[string]externalversions.SharedInformerFactory - factoriesKube map[string]informers.SharedInformerFactory - factoriesSecret map[string]informers.SharedInformerFactory + factoryNamespace kinformers.SharedInformerFactory + factoryGatewayClass gateinformers.SharedInformerFactory + factoriesGateway map[string]gateinformers.SharedInformerFactory + factoriesKube map[string]kinformers.SharedInformerFactory + factoriesSecret map[string]kinformers.SharedInformerFactory isNamespaceAll bool watchedNamespaces []string @@ -80,12 +80,12 @@ type clientWrapper struct { } func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { - csGateway, err := versioned.NewForConfig(c) + csGateway, err := gateclientset.NewForConfig(c) if err != nil { return nil, err } - csKube, err := kubernetes.NewForConfig(c) + csKube, err := kclientset.NewForConfig(c) if err != nil { return nil, err } @@ -93,13 +93,13 @@ func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { return newClientImpl(csKube, csGateway), nil } -func newClientImpl(csKube kubernetes.Interface, csGateway versioned.Interface) *clientWrapper { +func newClientImpl(csKube kclientset.Interface, csGateway gateclientset.Interface) *clientWrapper { return &clientWrapper{ csGateway: csGateway, csKube: csKube, - factoriesGateway: make(map[string]externalversions.SharedInformerFactory), - factoriesKube: make(map[string]informers.SharedInformerFactory), - factoriesSecret: make(map[string]informers.SharedInformerFactory), + factoriesGateway: make(map[string]gateinformers.SharedInformerFactory), + factoriesKube: make(map[string]kinformers.SharedInformerFactory), + factoriesSecret: make(map[string]kinformers.SharedInformerFactory), } } @@ -126,8 +126,7 @@ func newExternalClusterClientFromFile(file string) (*clientWrapper, error) { return createClientFromConfig(configFromFlags) } -// newExternalClusterClient returns a new Provider client that may run outside -// of the cluster. +// newExternalClusterClient returns a new Provider client that may run outside of the cluster. // The endpoint parameter must not be empty. func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) { if endpoint == "" { @@ -171,28 +170,55 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< options.LabelSelector = c.labelSelector } - c.factoryNamespace = informers.NewSharedInformerFactory(c.csKube, resyncPeriod) - c.factoryNamespace.Core().V1().Namespaces().Informer().AddEventHandler(eventHandler) + c.factoryNamespace = kinformers.NewSharedInformerFactory(c.csKube, resyncPeriod) + _, err := c.factoryNamespace.Core().V1().Namespaces().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } - c.factoryGatewayClass = externalversions.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, externalversions.WithTweakListOptions(labelSelectorOptions)) - c.factoryGatewayClass.Gateway().V1alpha2().GatewayClasses().Informer().AddEventHandler(eventHandler) + c.factoryGatewayClass = gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithTweakListOptions(labelSelectorOptions)) + _, err = c.factoryGatewayClass.Gateway().V1alpha2().GatewayClasses().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } // TODO manage Reference Policy // https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.ReferencePolicy for _, ns := range namespaces { - factoryGateway := externalversions.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, externalversions.WithNamespace(ns)) - factoryGateway.Gateway().V1alpha2().Gateways().Informer().AddEventHandler(eventHandler) - factoryGateway.Gateway().V1alpha2().HTTPRoutes().Informer().AddEventHandler(eventHandler) - factoryGateway.Gateway().V1alpha2().TCPRoutes().Informer().AddEventHandler(eventHandler) - factoryGateway.Gateway().V1alpha2().TLSRoutes().Informer().AddEventHandler(eventHandler) + factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns)) + _, err = factoryGateway.Gateway().V1alpha2().Gateways().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryGateway.Gateway().V1alpha2().HTTPRoutes().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryGateway.Gateway().V1alpha2().TCPRoutes().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryGateway.Gateway().V1alpha2().TLSRoutes().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } - factoryKube := informers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, informers.WithNamespace(ns)) - factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) - factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns)) + _, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } - factorySecret := informers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, informers.WithNamespace(ns), informers.WithTweakListOptions(notOwnedByHelm)) - factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm)) + _, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } c.factoriesGateway[ns] = factoryGateway c.factoriesKube[ns] = factoryKube @@ -260,8 +286,8 @@ func (c *clientWrapper) GetNamespaces(selector labels.Selector) ([]string, error return namespaces, nil } -func (c *clientWrapper) GetHTTPRoutes(namespaces []string) ([]*v1alpha2.HTTPRoute, error) { - var httpRoutes []*v1alpha2.HTTPRoute +func (c *clientWrapper) GetHTTPRoutes(namespaces []string) ([]*gatev1alpha2.HTTPRoute, error) { + var httpRoutes []*gatev1alpha2.HTTPRoute for _, namespace := range namespaces { if !c.isWatchedNamespace(namespace) { log.Warn().Msgf("Failed to get HTTPRoutes: %q is not within watched namespaces", namespace) @@ -284,8 +310,8 @@ func (c *clientWrapper) GetHTTPRoutes(namespaces []string) ([]*v1alpha2.HTTPRout return httpRoutes, nil } -func (c *clientWrapper) GetTCPRoutes(namespaces []string) ([]*v1alpha2.TCPRoute, error) { - var tcpRoutes []*v1alpha2.TCPRoute +func (c *clientWrapper) GetTCPRoutes(namespaces []string) ([]*gatev1alpha2.TCPRoute, error) { + var tcpRoutes []*gatev1alpha2.TCPRoute for _, namespace := range namespaces { if !c.isWatchedNamespace(namespace) { log.Warn().Msgf("Failed to get TCPRoutes: %q is not within watched namespaces", namespace) @@ -307,8 +333,8 @@ func (c *clientWrapper) GetTCPRoutes(namespaces []string) ([]*v1alpha2.TCPRoute, return tcpRoutes, nil } -func (c *clientWrapper) GetTLSRoutes(namespaces []string) ([]*v1alpha2.TLSRoute, error) { - var tlsRoutes []*v1alpha2.TLSRoute +func (c *clientWrapper) GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRoute, error) { + var tlsRoutes []*gatev1alpha2.TLSRoute for _, namespace := range namespaces { if !c.isWatchedNamespace(namespace) { log.Warn().Msgf("Failed to get TLSRoutes: %q is not within watched namespaces", namespace) @@ -330,8 +356,8 @@ func (c *clientWrapper) GetTLSRoutes(namespaces []string) ([]*v1alpha2.TLSRoute, return tlsRoutes, nil } -func (c *clientWrapper) GetGateways() []*v1alpha2.Gateway { - var result []*v1alpha2.Gateway +func (c *clientWrapper) GetGateways() []*gatev1alpha2.Gateway { + var result []*gatev1alpha2.Gateway for ns, factory := range c.factoriesGateway { gateways, err := factory.Gateway().V1alpha2().Gateways().Lister().List(labels.Everything()) @@ -345,11 +371,11 @@ func (c *clientWrapper) GetGateways() []*v1alpha2.Gateway { return result } -func (c *clientWrapper) GetGatewayClasses() ([]*v1alpha2.GatewayClass, error) { +func (c *clientWrapper) GetGatewayClasses() ([]*gatev1alpha2.GatewayClass, error) { return c.factoryGatewayClass.Gateway().V1alpha2().GatewayClasses().Lister().List(labels.Everything()) } -func (c *clientWrapper) UpdateGatewayClassStatus(gatewayClass *v1alpha2.GatewayClass, condition metav1.Condition) error { +func (c *clientWrapper) UpdateGatewayClassStatus(gatewayClass *gatev1alpha2.GatewayClass, condition metav1.Condition) error { gc := gatewayClass.DeepCopy() var newConditions []metav1.Condition @@ -380,7 +406,7 @@ func (c *clientWrapper) UpdateGatewayClassStatus(gatewayClass *v1alpha2.GatewayC return nil } -func (c *clientWrapper) UpdateGatewayStatus(gateway *v1alpha2.Gateway, gatewayStatus v1alpha2.GatewayStatus) error { +func (c *clientWrapper) UpdateGatewayStatus(gateway *gatev1alpha2.Gateway, gatewayStatus gatev1alpha2.GatewayStatus) error { if !c.isWatchedNamespace(gateway.Namespace) { return fmt.Errorf("cannot update Gateway status %s/%s: namespace is not within watched namespaces", gateway.Namespace, gateway.Name) } @@ -403,7 +429,7 @@ func (c *clientWrapper) UpdateGatewayStatus(gateway *v1alpha2.Gateway, gatewaySt return nil } -func statusEquals(oldStatus, newStatus v1alpha2.GatewayStatus) bool { +func statusEquals(oldStatus, newStatus gatev1alpha2.GatewayStatus) bool { if len(oldStatus.Listeners) != len(newStatus.Listeners) { return false } @@ -510,7 +536,7 @@ func eventHandlerFunc(events chan<- interface{}, obj interface{}) { // translateNotFoundError will translate a "not found" error to a boolean return // value which indicates if the resource exists and a nil error. func translateNotFoundError(err error) (bool, error) { - if kubeerror.IsNotFound(err) { + if kerror.IsNotFound(err) { return false, nil } return err == nil, err diff --git a/pkg/provider/kubernetes/gateway/client_mock_test.go b/pkg/provider/kubernetes/gateway/client_mock_test.go index 1003a777c..10c78801c 100644 --- a/pkg/provider/kubernetes/gateway/client_mock_test.go +++ b/pkg/provider/kubernetes/gateway/client_mock_test.go @@ -9,15 +9,15 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/gateway-api/apis/v1alpha2" + kscheme "k8s.io/client-go/kubernetes/scheme" + gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) var _ Client = (*clientMock)(nil) func init() { // required by k8s.MustParseYaml - err := v1alpha2.AddToScheme(scheme.Scheme) + err := gatev1alpha2.AddToScheme(kscheme.Scheme) if err != nil { panic(err) } @@ -33,11 +33,11 @@ type clientMock struct { apiSecretError error apiEndpointsError error - gatewayClasses []*v1alpha2.GatewayClass - gateways []*v1alpha2.Gateway - httpRoutes []*v1alpha2.HTTPRoute - tcpRoutes []*v1alpha2.TCPRoute - tlsRoutes []*v1alpha2.TLSRoute + gatewayClasses []*gatev1alpha2.GatewayClass + gateways []*gatev1alpha2.Gateway + httpRoutes []*gatev1alpha2.HTTPRoute + tcpRoutes []*gatev1alpha2.TCPRoute + tlsRoutes []*gatev1alpha2.TLSRoute watchChan chan interface{} } @@ -62,15 +62,15 @@ func newClientMock(paths ...string) clientMock { c.namespaces = append(c.namespaces, o) case *corev1.Endpoints: c.endpoints = append(c.endpoints, o) - case *v1alpha2.GatewayClass: + case *gatev1alpha2.GatewayClass: c.gatewayClasses = append(c.gatewayClasses, o) - case *v1alpha2.Gateway: + case *gatev1alpha2.Gateway: c.gateways = append(c.gateways, o) - case *v1alpha2.HTTPRoute: + case *gatev1alpha2.HTTPRoute: c.httpRoutes = append(c.httpRoutes, o) - case *v1alpha2.TCPRoute: + case *gatev1alpha2.TCPRoute: c.tcpRoutes = append(c.tcpRoutes, o) - case *v1alpha2.TLSRoute: + case *gatev1alpha2.TLSRoute: c.tlsRoutes = append(c.tlsRoutes, o) default: panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o)) @@ -81,7 +81,7 @@ func newClientMock(paths ...string) clientMock { return c } -func (c clientMock) UpdateGatewayStatus(gateway *v1alpha2.Gateway, gatewayStatus v1alpha2.GatewayStatus) error { +func (c clientMock) UpdateGatewayStatus(gateway *gatev1alpha2.Gateway, gatewayStatus gatev1alpha2.GatewayStatus) error { for _, g := range c.gateways { if g.Name == gateway.Name { if !statusEquals(g.Status, gatewayStatus) { @@ -94,7 +94,7 @@ func (c clientMock) UpdateGatewayStatus(gateway *v1alpha2.Gateway, gatewayStatus return nil } -func (c clientMock) UpdateGatewayClassStatus(gatewayClass *v1alpha2.GatewayClass, condition metav1.Condition) error { +func (c clientMock) UpdateGatewayClassStatus(gatewayClass *gatev1alpha2.GatewayClass, condition metav1.Condition) error { for _, gc := range c.gatewayClasses { if gc.Name == gatewayClass.Name { for _, c := range gc.Status.Conditions { @@ -110,7 +110,7 @@ func (c clientMock) UpdateGatewayClassStatus(gatewayClass *v1alpha2.GatewayClass return nil } -func (c clientMock) UpdateGatewayStatusConditions(gateway *v1alpha2.Gateway, condition metav1.Condition) error { +func (c clientMock) UpdateGatewayStatusConditions(gateway *gatev1alpha2.Gateway, condition metav1.Condition) error { for _, g := range c.gatewayClasses { if g.Name == gateway.Name { for _, c := range g.Status.Conditions { @@ -126,11 +126,11 @@ func (c clientMock) UpdateGatewayStatusConditions(gateway *v1alpha2.Gateway, con return nil } -func (c clientMock) GetGatewayClasses() ([]*v1alpha2.GatewayClass, error) { +func (c clientMock) GetGatewayClasses() ([]*gatev1alpha2.GatewayClass, error) { return c.gatewayClasses, nil } -func (c clientMock) GetGateways() []*v1alpha2.Gateway { +func (c clientMock) GetGateways() []*gatev1alpha2.Gateway { return c.gateways } @@ -148,8 +148,8 @@ func (c clientMock) GetNamespaces(selector labels.Selector) ([]string, error) { return ns, nil } -func (c clientMock) GetHTTPRoutes(namespaces []string) ([]*v1alpha2.HTTPRoute, error) { - var httpRoutes []*v1alpha2.HTTPRoute +func (c clientMock) GetHTTPRoutes(namespaces []string) ([]*gatev1alpha2.HTTPRoute, error) { + var httpRoutes []*gatev1alpha2.HTTPRoute for _, namespace := range namespaces { for _, httpRoute := range c.httpRoutes { if inNamespace(httpRoute.ObjectMeta, namespace) { @@ -160,8 +160,8 @@ func (c clientMock) GetHTTPRoutes(namespaces []string) ([]*v1alpha2.HTTPRoute, e return httpRoutes, nil } -func (c clientMock) GetTCPRoutes(namespaces []string) ([]*v1alpha2.TCPRoute, error) { - var tcpRoutes []*v1alpha2.TCPRoute +func (c clientMock) GetTCPRoutes(namespaces []string) ([]*gatev1alpha2.TCPRoute, error) { + var tcpRoutes []*gatev1alpha2.TCPRoute for _, namespace := range namespaces { for _, tcpRoute := range c.tcpRoutes { if inNamespace(tcpRoute.ObjectMeta, namespace) { @@ -172,8 +172,8 @@ func (c clientMock) GetTCPRoutes(namespaces []string) ([]*v1alpha2.TCPRoute, err return tcpRoutes, nil } -func (c clientMock) GetTLSRoutes(namespaces []string) ([]*v1alpha2.TLSRoute, error) { - var tlsRoutes []*v1alpha2.TLSRoute +func (c clientMock) GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRoute, error) { + var tlsRoutes []*gatev1alpha2.TLSRoute for _, namespace := range namespaces { for _, tlsRoute := range c.tlsRoutes { if inNamespace(tlsRoute.ObjectMeta, namespace) { diff --git a/pkg/provider/kubernetes/gateway/client_test.go b/pkg/provider/kubernetes/gateway/client_test.go index f90f7dfae..794f7d6a8 100644 --- a/pkg/provider/kubernetes/gateway/client_test.go +++ b/pkg/provider/kubernetes/gateway/client_test.go @@ -5,32 +5,32 @@ import ( "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) func TestStatusEquals(t *testing.T) { testCases := []struct { desc string - statusA v1alpha2.GatewayStatus - statusB v1alpha2.GatewayStatus + statusA gatev1alpha2.GatewayStatus + statusB gatev1alpha2.GatewayStatus expected bool }{ { desc: "Empty", - statusA: v1alpha2.GatewayStatus{}, - statusB: v1alpha2.GatewayStatus{}, + statusA: gatev1alpha2.GatewayStatus{}, + statusB: gatev1alpha2.GatewayStatus{}, expected: true, }, { desc: "Same status", - statusA: v1alpha2.GatewayStatus{ + statusA: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobar", Reason: "foobar", }, }, - Listeners: []v1alpha2.ListenerStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "foo", Conditions: []metav1.Condition{ @@ -42,14 +42,14 @@ func TestStatusEquals(t *testing.T) { }, }, }, - statusB: v1alpha2.GatewayStatus{ + statusB: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobar", Reason: "foobar", }, }, - Listeners: []v1alpha2.ListenerStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "foo", Conditions: []metav1.Condition{ @@ -65,11 +65,11 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Listeners length not equal", - statusA: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{}, + statusA: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{}, }, - statusB: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusB: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ {}, }, }, @@ -77,10 +77,10 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway conditions length not equal", - statusA: v1alpha2.GatewayStatus{ + statusA: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{}, }, - statusB: v1alpha2.GatewayStatus{ + statusB: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ {}, }, @@ -89,14 +89,14 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway conditions different types", - statusA: v1alpha2.GatewayStatus{ + statusA: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobar", }, }, }, - statusB: v1alpha2.GatewayStatus{ + statusB: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobir", @@ -107,14 +107,14 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway conditions same types but different reason", - statusA: v1alpha2.GatewayStatus{ + statusA: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobar", }, }, }, - statusB: v1alpha2.GatewayStatus{ + statusB: gatev1alpha2.GatewayStatus{ Conditions: []metav1.Condition{ { Type: "foobar", @@ -126,16 +126,16 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway listeners conditions length", - statusA: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusA: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "foo", Conditions: []metav1.Condition{}, }, }, }, - statusB: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusB: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "foo", Conditions: []metav1.Condition{ @@ -148,8 +148,8 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway listeners conditions same types but different status", - statusA: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusA: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Conditions: []metav1.Condition{ { @@ -159,8 +159,8 @@ func TestStatusEquals(t *testing.T) { }, }, }, - statusB: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusB: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Conditions: []metav1.Condition{ { @@ -175,8 +175,8 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway listeners conditions same types but different message", - statusA: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusA: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Conditions: []metav1.Condition{ { @@ -186,8 +186,8 @@ func TestStatusEquals(t *testing.T) { }, }, }, - statusB: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusB: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Conditions: []metav1.Condition{ { @@ -202,8 +202,8 @@ func TestStatusEquals(t *testing.T) { }, { desc: "Gateway listeners conditions same types/reason but different names", - statusA: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusA: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "foo", Conditions: []metav1.Condition{ @@ -215,8 +215,8 @@ func TestStatusEquals(t *testing.T) { }, }, }, - statusB: v1alpha2.GatewayStatus{ - Listeners: []v1alpha2.ListenerStatus{ + statusB: gatev1alpha2.GatewayStatus{ + Listeners: []gatev1alpha2.ListenerStatus{ { Name: "bar", Conditions: []metav1.Condition{ diff --git a/pkg/provider/kubernetes/gateway/kubernetes.go b/pkg/provider/kubernetes/gateway/kubernetes.go index 170540394..d7a715de3 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes.go +++ b/pkg/provider/kubernetes/gateway/kubernetes.go @@ -31,7 +31,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/utils/pointer" "k8s.io/utils/strings/slices" - "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) const ( @@ -209,14 +209,14 @@ func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Clie gatewayClassNames[gatewayClass.Name] = struct{}{} err := client.UpdateGatewayClassStatus(gatewayClass, metav1.Condition{ - Type: string(v1alpha2.GatewayClassConditionStatusAccepted), + Type: string(gatev1alpha2.GatewayClassConditionStatusAccepted), Status: metav1.ConditionTrue, Reason: "Handled", Message: "Handled by Traefik controller", LastTransitionTime: metav1.Now(), }) if err != nil { - logger.Error().Err(err).Msgf("Failed to update %s condition", v1alpha2.GatewayClassConditionStatusAccepted) + logger.Error().Err(err).Msgf("Failed to update %s condition", gatev1alpha2.GatewayClassConditionStatusAccepted) } } } @@ -272,7 +272,7 @@ func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Clie return conf } -func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway *v1alpha2.Gateway) (*dynamic.Configuration, error) { +func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway *gatev1alpha2.Gateway) (*dynamic.Configuration, error) { conf := &dynamic.Configuration{ HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{}, @@ -318,15 +318,15 @@ func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway return conf, nil } -func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *v1alpha2.Gateway, conf *dynamic.Configuration, tlsConfigs map[string]*tls.CertAndStores) []v1alpha2.ListenerStatus { +func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *gatev1alpha2.Gateway, conf *dynamic.Configuration, tlsConfigs map[string]*tls.CertAndStores) []gatev1alpha2.ListenerStatus { logger := log.Ctx(ctx) - listenerStatuses := make([]v1alpha2.ListenerStatus, len(gateway.Spec.Listeners)) + listenerStatuses := make([]gatev1alpha2.ListenerStatus, len(gateway.Spec.Listeners)) allocatedListeners := make(map[string]struct{}) for i, listener := range gateway.Spec.Listeners { - listenerStatuses[i] = v1alpha2.ListenerStatus{ + listenerStatuses[i] = gatev1alpha2.ListenerStatus{ Name: listener.Name, - SupportedKinds: []v1alpha2.RouteGroupKind{}, + SupportedKinds: []gatev1alpha2.RouteGroupKind{}, Conditions: []metav1.Condition{}, } @@ -348,7 +348,7 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * if _, ok := allocatedListeners[listenerKey]; ok { listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionConflicted), + Type: string(gatev1alpha2.ListenerConditionConflicted), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), Reason: "DuplicateListener", @@ -364,19 +364,19 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * if err != nil { // update "Detached" status with "PortUnavailable" reason listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonPortUnavailable), + Reason: string(gatev1alpha2.ListenerReasonPortUnavailable), Message: fmt.Sprintf("Cannot find entryPoint for Gateway: %v", err), }) continue } - if (listener.Protocol == v1alpha2.HTTPProtocolType || listener.Protocol == v1alpha2.TCPProtocolType) && listener.TLS != nil { + if (listener.Protocol == gatev1alpha2.HTTPProtocolType || listener.Protocol == gatev1alpha2.TCPProtocolType) && listener.TLS != nil { listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), Reason: "InvalidTLSConfiguration", // TODO check the spec if a proper reason is introduced at some point @@ -387,11 +387,11 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * } // TLS - if listener.Protocol == v1alpha2.HTTPSProtocolType || listener.Protocol == v1alpha2.TLSProtocolType { - if listener.TLS == nil || (len(listener.TLS.CertificateRefs) == 0 && listener.TLS.Mode != nil && *listener.TLS.Mode != v1alpha2.TLSModePassthrough) { + if listener.Protocol == gatev1alpha2.HTTPSProtocolType || listener.Protocol == gatev1alpha2.TLSProtocolType { + if listener.TLS == nil || (len(listener.TLS.CertificateRefs) == 0 && listener.TLS.Mode != nil && *listener.TLS.Mode != gatev1alpha2.TLSModePassthrough) { // update "Detached" status with "UnsupportedProtocol" reason listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), Reason: "InvalidTLSConfiguration", // TODO check the spec if a proper reason is introduced at some point @@ -402,12 +402,12 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * continue } - var tlsModeType v1alpha2.TLSModeType + var tlsModeType gatev1alpha2.TLSModeType if listener.TLS.Mode != nil { tlsModeType = *listener.TLS.Mode } - isTLSPassthrough := tlsModeType == v1alpha2.TLSModePassthrough + isTLSPassthrough := tlsModeType == gatev1alpha2.TLSModePassthrough if isTLSPassthrough && len(listener.TLS.CertificateRefs) > 0 { // https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.GatewayTLSConfig @@ -418,12 +418,12 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * // Protocol TLS -> Passthrough -> TLSRoute/TCPRoute // Protocol TLS -> Terminate -> TLSRoute/TCPRoute // Protocol HTTPS -> Terminate -> HTTPRoute - if listener.Protocol == v1alpha2.HTTPSProtocolType && isTLSPassthrough { + if listener.Protocol == gatev1alpha2.HTTPSProtocolType && isTLSPassthrough { listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonUnsupportedProtocol), + Reason: string(gatev1alpha2.ListenerReasonUnsupportedProtocol), Message: "HTTPS protocol is not supported with TLS mode Passthrough", }) @@ -434,10 +434,10 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * if len(listener.TLS.CertificateRefs) == 0 { // update "ResolvedRefs" status true with "InvalidCertificateRef" reason listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonInvalidCertificateRef), + Reason: string(gatev1alpha2.ListenerReasonInvalidCertificateRef), Message: "One TLS CertificateRef is required in Terminate mode", }) @@ -451,10 +451,10 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * certificateRef.Group == nil || (*certificateRef.Group != "" && *certificateRef.Group != "core") { // update "ResolvedRefs" status true with "InvalidCertificateRef" reason listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonInvalidCertificateRef), + Reason: string(gatev1alpha2.ListenerReasonInvalidCertificateRef), Message: fmt.Sprintf("Unsupported TLS CertificateRef group/kind: %v/%v", certificateRef.Group, certificateRef.Kind), }) @@ -464,10 +464,10 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * // TODO Support ReferencePolicy to support cross namespace references. if certificateRef.Namespace != nil && string(*certificateRef.Namespace) != gateway.Namespace { listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonInvalidCertificateRef), + Reason: string(gatev1alpha2.ListenerReasonInvalidCertificateRef), Message: "Cross namespace secrets are not supported", }) @@ -480,10 +480,10 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * if err != nil { // update "ResolvedRefs" status true with "InvalidCertificateRef" reason listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonInvalidCertificateRef), + Reason: string(gatev1alpha2.ListenerReasonInvalidCertificateRef), Message: fmt.Sprintf("Error while retrieving certificate: %v", err), }) @@ -510,10 +510,10 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway * return listenerStatuses } -func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) (v1alpha2.GatewayStatus, error) { +func (p *Provider) makeGatewayStatus(listenerStatuses []gatev1alpha2.ListenerStatus) (gatev1alpha2.GatewayStatus, error) { // As Status.Addresses are not implemented yet, we initialize an empty array to follow the API expectations. - gatewayStatus := v1alpha2.GatewayStatus{ - Addresses: []v1alpha2.GatewayAddress{}, + gatewayStatus := gatev1alpha2.GatewayStatus{ + Addresses: []gatev1alpha2.GatewayAddress{}, } var result error @@ -521,7 +521,7 @@ func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) if len(listener.Conditions) == 0 { // GatewayConditionReady "Ready", GatewayConditionReason "ListenerReady" listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionReady), + Type: string(gatev1alpha2.ListenerConditionReady), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), Reason: "ListenerReady", @@ -539,10 +539,10 @@ func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) if result != nil { // GatewayConditionReady "Ready", GatewayConditionReason "ListenersNotValid" gatewayStatus.Conditions = append(gatewayStatus.Conditions, metav1.Condition{ - Type: string(v1alpha2.GatewayConditionReady), + Type: string(gatev1alpha2.GatewayConditionReady), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.GatewayReasonListenersNotValid), + Reason: string(gatev1alpha2.GatewayReasonListenersNotValid), Message: "All Listeners must be valid", }) @@ -554,7 +554,7 @@ func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) gatewayStatus.Conditions = append(gatewayStatus.Conditions, // update "Scheduled" status with "ResourcesAvailable" reason metav1.Condition{ - Type: string(v1alpha2.GatewayConditionScheduled), + Type: string(gatev1alpha2.GatewayConditionScheduled), Status: metav1.ConditionTrue, Reason: "ResourcesAvailable", Message: "Resources available", @@ -562,7 +562,7 @@ func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) }, // update "Ready" status with "ListenersValid" reason metav1.Condition{ - Type: string(v1alpha2.GatewayConditionReady), + Type: string(gatev1alpha2.GatewayConditionReady), Status: metav1.ConditionTrue, Reason: "ListenersValid", Message: "Listeners valid", @@ -573,14 +573,14 @@ func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha2.ListenerStatus) return gatewayStatus, nil } -func (p *Provider) entryPointName(port v1alpha2.PortNumber, protocol v1alpha2.ProtocolType) (string, error) { +func (p *Provider) entryPointName(port gatev1alpha2.PortNumber, protocol gatev1alpha2.ProtocolType) (string, error) { portStr := strconv.FormatInt(int64(port), 10) for name, entryPoint := range p.EntryPoints { if strings.HasSuffix(entryPoint.Address, ":"+portStr) { // If the protocol is HTTP the entryPoint must have no TLS conf - // Not relevant for v1alpha2.TLSProtocolType && v1alpha2.TCPProtocolType - if protocol == v1alpha2.HTTPProtocolType && entryPoint.HasHTTPTLSConf { + // Not relevant for gatev1alpha2.TLSProtocolType && gatev1alpha2.TCPProtocolType + if protocol == gatev1alpha2.HTTPProtocolType && entryPoint.HasHTTPTLSConf { continue } @@ -591,43 +591,43 @@ func (p *Provider) entryPointName(port v1alpha2.PortNumber, protocol v1alpha2.Pr return "", fmt.Errorf("no matching entryPoint for port %d and protocol %q", port, protocol) } -func supportedRouteKinds(protocol v1alpha2.ProtocolType) ([]v1alpha2.RouteGroupKind, []metav1.Condition) { - group := v1alpha2.Group(v1alpha2.GroupName) +func supportedRouteKinds(protocol gatev1alpha2.ProtocolType) ([]gatev1alpha2.RouteGroupKind, []metav1.Condition) { + group := gatev1alpha2.Group(gatev1alpha2.GroupName) switch protocol { - case v1alpha2.TCPProtocolType: - return []v1alpha2.RouteGroupKind{{Kind: kindTCPRoute, Group: &group}}, nil + case gatev1alpha2.TCPProtocolType: + return []gatev1alpha2.RouteGroupKind{{Kind: kindTCPRoute, Group: &group}}, nil - case v1alpha2.HTTPProtocolType, v1alpha2.HTTPSProtocolType: - return []v1alpha2.RouteGroupKind{{Kind: kindHTTPRoute, Group: &group}}, nil + case gatev1alpha2.HTTPProtocolType, gatev1alpha2.HTTPSProtocolType: + return []gatev1alpha2.RouteGroupKind{{Kind: kindHTTPRoute, Group: &group}}, nil - case v1alpha2.TLSProtocolType: - return []v1alpha2.RouteGroupKind{ + case gatev1alpha2.TLSProtocolType: + return []gatev1alpha2.RouteGroupKind{ {Kind: kindTCPRoute, Group: &group}, {Kind: kindTLSRoute, Group: &group}, }, nil } return nil, []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonUnsupportedProtocol), + Reason: string(gatev1alpha2.ListenerReasonUnsupportedProtocol), Message: fmt.Sprintf("Unsupported listener protocol %q", protocol), }} } -func getAllowedRouteKinds(listener v1alpha2.Listener, supportedKinds []v1alpha2.RouteGroupKind) ([]v1alpha2.RouteGroupKind, []metav1.Condition) { +func getAllowedRouteKinds(listener gatev1alpha2.Listener, supportedKinds []gatev1alpha2.RouteGroupKind) ([]gatev1alpha2.RouteGroupKind, []metav1.Condition) { if listener.AllowedRoutes == nil || len(listener.AllowedRoutes.Kinds) == 0 { return supportedKinds, nil } var ( - routeKinds []v1alpha2.RouteGroupKind + routeKinds []gatev1alpha2.RouteGroupKind conditions []metav1.Condition ) - uniqRouteKinds := map[v1alpha2.Kind]struct{}{} + uniqRouteKinds := map[gatev1alpha2.Kind]struct{}{} for _, routeKind := range listener.AllowedRoutes.Kinds { var isSupported bool for _, kind := range supportedKinds { @@ -639,10 +639,10 @@ func getAllowedRouteKinds(listener v1alpha2.Listener, supportedKinds []v1alpha2. if !isSupported { conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionDetached), + Type: string(gatev1alpha2.ListenerConditionDetached), Status: metav1.ConditionTrue, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonInvalidRouteKinds), + Reason: string(gatev1alpha2.ListenerReasonInvalidRouteKinds), Message: fmt.Sprintf("Listener protocol %q does not support RouteGroupKind %v/%s", listener.Protocol, routeKind.Group, routeKind.Kind), }) continue @@ -657,7 +657,7 @@ func getAllowedRouteKinds(listener v1alpha2.Listener, supportedKinds []v1alpha2. return routeKinds, conditions } -func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha2.Listener, gateway *v1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { +func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener gatev1alpha2.Listener, gateway *gatev1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { if listener.AllowedRoutes == nil { // Should not happen due to validation. return nil @@ -667,7 +667,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouteNamespacesSelector", // Should never happen as the selector is validated by kubernetes @@ -679,10 +679,10 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonRefNotPermitted), + Reason: string(gatev1alpha2.ListenerReasonRefNotPermitted), Message: fmt.Sprintf("Cannot fetch HTTPRoutes: %v", err), }} } @@ -708,7 +708,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha hostRule, err := hostRule(hostnames) if err != nil { conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouteHostname", // TODO check the spec if a proper reason is introduced at some point @@ -722,7 +722,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "UnsupportedPathOrHeaderType", // TODO check the spec if a proper reason is introduced at some point @@ -735,7 +735,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha EntryPoints: []string{ep}, } - if listener.Protocol == v1alpha2.HTTPSProtocolType && listener.TLS != nil { + if listener.Protocol == gatev1alpha2.HTTPSProtocolType && listener.TLS != nil { // TODO support let's encrypt router.TLS = &dynamic.RouterTLSConfig{} } @@ -746,7 +746,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouterKey", // Should never happen @@ -761,7 +761,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "InvalidFilters" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidFilters", // TODO check the spec if a proper reason is introduced at some point @@ -789,7 +789,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidBackendRefs", // TODO check the spec if a proper reason is introduced at some point @@ -818,7 +818,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha return conditions } -func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2.Listener, gateway *v1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { +func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener gatev1alpha2.Listener, gateway *gatev1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { if listener.AllowedRoutes == nil { // Should not happen due to validation. return nil @@ -828,7 +828,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouteNamespacesSelector", // TODO should never happen as the selector is validated by Kubernetes @@ -840,10 +840,10 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonRefNotPermitted), + Reason: string(gatev1alpha2.ListenerReasonRefNotPermitted), Message: fmt.Sprintf("Cannot fetch TCPRoutes: %v", err), }} } @@ -864,10 +864,10 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. EntryPoints: []string{ep}, } - if listener.Protocol == v1alpha2.TLSProtocolType && listener.TLS != nil { + if listener.Protocol == gatev1alpha2.TLSProtocolType && listener.TLS != nil { // TODO support let's encrypt router.TLS = &dynamic.RouterTCPTLSConfig{ - Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == v1alpha2.TLSModePassthrough, + Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1alpha2.TLSModePassthrough, } } @@ -877,7 +877,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouterKey", // Should never happen @@ -902,7 +902,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidBackendRefs", // TODO check the spec if a proper reason is introduced at some point @@ -948,7 +948,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. return conditions } -func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2.Listener, gateway *v1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { +func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener gatev1alpha2.Listener, gateway *gatev1alpha2.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition { if listener.AllowedRoutes == nil { // Should not happen due to validation. return nil @@ -958,7 +958,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouteNamespacesSelector", // TODO should never happen as the selector is validated by Kubernetes @@ -970,10 +970,10 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "InvalidRoutesRef" reason return []metav1.Condition{{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), - Reason: string(v1alpha2.ListenerReasonRefNotPermitted), + Reason: string(gatev1alpha2.ListenerReasonRefNotPermitted), Message: fmt.Sprintf("Cannot fetch TLSRoutes: %v", err), }} } @@ -993,9 +993,9 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if len(hostnames) == 0 && listener.Hostname != nil && *listener.Hostname != "" && len(route.Spec.Hostnames) > 0 { for _, parent := range route.Status.Parents { parent.Conditions = append(parent.Conditions, metav1.Condition{ - Type: string(v1alpha2.GatewayClassConditionStatusAccepted), + Type: string(gatev1alpha2.GatewayClassConditionStatusAccepted), Status: metav1.ConditionFalse, - Reason: string(v1alpha2.ListenerReasonRouteConflict), + Reason: string(gatev1alpha2.ListenerReasonRouteConflict), Message: fmt.Sprintf("No hostname match between listener: %v and route: %v", listener.Hostname, route.Spec.Hostnames), LastTransitionTime: metav1.Now(), }) @@ -1008,7 +1008,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidHostnames", // TODO check the spec if a proper reason is introduced at some point @@ -1022,7 +1022,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. Rule: rule, EntryPoints: []string{ep}, TLS: &dynamic.RouterTCPTLSConfig{ - Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == v1alpha2.TLSModePassthrough, + Passthrough: listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1alpha2.TLSModePassthrough, }, } @@ -1032,7 +1032,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidRouterKey", // Should never happen @@ -1057,7 +1057,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. if err != nil { // update "ResolvedRefs" status true with "DroppedRoutes" reason conditions = append(conditions, metav1.Condition{ - Type: string(v1alpha2.ListenerConditionResolvedRefs), + Type: string(gatev1alpha2.ListenerConditionResolvedRefs), Status: metav1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: "InvalidBackendRefs", // TODO check the spec if a proper reason is introduced at some point @@ -1105,18 +1105,18 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha2. // Because of Kubernetes validation we admit that the given Hostnames are valid. // https://github.com/kubernetes-sigs/gateway-api/blob/ff9883da4cad8554cd300394f725ab3a27502785/apis/v1alpha2/shared_types.go#L252 -func matchingHostnames(listener v1alpha2.Listener, hostnames []v1alpha2.Hostname) []v1alpha2.Hostname { +func matchingHostnames(listener gatev1alpha2.Listener, hostnames []gatev1alpha2.Hostname) []gatev1alpha2.Hostname { if listener.Hostname == nil || *listener.Hostname == "" { return hostnames } if len(hostnames) == 0 { - return []v1alpha2.Hostname{*listener.Hostname} + return []gatev1alpha2.Hostname{*listener.Hostname} } listenerLabels := strings.Split(string(*listener.Hostname), ".") - var matches []v1alpha2.Hostname + var matches []gatev1alpha2.Hostname for _, hostname := range hostnames { if hostname == *listener.Hostname { @@ -1147,9 +1147,9 @@ func matchingHostnames(listener v1alpha2.Listener, hostnames []v1alpha2.Hostname return matches } -func shouldAttach(gateway *v1alpha2.Gateway, listener v1alpha2.Listener, routeNamespace string, routeSpec v1alpha2.CommonRouteSpec) bool { +func shouldAttach(gateway *gatev1alpha2.Gateway, listener gatev1alpha2.Listener, routeNamespace string, routeSpec gatev1alpha2.CommonRouteSpec) bool { for _, parentRef := range routeSpec.ParentRefs { - if parentRef.Group == nil || *parentRef.Group != v1alpha2.GroupName { + if parentRef.Group == nil || *parentRef.Group != gatev1alpha2.GroupName { continue } @@ -1174,19 +1174,19 @@ func shouldAttach(gateway *v1alpha2.Gateway, listener v1alpha2.Listener, routeNa return false } -func getRouteBindingSelectorNamespace(client Client, gatewayNamespace string, routeNamespaces *v1alpha2.RouteNamespaces) ([]string, error) { +func getRouteBindingSelectorNamespace(client Client, gatewayNamespace string, routeNamespaces *gatev1alpha2.RouteNamespaces) ([]string, error) { if routeNamespaces == nil || routeNamespaces.From == nil { return []string{gatewayNamespace}, nil } switch *routeNamespaces.From { - case v1alpha2.NamespacesFromAll: + case gatev1alpha2.NamespacesFromAll: return []string{metav1.NamespaceAll}, nil - case v1alpha2.NamespacesFromSame: + case gatev1alpha2.NamespacesFromSame: return []string{gatewayNamespace}, nil - case v1alpha2.NamespacesFromSelector: + case gatev1alpha2.NamespacesFromSelector: selector, err := metav1.LabelSelectorAsSelector(routeNamespaces.Selector) if err != nil { return nil, fmt.Errorf("malformed selector: %w", err) @@ -1198,7 +1198,7 @@ func getRouteBindingSelectorNamespace(client Client, gatewayNamespace string, ro return nil, fmt.Errorf("unsupported RouteSelectType: %q", *routeNamespaces.From) } -func hostRule(hostnames []v1alpha2.Hostname) (string, error) { +func hostRule(hostnames []gatev1alpha2.Hostname) (string, error) { var rules []string for _, hostname := range hostnames { @@ -1235,9 +1235,9 @@ func hostRule(hostnames []v1alpha2.Hostname) (string, error) { } } -func hostSNIRule(hostnames []v1alpha2.Hostname) (string, error) { +func hostSNIRule(hostnames []gatev1alpha2.Hostname) (string, error) { rules := make([]string, 0, len(hostnames)) - uniqHostnames := map[v1alpha2.Hostname]struct{}{} + uniqHostnames := map[gatev1alpha2.Hostname]struct{}{} for _, hostname := range hostnames { if len(hostname) == 0 { @@ -1272,7 +1272,7 @@ func hostSNIRule(hostnames []v1alpha2.Hostname) (string, error) { return strings.Join(rules, " || "), nil } -func extractRule(routeRule v1alpha2.HTTPRouteRule, hostRule string) (string, error) { +func extractRule(routeRule gatev1alpha2.HTTPRouteRule, hostRule string) (string, error) { var rule string var matchesRules []string @@ -1286,9 +1286,9 @@ func extractRule(routeRule v1alpha2.HTTPRouteRule, hostRule string) (string, err if match.Path != nil && match.Path.Type != nil && match.Path.Value != nil { // TODO handle other path types switch *match.Path.Type { - case v1alpha2.PathMatchExact: + case gatev1alpha2.PathMatchExact: matchRules = append(matchRules, fmt.Sprintf("Path(`%s`)", *match.Path.Value)) - case v1alpha2.PathMatchPathPrefix: + case gatev1alpha2.PathMatchPathPrefix: matchRules = append(matchRules, fmt.Sprintf("PathPrefix(`%s`)", *match.Path.Value)) default: return "", fmt.Errorf("unsupported path match %s", *match.Path.Type) @@ -1329,7 +1329,7 @@ func extractRule(routeRule v1alpha2.HTTPRouteRule, hostRule string) (string, err return rule + "(" + strings.Join(matchesRules, " || ") + ")", nil } -func extractHeaderRules(headers []v1alpha2.HTTPHeaderMatch) ([]string, error) { +func extractHeaderRules(headers []gatev1alpha2.HTTPHeaderMatch) ([]string, error) { var headerRules []string // TODO handle other headers types @@ -1340,7 +1340,7 @@ func extractHeaderRules(headers []v1alpha2.HTTPHeaderMatch) ([]string, error) { } switch *header.Type { - case v1alpha2.HeaderMatchExact: + case gatev1alpha2.HeaderMatchExact: headerRules = append(headerRules, fmt.Sprintf("Headers(`%s`,`%s`)", header.Name, header.Value)) default: return nil, fmt.Errorf("unsupported header match type %s", *header.Type) @@ -1369,7 +1369,7 @@ func makeID(namespace, name string) string { return namespace + "-" + name } -func getTLS(k8sClient Client, secretName v1alpha2.ObjectName, namespace string) (*tls.CertAndStores, error) { +func getTLS(k8sClient Client, secretName gatev1alpha2.ObjectName, namespace string) (*tls.CertAndStores, error) { secret, exists, err := k8sClient.GetSecret(namespace, string(secretName)) if err != nil { return nil, fmt.Errorf("failed to fetch secret %s/%s: %w", namespace, secretName, err) @@ -1443,7 +1443,7 @@ func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) ( } // loadServices is generating a WRR service, even when there is only one target. -func loadServices(client Client, namespace string, backendRefs []v1alpha2.HTTPBackendRef) (*dynamic.Service, map[string]*dynamic.Service, error) { +func loadServices(client Client, namespace string, backendRefs []gatev1alpha2.HTTPBackendRef) (*dynamic.Service, map[string]*dynamic.Service, error) { services := map[string]*dynamic.Service{} wrrSvc := &dynamic.Service{ @@ -1566,7 +1566,7 @@ func loadServices(client Client, namespace string, backendRefs []v1alpha2.HTTPBa } // loadTCPServices is generating a WRR service, even when there is only one target. -func loadTCPServices(client Client, namespace string, backendRefs []v1alpha2.BackendRef) (*dynamic.TCPService, map[string]*dynamic.TCPService, error) { +func loadTCPServices(client Client, namespace string, backendRefs []gatev1alpha2.BackendRef) (*dynamic.TCPService, map[string]*dynamic.TCPService, error) { services := map[string]*dynamic.TCPService{} wrrSvc := &dynamic.TCPService{ @@ -1684,16 +1684,16 @@ func loadTCPServices(client Client, namespace string, backendRefs []v1alpha2.Bac return wrrSvc, services, nil } -func loadMiddlewares(listener v1alpha2.Listener, prefix string, filters []v1alpha2.HTTPRouteFilter) (map[string]*dynamic.Middleware, error) { +func loadMiddlewares(listener gatev1alpha2.Listener, prefix string, filters []gatev1alpha2.HTTPRouteFilter) (map[string]*dynamic.Middleware, error) { middlewares := make(map[string]*dynamic.Middleware) // The spec allows for an empty string in which case we should use the // scheme of the request which in this case is the listener scheme. var listenerScheme string switch listener.Protocol { - case v1alpha2.HTTPProtocolType: + case gatev1alpha2.HTTPProtocolType: listenerScheme = "http" - case v1alpha2.HTTPSProtocolType: + case gatev1alpha2.HTTPSProtocolType: listenerScheme = "https" default: return nil, fmt.Errorf("invalid listener protocol %s", listener.Protocol) @@ -1702,7 +1702,7 @@ func loadMiddlewares(listener v1alpha2.Listener, prefix string, filters []v1alph for i, filter := range filters { var middleware *dynamic.Middleware switch filter.Type { - case v1alpha2.HTTPRouteFilterRequestRedirect: + case gatev1alpha2.HTTPRouteFilterRequestRedirect: var err error middleware, err = createRedirectRegexMiddleware(listenerScheme, filter.RequestRedirect) if err != nil { @@ -1724,7 +1724,7 @@ func loadMiddlewares(listener v1alpha2.Listener, prefix string, filters []v1alph return middlewares, nil } -func createRedirectRegexMiddleware(scheme string, filter *v1alpha2.HTTPRequestRedirectFilter) (*dynamic.Middleware, error) { +func createRedirectRegexMiddleware(scheme string, filter *gatev1alpha2.HTTPRequestRedirectFilter) (*dynamic.Middleware, error) { // Use the HTTPRequestRedirectFilter scheme if defined. filterScheme := scheme if filter.Scheme != nil { @@ -1802,7 +1802,7 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *s return eventsChanBuffered } -func isTraefikService(ref v1alpha2.BackendRef) bool { +func isTraefikService(ref gatev1alpha2.BackendRef) bool { if ref.Kind == nil || ref.Group == nil { return false } @@ -1810,13 +1810,13 @@ func isTraefikService(ref v1alpha2.BackendRef) bool { return *ref.Group == traefikv1alpha1.GroupName && *ref.Kind == kindTraefikService } -func isInternalService(ref v1alpha2.BackendRef) bool { +func isInternalService(ref gatev1alpha2.BackendRef) bool { return isTraefikService(ref) && strings.HasSuffix(string(ref.Name), "@internal") } // makeListenerKey joins protocol, hostname, and port of a listener into a string key. -func makeListenerKey(l v1alpha2.Listener) string { - var hostname v1alpha2.Hostname +func makeListenerKey(l gatev1alpha2.Listener) string { + var hostname gatev1alpha2.Hostname if l.Hostname != nil { hostname = *l.Hostname } diff --git a/pkg/provider/kubernetes/gateway/kubernetes_test.go b/pkg/provider/kubernetes/gateway/kubernetes_test.go index f7e2acafe..e3783796e 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes_test.go +++ b/pkg/provider/kubernetes/gateway/kubernetes_test.go @@ -13,7 +13,7 @@ import ( "github.com/traefik/traefik/v3/pkg/tls" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" - "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) var _ provider.Provider = (*Provider)(nil) @@ -4555,7 +4555,7 @@ func TestLoadMixedRoutes(t *testing.T) { func Test_hostRule(t *testing.T) { testCases := []struct { desc string - hostnames []v1alpha2.Hostname + hostnames []gatev1alpha2.Hostname expectedRule string expectErr bool }{ @@ -4565,14 +4565,14 @@ func Test_hostRule(t *testing.T) { }, { desc: "One Host", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "Foo", }, expectedRule: "Host(`Foo`)", }, { desc: "Multiple Hosts", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "Foo", "Bar", "Bir", @@ -4581,7 +4581,7 @@ func Test_hostRule(t *testing.T) { }, { desc: "Multiple Hosts with empty one", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "Foo", "", "Bir", @@ -4590,7 +4590,7 @@ func Test_hostRule(t *testing.T) { }, { desc: "Multiple empty hosts", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "", "", "", @@ -4599,7 +4599,7 @@ func Test_hostRule(t *testing.T) { }, { desc: "Several Host and wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "*.bar.foo", "bar.foo", "foo.foo", @@ -4608,21 +4608,21 @@ func Test_hostRule(t *testing.T) { }, { desc: "Host with wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "*.bar.foo", }, expectedRule: "HostRegexp(`^[a-zA-Z0-9-]+\\.bar\\.foo$`)", }, { desc: "Alone wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "*", "*.foo.foo", }, }, { desc: "Multiple alone Wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "foo.foo", "*.*", }, @@ -4630,7 +4630,7 @@ func Test_hostRule(t *testing.T) { }, { desc: "Multiple Wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "foo.foo", "*.toto.*.bar.foo", }, @@ -4638,7 +4638,7 @@ func Test_hostRule(t *testing.T) { }, { desc: "Multiple subdomain with misplaced wildcard", - hostnames: []v1alpha2.Hostname{ + hostnames: []gatev1alpha2.Hostname{ "foo.foo", "toto.*.bar.foo", }, @@ -4663,7 +4663,7 @@ func Test_hostRule(t *testing.T) { func Test_extractRule(t *testing.T) { testCases := []struct { desc string - routeRule v1alpha2.HTTPRouteRule + routeRule gatev1alpha2.HTTPRouteRule hostRule string expectedRule string expectedError bool @@ -4679,8 +4679,8 @@ func Test_extractRule(t *testing.T) { }, { desc: "One HTTPRouteMatch with nil HTTPHeaderMatch", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ {Headers: nil}, }, }, @@ -4688,10 +4688,10 @@ func Test_extractRule(t *testing.T) { }, { desc: "One HTTPRouteMatch with nil HTTPHeaderMatch Type", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Headers: []v1alpha2.HTTPHeaderMatch{ + Headers: []gatev1alpha2.HTTPHeaderMatch{ {Type: nil, Name: "foo", Value: "bar"}, }, }, @@ -4701,8 +4701,8 @@ func Test_extractRule(t *testing.T) { }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ {Path: nil}, }, }, @@ -4710,10 +4710,10 @@ func Test_extractRule(t *testing.T) { }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch Type", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ + Path: &gatev1alpha2.HTTPPathMatch{ Type: nil, Value: pointer.String("/foo/"), }, @@ -4724,11 +4724,11 @@ func Test_extractRule(t *testing.T) { }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch Values", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: nil, }, }, @@ -4738,11 +4738,11 @@ func Test_extractRule(t *testing.T) { }, { desc: "One Path in matches", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, }, @@ -4752,16 +4752,16 @@ func Test_extractRule(t *testing.T) { }, { desc: "One Path in matches and another unknown", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, }, { - Path: &v1alpha2.HTTPPathMatch{ + Path: &gatev1alpha2.HTTPPathMatch{ Type: pathMatchTypePtr("unknown"), Value: pointer.String("/foo/"), }, @@ -4772,11 +4772,11 @@ func Test_extractRule(t *testing.T) { }, { desc: "One Path in matches and another empty", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, }, @@ -4787,18 +4787,18 @@ func Test_extractRule(t *testing.T) { }, { desc: "Path OR Header rules", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, }, { - Headers: []v1alpha2.HTTPHeaderMatch{ + Headers: []gatev1alpha2.HTTPHeaderMatch{ { - Type: headerMatchTypePtr(v1alpha2.HeaderMatchExact), + Type: headerMatchTypePtr(gatev1alpha2.HeaderMatchExact), Name: "my-header", Value: "foo", }, @@ -4810,16 +4810,16 @@ func Test_extractRule(t *testing.T) { }, { desc: "Path && Header rules", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, - Headers: []v1alpha2.HTTPHeaderMatch{ + Headers: []gatev1alpha2.HTTPHeaderMatch{ { - Type: headerMatchTypePtr(v1alpha2.HeaderMatchExact), + Type: headerMatchTypePtr(gatev1alpha2.HeaderMatchExact), Name: "my-header", Value: "foo", }, @@ -4832,16 +4832,16 @@ func Test_extractRule(t *testing.T) { { desc: "Host && Path && Header rules", hostRule: "Host(`foo.com`)", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, - Headers: []v1alpha2.HTTPHeaderMatch{ + Headers: []gatev1alpha2.HTTPHeaderMatch{ { - Type: headerMatchTypePtr(v1alpha2.HeaderMatchExact), + Type: headerMatchTypePtr(gatev1alpha2.HeaderMatchExact), Name: "my-header", Value: "foo", }, @@ -4854,18 +4854,18 @@ func Test_extractRule(t *testing.T) { { desc: "Host && (Path || Header) rules", hostRule: "Host(`foo.com`)", - routeRule: v1alpha2.HTTPRouteRule{ - Matches: []v1alpha2.HTTPRouteMatch{ + routeRule: gatev1alpha2.HTTPRouteRule{ + Matches: []gatev1alpha2.HTTPRouteMatch{ { - Path: &v1alpha2.HTTPPathMatch{ - Type: pathMatchTypePtr(v1alpha2.PathMatchExact), + Path: &gatev1alpha2.HTTPPathMatch{ + Type: pathMatchTypePtr(gatev1alpha2.PathMatchExact), Value: pointer.String("/foo/"), }, }, { - Headers: []v1alpha2.HTTPHeaderMatch{ + Headers: []gatev1alpha2.HTTPHeaderMatch{ { - Type: headerMatchTypePtr(v1alpha2.HeaderMatchExact), + Type: headerMatchTypePtr(gatev1alpha2.HeaderMatchExact), Name: "my-header", Value: "foo", }, @@ -4897,7 +4897,7 @@ func Test_extractRule(t *testing.T) { func Test_hostSNIRule(t *testing.T) { testCases := []struct { desc string - hostnames []v1alpha2.Hostname + hostnames []gatev1alpha2.Hostname expectedRule string expectError bool }{ @@ -4907,47 +4907,47 @@ func Test_hostSNIRule(t *testing.T) { }, { desc: "Empty hostname", - hostnames: []v1alpha2.Hostname{""}, + hostnames: []gatev1alpha2.Hostname{""}, expectedRule: "HostSNI(`*`)", }, { desc: "Unsupported wildcard", - hostnames: []v1alpha2.Hostname{"*"}, + hostnames: []gatev1alpha2.Hostname{"*"}, expectError: true, }, { desc: "Supported wildcard", - hostnames: []v1alpha2.Hostname{"*.foo"}, + hostnames: []gatev1alpha2.Hostname{"*.foo"}, expectedRule: "HostSNIRegexp(`^[a-zA-Z0-9-]+\\.foo$`)", }, { desc: "Multiple malformed wildcard", - hostnames: []v1alpha2.Hostname{"*.foo.*"}, + hostnames: []gatev1alpha2.Hostname{"*.foo.*"}, expectError: true, }, { desc: "Some empty hostnames", - hostnames: []v1alpha2.Hostname{"foo", "", "bar"}, + hostnames: []gatev1alpha2.Hostname{"foo", "", "bar"}, expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", }, { desc: "Valid hostname", - hostnames: []v1alpha2.Hostname{"foo"}, + hostnames: []gatev1alpha2.Hostname{"foo"}, expectedRule: "HostSNI(`foo`)", }, { desc: "Multiple valid hostnames", - hostnames: []v1alpha2.Hostname{"foo", "bar"}, + hostnames: []gatev1alpha2.Hostname{"foo", "bar"}, expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", }, { desc: "Multiple valid hostnames with wildcard", - hostnames: []v1alpha2.Hostname{"bar.foo", "foo.foo", "*.foo"}, + hostnames: []gatev1alpha2.Hostname{"bar.foo", "foo.foo", "*.foo"}, expectedRule: "HostSNI(`bar.foo`) || HostSNI(`foo.foo`) || HostSNIRegexp(`^[a-zA-Z0-9-]+\\.foo$`)", }, { desc: "Multiple overlapping hostnames", - hostnames: []v1alpha2.Hostname{"foo", "bar", "foo", "baz"}, + hostnames: []gatev1alpha2.Hostname{"foo", "bar", "foo", "baz"}, expectedRule: "HostSNI(`foo`) || HostSNI(`bar`) || HostSNI(`baz`)", }, } @@ -4972,49 +4972,49 @@ func Test_hostSNIRule(t *testing.T) { func Test_shouldAttach(t *testing.T) { testCases := []struct { desc string - gateway *v1alpha2.Gateway - listener v1alpha2.Listener + gateway *gatev1alpha2.Gateway + listener gatev1alpha2.Listener routeNamespace string - routeSpec v1alpha2.CommonRouteSpec + routeSpec gatev1alpha2.CommonRouteSpec expectedAttach bool }{ { desc: "No ParentRefs", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ + routeSpec: gatev1alpha2.CommonRouteSpec{ ParentRefs: nil, }, expectedAttach: false, }, { desc: "Unsupported Kind", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", Namespace: namespacePtr("default"), Kind: kindPtr("Foo"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5022,18 +5022,18 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Unsupported Group", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", @@ -5047,23 +5047,23 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Kind is nil", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", Namespace: namespacePtr("default"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5071,18 +5071,18 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Group is nil", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", @@ -5095,23 +5095,23 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "SectionName does not match a listener desc", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", Namespace: namespacePtr("default"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), Kind: kindPtr("Gateway"), }, }, @@ -5120,23 +5120,23 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Namespace does not match the Gateway namespace", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", Namespace: namespacePtr("bar"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), Kind: kindPtr("Gateway"), }, }, @@ -5145,22 +5145,22 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Route namespace does not match the Gateway namespace", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "bar", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), Kind: kindPtr("Gateway"), }, }, @@ -5169,24 +5169,24 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Unsupported Kind", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("bar"), Name: "gateway", Namespace: namespacePtr("default"), Kind: kindPtr("Gateway"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5194,23 +5194,23 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Route namespace matches the Gateway namespace", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "default", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("foo"), Name: "gateway", Kind: kindPtr("Gateway"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5218,24 +5218,24 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Namespace matches the Gateway namespace", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "bar", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { SectionName: sectionNamePtr("foo"), Name: "gateway", Namespace: namespacePtr("default"), Kind: kindPtr("Gateway"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5243,29 +5243,29 @@ func Test_shouldAttach(t *testing.T) { }, { desc: "Only one ParentRef matches the Gateway", - gateway: &v1alpha2.Gateway{ + gateway: &gatev1alpha2.Gateway{ ObjectMeta: metav1.ObjectMeta{ Name: "gateway", Namespace: "default", }, }, - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Name: "foo", }, routeNamespace: "bar", - routeSpec: v1alpha2.CommonRouteSpec{ - ParentRefs: []v1alpha2.ParentRef{ + routeSpec: gatev1alpha2.CommonRouteSpec{ + ParentRefs: []gatev1alpha2.ParentRef{ { Name: "gateway2", Namespace: namespacePtr("default"), Kind: kindPtr("Gateway"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, { Name: "gateway", Namespace: namespacePtr("default"), Kind: kindPtr("Gateway"), - Group: groupPtr(v1alpha2.GroupName), + Group: groupPtr(gatev1alpha2.GroupName), }, }, }, @@ -5287,93 +5287,93 @@ func Test_shouldAttach(t *testing.T) { func Test_matchingHostnames(t *testing.T) { testCases := []struct { desc string - listener v1alpha2.Listener - hostnames []v1alpha2.Hostname - want []v1alpha2.Hostname + listener gatev1alpha2.Listener + hostnames []gatev1alpha2.Hostname + want []gatev1alpha2.Hostname }{ { desc: "Empty", }, { desc: "Only listener hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("foo.com"), }, - want: []v1alpha2.Hostname{"foo.com"}, + want: []gatev1alpha2.Hostname{"foo.com"}, }, { desc: "Only Route hostname", - hostnames: []v1alpha2.Hostname{"foo.com"}, - want: []v1alpha2.Hostname{"foo.com"}, + hostnames: []gatev1alpha2.Hostname{"foo.com"}, + want: []gatev1alpha2.Hostname{"foo.com"}, }, { desc: "Matching hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("foo.com"), }, - hostnames: []v1alpha2.Hostname{"foo.com"}, - want: []v1alpha2.Hostname{"foo.com"}, + hostnames: []gatev1alpha2.Hostname{"foo.com"}, + want: []gatev1alpha2.Hostname{"foo.com"}, }, { desc: "Matching hostname with wildcard", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.foo.com"), }, - hostnames: []v1alpha2.Hostname{"*.foo.com"}, - want: []v1alpha2.Hostname{"*.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"*.foo.com"}, + want: []gatev1alpha2.Hostname{"*.foo.com"}, }, { desc: "Matching subdomain with listener wildcard", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.foo.com"), }, - hostnames: []v1alpha2.Hostname{"bar.foo.com"}, - want: []v1alpha2.Hostname{"bar.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"bar.foo.com"}, + want: []gatev1alpha2.Hostname{"bar.foo.com"}, }, { desc: "Matching subdomain with route hostname wildcard", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("bar.foo.com"), }, - hostnames: []v1alpha2.Hostname{"*.foo.com"}, - want: []v1alpha2.Hostname{"bar.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"*.foo.com"}, + want: []gatev1alpha2.Hostname{"bar.foo.com"}, }, { desc: "Non matching root domain with listener wildcard", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.foo.com"), }, - hostnames: []v1alpha2.Hostname{"foo.com"}, + hostnames: []gatev1alpha2.Hostname{"foo.com"}, }, { desc: "Non matching root domain with route hostname wildcard", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("foo.com"), }, - hostnames: []v1alpha2.Hostname{"*.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"*.foo.com"}, }, { desc: "Multiple route hostnames with one matching route hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.foo.com"), }, - hostnames: []v1alpha2.Hostname{"bar.com", "test.foo.com", "test.buz.com"}, - want: []v1alpha2.Hostname{"test.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"bar.com", "test.foo.com", "test.buz.com"}, + want: []gatev1alpha2.Hostname{"test.foo.com"}, }, { desc: "Multiple route hostnames with non matching route hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.fuz.com"), }, - hostnames: []v1alpha2.Hostname{"bar.com", "test.foo.com", "test.buz.com"}, + hostnames: []gatev1alpha2.Hostname{"bar.com", "test.foo.com", "test.buz.com"}, }, { desc: "Multiple route hostnames with multiple matching route hostnames", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Hostname: hostnamePtr("*.foo.com"), }, - hostnames: []v1alpha2.Hostname{"toto.foo.com", "test.foo.com", "test.buz.com"}, - want: []v1alpha2.Hostname{"toto.foo.com", "test.foo.com"}, + hostnames: []gatev1alpha2.Hostname{"toto.foo.com", "test.foo.com", "test.buz.com"}, + want: []gatev1alpha2.Hostname{"toto.foo.com", "test.foo.com"}, }, } @@ -5391,9 +5391,9 @@ func Test_matchingHostnames(t *testing.T) { func Test_getAllowedRoutes(t *testing.T) { testCases := []struct { desc string - listener v1alpha2.Listener - supportedRouteKinds []v1alpha2.RouteGroupKind - wantKinds []v1alpha2.RouteGroupKind + listener gatev1alpha2.Listener + supportedRouteKinds []gatev1alpha2.RouteGroupKind + wantKinds []gatev1alpha2.RouteGroupKind wantErr bool }{ { @@ -5401,90 +5401,90 @@ func Test_getAllowedRoutes(t *testing.T) { }, { desc: "Empty AllowedRoutes", - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, - wantKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + wantKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, }, { desc: "AllowedRoutes with unsupported Group", - listener: v1alpha2.Listener{ - AllowedRoutes: &v1alpha2.AllowedRoutes{ - Kinds: []v1alpha2.RouteGroupKind{{ + listener: gatev1alpha2.Listener{ + AllowedRoutes: &gatev1alpha2.AllowedRoutes{ + Kinds: []gatev1alpha2.RouteGroupKind{{ Kind: kindTLSRoute, Group: groupPtr("foo"), }}, }, }, - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, wantErr: true, }, { desc: "AllowedRoutes with nil Group", - listener: v1alpha2.Listener{ - AllowedRoutes: &v1alpha2.AllowedRoutes{ - Kinds: []v1alpha2.RouteGroupKind{{ + listener: gatev1alpha2.Listener{ + AllowedRoutes: &gatev1alpha2.AllowedRoutes{ + Kinds: []gatev1alpha2.RouteGroupKind{{ Kind: kindTLSRoute, Group: nil, }}, }, }, - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, wantErr: true, }, { desc: "AllowedRoutes with unsupported Kind", - listener: v1alpha2.Listener{ - AllowedRoutes: &v1alpha2.AllowedRoutes{ - Kinds: []v1alpha2.RouteGroupKind{{ - Kind: "foo", Group: groupPtr(v1alpha2.GroupName), + listener: gatev1alpha2.Listener{ + AllowedRoutes: &gatev1alpha2.AllowedRoutes{ + Kinds: []gatev1alpha2.RouteGroupKind{{ + Kind: "foo", Group: groupPtr(gatev1alpha2.GroupName), }}, }, }, - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, wantErr: true, }, { desc: "Supported AllowedRoutes", - listener: v1alpha2.Listener{ - AllowedRoutes: &v1alpha2.AllowedRoutes{ - Kinds: []v1alpha2.RouteGroupKind{{ - Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName), + listener: gatev1alpha2.Listener{ + AllowedRoutes: &gatev1alpha2.AllowedRoutes{ + Kinds: []gatev1alpha2.RouteGroupKind{{ + Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName), }}, }, }, - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, - wantKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, + wantKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, }, { desc: "Supported AllowedRoutes with duplicates", - listener: v1alpha2.Listener{ - AllowedRoutes: &v1alpha2.AllowedRoutes{ - Kinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, - {Kind: kindTCPRoute, Group: groupPtr(v1alpha2.GroupName)}, - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, - {Kind: kindTCPRoute, Group: groupPtr(v1alpha2.GroupName)}, + listener: gatev1alpha2.Listener{ + AllowedRoutes: &gatev1alpha2.AllowedRoutes{ + Kinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, + {Kind: kindTCPRoute, Group: groupPtr(gatev1alpha2.GroupName)}, + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, + {Kind: kindTCPRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, }, }, - supportedRouteKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, - {Kind: kindTCPRoute, Group: groupPtr(v1alpha2.GroupName)}, + supportedRouteKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, + {Kind: kindTCPRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, - wantKinds: []v1alpha2.RouteGroupKind{ - {Kind: kindTLSRoute, Group: groupPtr(v1alpha2.GroupName)}, - {Kind: kindTCPRoute, Group: groupPtr(v1alpha2.GroupName)}, + wantKinds: []gatev1alpha2.RouteGroupKind{ + {Kind: kindTLSRoute, Group: groupPtr(gatev1alpha2.GroupName)}, + {Kind: kindTCPRoute, Group: groupPtr(gatev1alpha2.GroupName)}, }, }, } @@ -5509,7 +5509,7 @@ func Test_getAllowedRoutes(t *testing.T) { func Test_makeListenerKey(t *testing.T) { testCases := []struct { desc string - listener v1alpha2.Listener + listener gatev1alpha2.Listener expectedKey string }{ { @@ -5518,18 +5518,18 @@ func Test_makeListenerKey(t *testing.T) { }, { desc: "listener with port, protocol and hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Port: 443, - Protocol: v1alpha2.HTTPSProtocolType, + Protocol: gatev1alpha2.HTTPSProtocolType, Hostname: hostnamePtr("www.example.com"), }, expectedKey: "HTTPS|www.example.com|443", }, { desc: "listener with port, protocol and nil hostname", - listener: v1alpha2.Listener{ + listener: gatev1alpha2.Listener{ Port: 443, - Protocol: v1alpha2.HTTPSProtocolType, + Protocol: gatev1alpha2.HTTPSProtocolType, }, expectedKey: "HTTPS||443", }, @@ -5545,26 +5545,26 @@ func Test_makeListenerKey(t *testing.T) { } } -func hostnamePtr(hostname v1alpha2.Hostname) *v1alpha2.Hostname { +func hostnamePtr(hostname gatev1alpha2.Hostname) *gatev1alpha2.Hostname { return &hostname } -func groupPtr(group v1alpha2.Group) *v1alpha2.Group { +func groupPtr(group gatev1alpha2.Group) *gatev1alpha2.Group { return &group } -func sectionNamePtr(sectionName v1alpha2.SectionName) *v1alpha2.SectionName { +func sectionNamePtr(sectionName gatev1alpha2.SectionName) *gatev1alpha2.SectionName { return §ionName } -func namespacePtr(namespace v1alpha2.Namespace) *v1alpha2.Namespace { +func namespacePtr(namespace gatev1alpha2.Namespace) *gatev1alpha2.Namespace { return &namespace } -func kindPtr(kind v1alpha2.Kind) *v1alpha2.Kind { +func kindPtr(kind gatev1alpha2.Kind) *gatev1alpha2.Kind { return &kind } -func pathMatchTypePtr(p v1alpha2.PathMatchType) *v1alpha2.PathMatchType { return &p } +func pathMatchTypePtr(p gatev1alpha2.PathMatchType) *gatev1alpha2.PathMatchType { return &p } -func headerMatchTypePtr(h v1alpha2.HeaderMatchType) *v1alpha2.HeaderMatchType { return &h } +func headerMatchTypePtr(h gatev1alpha2.HeaderMatchType) *gatev1alpha2.HeaderMatchType { return &h } diff --git a/pkg/provider/kubernetes/ingress/builder_ingress_test.go b/pkg/provider/kubernetes/ingress/builder_ingress_test.go index 56ba2d286..bd9bfb9a3 100644 --- a/pkg/provider/kubernetes/ingress/builder_ingress_test.go +++ b/pkg/provider/kubernetes/ingress/builder_ingress_test.go @@ -1,9 +1,9 @@ package ingress -import networkingv1 "k8s.io/api/networking/v1" +import netv1 "k8s.io/api/networking/v1" -func buildIngress(opts ...func(*networkingv1.Ingress)) *networkingv1.Ingress { - i := &networkingv1.Ingress{} +func buildIngress(opts ...func(*netv1.Ingress)) *netv1.Ingress { + i := &netv1.Ingress{} i.Kind = "Ingress" for _, opt := range opts { opt(i) @@ -11,15 +11,15 @@ func buildIngress(opts ...func(*networkingv1.Ingress)) *networkingv1.Ingress { return i } -func iNamespace(value string) func(*networkingv1.Ingress) { - return func(i *networkingv1.Ingress) { +func iNamespace(value string) func(*netv1.Ingress) { + return func(i *netv1.Ingress) { i.Namespace = value } } -func iRules(opts ...func(*networkingv1.IngressSpec)) func(*networkingv1.Ingress) { - return func(i *networkingv1.Ingress) { - s := &networkingv1.IngressSpec{} +func iRules(opts ...func(*netv1.IngressSpec)) func(*netv1.Ingress) { + return func(i *netv1.Ingress) { + s := &netv1.IngressSpec{} for _, opt := range opts { opt(s) } @@ -27,9 +27,9 @@ func iRules(opts ...func(*networkingv1.IngressSpec)) func(*networkingv1.Ingress) } } -func iRule(opts ...func(*networkingv1.IngressRule)) func(*networkingv1.IngressSpec) { - return func(spec *networkingv1.IngressSpec) { - r := &networkingv1.IngressRule{} +func iRule(opts ...func(*netv1.IngressRule)) func(*netv1.IngressSpec) { + return func(spec *netv1.IngressSpec) { + r := &netv1.IngressRule{} for _, opt := range opts { opt(r) } @@ -37,24 +37,24 @@ func iRule(opts ...func(*networkingv1.IngressRule)) func(*networkingv1.IngressSp } } -func iHost(name string) func(*networkingv1.IngressRule) { - return func(rule *networkingv1.IngressRule) { +func iHost(name string) func(*netv1.IngressRule) { + return func(rule *netv1.IngressRule) { rule.Host = name } } -func iTLSes(opts ...func(*networkingv1.IngressTLS)) func(*networkingv1.Ingress) { - return func(i *networkingv1.Ingress) { +func iTLSes(opts ...func(*netv1.IngressTLS)) func(*netv1.Ingress) { + return func(i *netv1.Ingress) { for _, opt := range opts { - iTLS := networkingv1.IngressTLS{} + iTLS := netv1.IngressTLS{} opt(&iTLS) i.Spec.TLS = append(i.Spec.TLS, iTLS) } } } -func iTLS(secret string, hosts ...string) func(*networkingv1.IngressTLS) { - return func(i *networkingv1.IngressTLS) { +func iTLS(secret string, hosts ...string) func(*netv1.IngressTLS) { + return func(i *netv1.IngressTLS) { i.SecretName = secret i.Hosts = hosts } diff --git a/pkg/provider/kubernetes/ingress/client.go b/pkg/provider/kubernetes/ingress/client.go index 11854c12b..b0388e1fa 100644 --- a/pkg/provider/kubernetes/ingress/client.go +++ b/pkg/provider/kubernetes/ingress/client.go @@ -14,14 +14,14 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" traefikversion "github.com/traefik/traefik/v3/pkg/version" corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - networkingv1beta1 "k8s.io/api/networking/v1beta1" - kubeerror "k8s.io/apimachinery/pkg/api/errors" + netv1 "k8s.io/api/networking/v1" + netv1beta1 "k8s.io/api/networking/v1beta1" + kerror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" + kinformers "k8s.io/client-go/informers" + kclientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) @@ -31,30 +31,26 @@ const ( defaultTimeout = 5 * time.Second ) -type marshaler interface { - Marshal() ([]byte, error) -} - // Client is a client for the Provider master. // WatchAll starts the watch of the Provider resources and updates the stores. // The stores can then be accessed via the Get* functions. type Client interface { WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) - GetIngresses() []*networkingv1.Ingress - GetIngressClasses() ([]*networkingv1.IngressClass, error) + GetIngresses() []*netv1.Ingress + GetIngressClasses() ([]*netv1.IngressClass, error) GetService(namespace, name string) (*corev1.Service, bool, error) GetSecret(namespace, name string) (*corev1.Secret, bool, error) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) - UpdateIngressStatus(ing *networkingv1.Ingress, ingStatus []corev1.LoadBalancerIngress) error + UpdateIngressStatus(ing *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error GetServerVersion() *version.Version } type clientWrapper struct { - clientset kubernetes.Interface - factoriesKube map[string]informers.SharedInformerFactory - factoriesSecret map[string]informers.SharedInformerFactory - factoriesIngress map[string]informers.SharedInformerFactory - clusterFactory informers.SharedInformerFactory + clientset kclientset.Interface + factoriesKube map[string]kinformers.SharedInformerFactory + factoriesSecret map[string]kinformers.SharedInformerFactory + factoriesIngress map[string]kinformers.SharedInformerFactory + clusterFactory kinformers.SharedInformerFactory ingressLabelSelector string isNamespaceAll bool disableIngressClassInformer bool @@ -118,7 +114,7 @@ func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { runtime.GOARCH, ) - clientset, err := kubernetes.NewForConfig(c) + clientset, err := kclientset.NewForConfig(c) if err != nil { return nil, err } @@ -126,12 +122,12 @@ func createClientFromConfig(c *rest.Config) (*clientWrapper, error) { return newClientImpl(clientset), nil } -func newClientImpl(clientset kubernetes.Interface) *clientWrapper { +func newClientImpl(clientset kclientset.Interface) *clientWrapper { return &clientWrapper{ clientset: clientset, - factoriesSecret: make(map[string]informers.SharedInformerFactory), - factoriesIngress: make(map[string]informers.SharedInformerFactory), - factoriesKube: make(map[string]informers.SharedInformerFactory), + factoriesSecret: make(map[string]kinformers.SharedInformerFactory), + factoriesIngress: make(map[string]kinformers.SharedInformerFactory), + factoriesKube: make(map[string]kinformers.SharedInformerFactory), } } @@ -169,23 +165,38 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< } for _, ns := range namespaces { - factoryIngress := informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, informers.WithNamespace(ns), informers.WithTweakListOptions(matchesLabelSelector)) + factoryIngress := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(matchesLabelSelector)) if supportsNetworkingV1Ingress(serverVersion) { - factoryIngress.Networking().V1().Ingresses().Informer().AddEventHandler(eventHandler) + _, err = factoryIngress.Networking().V1().Ingresses().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } } else { - factoryIngress.Networking().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler) + _, err = factoryIngress.Networking().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } } c.factoriesIngress[ns] = factoryIngress - factoryKube := informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, informers.WithNamespace(ns)) - factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) - factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns)) + _, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } + _, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } c.factoriesKube[ns] = factoryKube - factorySecret := informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, informers.WithNamespace(ns), informers.WithTweakListOptions(notOwnedByHelm)) - factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm)) + _, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } c.factoriesSecret[ns] = factorySecret } @@ -216,12 +227,18 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< } if !c.disableIngressClassInformer && supportsIngressClass(serverVersion) { - c.clusterFactory = informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod) + c.clusterFactory = kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod) if supportsNetworkingV1Ingress(serverVersion) { - c.clusterFactory.Networking().V1().IngressClasses().Informer().AddEventHandler(eventHandler) + _, err = c.clusterFactory.Networking().V1().IngressClasses().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } } else { - c.clusterFactory.Networking().V1beta1().IngressClasses().Informer().AddEventHandler(eventHandler) + _, err = c.clusterFactory.Networking().V1beta1().IngressClasses().Informer().AddEventHandler(eventHandler) + if err != nil { + return nil, err + } } c.clusterFactory.Start(stopCh) @@ -237,8 +254,8 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (< } // GetIngresses returns all Ingresses for observed namespaces in the cluster. -func (c *clientWrapper) GetIngresses() []*networkingv1.Ingress { - var results []*networkingv1.Ingress +func (c *clientWrapper) GetIngresses() []*netv1.Ingress { + var results []*netv1.Ingress isNetworkingV1Supported := supportsNetworkingV1Ingress(c.serverVersion) @@ -263,7 +280,7 @@ func (c *clientWrapper) GetIngresses() []*networkingv1.Ingress { } for _, ing := range list { - n, err := toNetworkingV1(ing) + n, err := convert[netv1.Ingress](ing) if err != nil { log.Error().Err(err).Msgf("Failed to convert ingress %s from networking/v1beta1 to networking/v1", ns) continue @@ -277,39 +294,9 @@ func (c *clientWrapper) GetIngresses() []*networkingv1.Ingress { return results } -func toNetworkingV1(ing marshaler) (*networkingv1.Ingress, error) { - data, err := ing.Marshal() - if err != nil { - return nil, err - } - - ni := &networkingv1.Ingress{} - err = ni.Unmarshal(data) - if err != nil { - return nil, err - } - - return ni, nil -} - -func toNetworkingV1IngressClass(ing marshaler) (*networkingv1.IngressClass, error) { - data, err := ing.Marshal() - if err != nil { - return nil, err - } - - ni := &networkingv1.IngressClass{} - err = ni.Unmarshal(data) - if err != nil { - return nil, err - } - - return ni, nil -} - -func addServiceFromV1Beta1(ing *networkingv1.Ingress, old networkingv1beta1.Ingress) { +func addServiceFromV1Beta1(ing *netv1.Ingress, old netv1beta1.Ingress) { if old.Spec.Backend != nil { - port := networkingv1.ServiceBackendPort{} + port := netv1.ServiceBackendPort{} if old.Spec.Backend.ServicePort.Type == intstr.Int { port.Number = old.Spec.Backend.ServicePort.IntVal } else { @@ -317,8 +304,8 @@ func addServiceFromV1Beta1(ing *networkingv1.Ingress, old networkingv1beta1.Ingr } if old.Spec.Backend.ServiceName != "" { - ing.Spec.DefaultBackend = &networkingv1.IngressBackend{ - Service: &networkingv1.IngressServiceBackend{ + ing.Spec.DefaultBackend = &netv1.IngressBackend{ + Service: &netv1.IngressServiceBackend{ Name: old.Spec.Backend.ServiceName, Port: port, }, @@ -334,14 +321,14 @@ func addServiceFromV1Beta1(ing *networkingv1.Ingress, old networkingv1beta1.Ingr if path.Backend.Service == nil { oldBackend := old.Spec.Rules[rc].HTTP.Paths[pc].Backend - port := networkingv1.ServiceBackendPort{} + port := netv1.ServiceBackendPort{} if oldBackend.ServicePort.Type == intstr.Int { port.Number = oldBackend.ServicePort.IntVal } else { port.Name = oldBackend.ServicePort.StrVal } - svc := networkingv1.IngressServiceBackend{ + svc := netv1.IngressServiceBackend{ Name: oldBackend.ServiceName, Port: port, } @@ -353,7 +340,7 @@ func addServiceFromV1Beta1(ing *networkingv1.Ingress, old networkingv1beta1.Ingr } // UpdateIngressStatus updates an Ingress with a provided status. -func (c *clientWrapper) UpdateIngressStatus(src *networkingv1.Ingress, ingStatus []corev1.LoadBalancerIngress) error { +func (c *clientWrapper) UpdateIngressStatus(src *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error { if !c.isWatchedNamespace(src.Namespace) { return fmt.Errorf("failed to get ingress %s/%s: namespace is not within watched namespaces", src.Namespace, src.Name) } @@ -375,7 +362,7 @@ func (c *clientWrapper) UpdateIngressStatus(src *networkingv1.Ingress, ingStatus } ingCopy := ing.DeepCopy() - ingCopy.Status = networkingv1.IngressStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: ingStatus}} + ingCopy.Status = netv1.IngressStatus{LoadBalancer: netv1.IngressLoadBalancerStatus{Ingress: ingStatus}} ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() @@ -389,7 +376,7 @@ func (c *clientWrapper) UpdateIngressStatus(src *networkingv1.Ingress, ingStatus return nil } -func (c *clientWrapper) updateIngressStatusOld(src *networkingv1.Ingress, ingStatus []corev1.LoadBalancerIngress) error { +func (c *clientWrapper) updateIngressStatusOld(src *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error { ing, err := c.factoriesIngress[c.lookupNamespace(src.Namespace)].Networking().V1beta1().Ingresses().Lister().Ingresses(src.Namespace).Get(src.Name) if err != nil { return fmt.Errorf("failed to get ingress %s/%s: %w", src.Namespace, src.Name, err) @@ -397,13 +384,23 @@ func (c *clientWrapper) updateIngressStatusOld(src *networkingv1.Ingress, ingSta logger := log.With().Str("namespace", ing.Namespace).Str("ingress", ing.Name).Logger() - if isLoadBalancerIngressEquals(ing.Status.LoadBalancer.Ingress, ingStatus) { + ingresses, err := convertSlice[netv1.IngressLoadBalancerIngress](ing.Status.LoadBalancer.Ingress) + if err != nil { + return err + } + + if isLoadBalancerIngressEquals(ingresses, ingStatus) { logger.Debug().Msg("Skipping ingress status update") return nil } + ingressesBeta1, err := convertSlice[netv1beta1.IngressLoadBalancerIngress](ingStatus) + if err != nil { + return err + } + ingCopy := ing.DeepCopy() - ingCopy.Status = networkingv1beta1.IngressStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: ingStatus}} + ingCopy.Status = netv1beta1.IngressStatus{LoadBalancer: netv1beta1.IngressLoadBalancerStatus{Ingress: ingressesBeta1}} ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() @@ -417,7 +414,7 @@ func (c *clientWrapper) updateIngressStatusOld(src *networkingv1.Ingress, ingSta } // isLoadBalancerIngressEquals returns true if the given slices are equal, false otherwise. -func isLoadBalancerIngressEquals(aSlice, bSlice []corev1.LoadBalancerIngress) bool { +func isLoadBalancerIngressEquals(aSlice, bSlice []netv1.IngressLoadBalancerIngress) bool { if len(aSlice) != len(bSlice) { return false } @@ -469,12 +466,12 @@ func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool, return secret, exist, err } -func (c *clientWrapper) GetIngressClasses() ([]*networkingv1.IngressClass, error) { +func (c *clientWrapper) GetIngressClasses() ([]*netv1.IngressClass, error) { if c.clusterFactory == nil { return nil, errors.New("cluster factory not loaded") } - var ics []*networkingv1.IngressClass + var ics []*netv1.IngressClass if !supportsNetworkingV1Ingress(c.serverVersion) { ingressClasses, err := c.clusterFactory.Networking().V1beta1().IngressClasses().Lister().List(labels.Everything()) if err != nil { @@ -483,7 +480,7 @@ func (c *clientWrapper) GetIngressClasses() ([]*networkingv1.IngressClass, error for _, ic := range ingressClasses { if ic.Spec.Controller == traefikDefaultIngressClassController { - icN, err := toNetworkingV1IngressClass(ic) + icN, err := convert[netv1.IngressClass](ic) if err != nil { log.Error().Err(err).Msgf("Failed to convert ingress class %s from networking/v1beta1 to networking/v1", ic.Name) continue @@ -530,7 +527,7 @@ func (c *clientWrapper) GetServerVersion() *version.Version { // translateNotFoundError will translate a "not found" error to a boolean return // value which indicates if the resource exists and a nil error. func translateNotFoundError(err error) (bool, error) { - if kubeerror.IsNotFound(err) { + if kerror.IsNotFound(err) { return false, nil } return err == nil, err @@ -559,8 +556,8 @@ func supportsIngressClass(serverVersion *version.Version) bool { } // filterIngressClassByName return a slice containing ingressclasses with the correct name. -func filterIngressClassByName(ingressClassName string, ics []*networkingv1.IngressClass) []*networkingv1.IngressClass { - var ingressClasses []*networkingv1.IngressClass +func filterIngressClassByName(ingressClassName string, ics []*netv1.IngressClass) []*netv1.IngressClass { + var ingressClasses []*netv1.IngressClass for _, ic := range ics { if ic.Name == ingressClassName { diff --git a/pkg/provider/kubernetes/ingress/client_mock_test.go b/pkg/provider/kubernetes/ingress/client_mock_test.go index 6d91c37c8..518797a8c 100644 --- a/pkg/provider/kubernetes/ingress/client_mock_test.go +++ b/pkg/provider/kubernetes/ingress/client_mock_test.go @@ -7,18 +7,18 @@ import ( "github.com/hashicorp/go-version" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - networkingv1beta1 "k8s.io/api/networking/v1beta1" + netv1 "k8s.io/api/networking/v1" + netv1beta1 "k8s.io/api/networking/v1beta1" ) var _ Client = (*clientMock)(nil) type clientMock struct { - ingresses []*networkingv1.Ingress + ingresses []*netv1.Ingress services []*corev1.Service secrets []*corev1.Secret endpoints []*corev1.Endpoints - ingressClasses []*networkingv1.IngressClass + ingressClasses []*netv1.IngressClass serverVersion *version.Version @@ -50,22 +50,22 @@ func newClientMock(serverVersion string, paths ...string) clientMock { c.secrets = append(c.secrets, o) case *corev1.Endpoints: c.endpoints = append(c.endpoints, o) - case *networkingv1beta1.Ingress: - ing, err := toNetworkingV1(o) + case *netv1beta1.Ingress: + ing, err := convert[netv1.Ingress](o) if err != nil { panic(err) } addServiceFromV1Beta1(ing, *o) c.ingresses = append(c.ingresses, ing) - case *networkingv1.Ingress: + case *netv1.Ingress: c.ingresses = append(c.ingresses, o) - case *networkingv1beta1.IngressClass: - ic, err := toNetworkingV1IngressClass(o) + case *netv1beta1.IngressClass: + ic, err := convert[netv1.IngressClass](o) if err != nil { panic(err) } c.ingressClasses = append(c.ingressClasses, ic) - case *networkingv1.IngressClass: + case *netv1.IngressClass: c.ingressClasses = append(c.ingressClasses, o) default: panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o)) @@ -76,7 +76,7 @@ func newClientMock(serverVersion string, paths ...string) clientMock { return c } -func (c clientMock) GetIngresses() []*networkingv1.Ingress { +func (c clientMock) GetIngresses() []*netv1.Ingress { return c.ingresses } @@ -124,7 +124,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err return nil, false, nil } -func (c clientMock) GetIngressClasses() ([]*networkingv1.IngressClass, error) { +func (c clientMock) GetIngressClasses() ([]*netv1.IngressClass, error) { return c.ingressClasses, nil } @@ -132,6 +132,6 @@ func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-cha return c.watchChan, nil } -func (c clientMock) UpdateIngressStatus(_ *networkingv1.Ingress, _ []corev1.LoadBalancerIngress) error { +func (c clientMock) UpdateIngressStatus(_ *netv1.Ingress, _ []netv1.IngressLoadBalancerIngress) error { return c.apiIngressStatusError } diff --git a/pkg/provider/kubernetes/ingress/client_test.go b/pkg/provider/kubernetes/ingress/client_test.go index 48f0bf064..402da8e45 100644 --- a/pkg/provider/kubernetes/ingress/client_test.go +++ b/pkg/provider/kubernetes/ingress/client_test.go @@ -9,13 +9,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - "k8s.io/api/networking/v1beta1" - kubeerror "k8s.io/apimachinery/pkg/api/errors" + netv1 "k8s.io/api/networking/v1" + netv1beta1 "k8s.io/api/networking/v1beta1" + kerror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/version" - fakediscovery "k8s.io/client-go/discovery/fake" + kschema "k8s.io/apimachinery/pkg/runtime/schema" + kversion "k8s.io/apimachinery/pkg/version" + discoveryfake "k8s.io/client-go/discovery/fake" kubefake "k8s.io/client-go/kubernetes/fake" ) @@ -28,7 +28,7 @@ func TestTranslateNotFoundError(t *testing.T) { }{ { desc: "kubernetes not found error", - err: kubeerror.NewNotFound(schema.GroupResource{}, "foo"), + err: kerror.NewNotFound(kschema.GroupResource{}, "foo"), expectedExists: false, expectedError: nil, }, @@ -61,8 +61,8 @@ func TestTranslateNotFoundError(t *testing.T) { func TestIsLoadBalancerIngressEquals(t *testing.T) { testCases := []struct { desc string - aSlice []corev1.LoadBalancerIngress - bSlice []corev1.LoadBalancerIngress + aSlice []netv1.IngressLoadBalancerIngress + bSlice []netv1.IngressLoadBalancerIngress expectedEqual bool }{ { @@ -71,28 +71,28 @@ func TestIsLoadBalancerIngressEquals(t *testing.T) { }, { desc: "not the same length", - bSlice: []corev1.LoadBalancerIngress{ + bSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, }, expectedEqual: false, }, { desc: "same ordered content", - aSlice: []corev1.LoadBalancerIngress{ + aSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, }, - bSlice: []corev1.LoadBalancerIngress{ + bSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, }, expectedEqual: true, }, { desc: "same unordered content", - aSlice: []corev1.LoadBalancerIngress{ + aSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, {IP: "192.168.1.2", Hostname: "traefik2"}, }, - bSlice: []corev1.LoadBalancerIngress{ + bSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.2", Hostname: "traefik2"}, {IP: "192.168.1.1", Hostname: "traefik"}, }, @@ -100,11 +100,11 @@ func TestIsLoadBalancerIngressEquals(t *testing.T) { }, { desc: "different ordered content", - aSlice: []corev1.LoadBalancerIngress{ + aSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, {IP: "192.168.1.2", Hostname: "traefik2"}, }, - bSlice: []corev1.LoadBalancerIngress{ + bSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, {IP: "192.168.1.2", Hostname: "traefik"}, }, @@ -112,11 +112,11 @@ func TestIsLoadBalancerIngressEquals(t *testing.T) { }, { desc: "different unordered content", - aSlice: []corev1.LoadBalancerIngress{ + aSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.1", Hostname: "traefik"}, {IP: "192.168.1.2", Hostname: "traefik2"}, }, - bSlice: []corev1.LoadBalancerIngress{ + bSlice: []netv1.IngressLoadBalancerIngress{ {IP: "192.168.1.2", Hostname: "traefik3"}, {IP: "192.168.1.1", Hostname: "traefik"}, }, @@ -154,8 +154,8 @@ func TestClientIgnoresHelmOwnedSecrets(t *testing.T) { kubeClient := kubefake.NewSimpleClientset(helmSecret, secret) - discovery, _ := kubeClient.Discovery().(*fakediscovery.FakeDiscovery) - discovery.FakedServerVersion = &version.Info{ + discovery, _ := kubeClient.Discovery().(*discoveryfake.FakeDiscovery) + discovery.FakedServerVersion = &kversion.Info{ GitVersion: "v1.19", } @@ -223,8 +223,8 @@ func TestClientIgnoresEmptyEndpointUpdates(t *testing.T) { kubeClient := kubefake.NewSimpleClientset(emptyEndpoint, filledEndpoint) - discovery, _ := kubeClient.Discovery().(*fakediscovery.FakeDiscovery) - discovery.FakedServerVersion = &version.Info{ + discovery, _ := kubeClient.Discovery().(*discoveryfake.FakeDiscovery) + discovery.FakedServerVersion = &kversion.Info{ GitVersion: "v1.19", } @@ -291,14 +291,14 @@ func TestClientIgnoresEmptyEndpointUpdates(t *testing.T) { } func TestClientUsesCorrectServerVersion(t *testing.T) { - ingressV1Beta := &v1beta1.Ingress{ + ingressV1Beta := &netv1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "ingress-v1beta", }, } - ingressV1 := &networkingv1.Ingress{ + ingressV1 := &netv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "ingress-v1", @@ -307,8 +307,8 @@ func TestClientUsesCorrectServerVersion(t *testing.T) { kubeClient := kubefake.NewSimpleClientset(ingressV1Beta, ingressV1) - discovery, _ := kubeClient.Discovery().(*fakediscovery.FakeDiscovery) - discovery.FakedServerVersion = &version.Info{ + discovery, _ := kubeClient.Discovery().(*discoveryfake.FakeDiscovery) + discovery.FakedServerVersion = &kversion.Info{ GitVersion: "v1.18.12+foobar", } @@ -321,7 +321,7 @@ func TestClientUsesCorrectServerVersion(t *testing.T) { select { case event := <-eventCh: - ingress, ok := event.(*v1beta1.Ingress) + ingress, ok := event.(*netv1beta1.Ingress) require.True(t, ok) assert.Equal(t, "ingress-v1beta", ingress.Name) @@ -335,7 +335,7 @@ func TestClientUsesCorrectServerVersion(t *testing.T) { case <-time.After(50 * time.Millisecond): } - discovery.FakedServerVersion = &version.Info{ + discovery.FakedServerVersion = &kversion.Info{ GitVersion: "v1.19", } @@ -344,7 +344,7 @@ func TestClientUsesCorrectServerVersion(t *testing.T) { select { case event := <-eventCh: - ingress, ok := event.(*networkingv1.Ingress) + ingress, ok := event.(*netv1.Ingress) require.True(t, ok) assert.Equal(t, "ingress-v1", ingress.Name) diff --git a/pkg/provider/kubernetes/ingress/convert.go b/pkg/provider/kubernetes/ingress/convert.go new file mode 100644 index 000000000..b0274d660 --- /dev/null +++ b/pkg/provider/kubernetes/ingress/convert.go @@ -0,0 +1,70 @@ +package ingress + +import ( + "errors" + + corev1 "k8s.io/api/core/v1" + netv1 "k8s.io/api/networking/v1" + netv1beta1 "k8s.io/api/networking/v1beta1" +) + +type marshaler interface { + Marshal() ([]byte, error) +} + +type unmarshaler interface { + Unmarshal([]byte) error +} + +type LoadBalancerIngress interface { + corev1.LoadBalancerIngress | netv1beta1.IngressLoadBalancerIngress | netv1.IngressLoadBalancerIngress +} + +// convertSlice converts slice of LoadBalancerIngress to slice of LoadBalancerIngress. +// O (Bar), I (Foo) => []Bar. +func convertSlice[O LoadBalancerIngress, I LoadBalancerIngress](loadBalancerIngresses []I) ([]O, error) { + var results []O + + for _, loadBalancerIngress := range loadBalancerIngresses { + mar, ok := any(&loadBalancerIngress).(marshaler) + if !ok { + // All the pointer of types related to the interface LoadBalancerIngress are compatible with the interface marshaler. + continue + } + + um, err := convert[O](mar) + if err != nil { + return nil, err + } + + v, ok := any(*um).(O) + if !ok { + continue + } + + results = append(results, v) + } + + return results, nil +} + +// convert must only be used with unmarshaler and marshaler compatible types. +func convert[T any](input marshaler) (*T, error) { + data, err := input.Marshal() + if err != nil { + return nil, err + } + + var output T + um, ok := any(&output).(unmarshaler) + if !ok { + return nil, errors.New("the output type doesn't implement unmarshaler interface") + } + + err = um.Unmarshal(data) + if err != nil { + return nil, err + } + + return &output, nil +} diff --git a/pkg/provider/kubernetes/ingress/convert_test.go b/pkg/provider/kubernetes/ingress/convert_test.go new file mode 100644 index 000000000..0002b2b3a --- /dev/null +++ b/pkg/provider/kubernetes/ingress/convert_test.go @@ -0,0 +1,151 @@ +package ingress + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + netv1 "k8s.io/api/networking/v1" + netv1beta1 "k8s.io/api/networking/v1beta1" +) + +func Test_convertSlice_corev1_to_networkingv1(t *testing.T) { + g := []corev1.LoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []corev1.PortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + actual, err := convertSlice[netv1.IngressLoadBalancerIngress](g) + require.NoError(t, err) + + expected := []netv1.IngressLoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []netv1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + assert.Equal(t, expected, actual) +} + +func Test_convertSlice_networkingv1beta1_to_networkingv1(t *testing.T) { + g := []netv1beta1.IngressLoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []netv1beta1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + actual, err := convertSlice[netv1.IngressLoadBalancerIngress](g) + require.NoError(t, err) + + expected := []netv1.IngressLoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []netv1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + assert.Equal(t, expected, actual) +} + +func Test_convertSlice_networkingv1_to_networkingv1beta1(t *testing.T) { + g := []netv1.IngressLoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []netv1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + actual, err := convertSlice[netv1beta1.IngressLoadBalancerIngress](g) + require.NoError(t, err) + + expected := []netv1beta1.IngressLoadBalancerIngress{ + { + IP: "132456", + Hostname: "foo", + Ports: []netv1beta1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + }, + } + + assert.Equal(t, expected, actual) +} + +func Test_convert(t *testing.T) { + g := &corev1.LoadBalancerIngress{ + IP: "132456", + Hostname: "foo", + Ports: []corev1.PortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + } + + actual, err := convert[netv1.IngressLoadBalancerIngress](g) + require.NoError(t, err) + + expected := &netv1.IngressLoadBalancerIngress{ + IP: "132456", + Hostname: "foo", + Ports: []netv1.IngressPortStatus{ + { + Port: 123, + Protocol: "https", + Error: ptr("test"), + }, + }, + } + + assert.Equal(t, expected, actual) +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index 9bab326a2..2366d1988 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -25,7 +25,7 @@ import ( "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" + netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/labels" ) @@ -195,7 +195,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl serverVersion := client.GetServerVersion() - var ingressClasses []*networkingv1.IngressClass + var ingressClasses []*netv1.IngressClass if !p.DisableIngressClassLookup && supportsIngressClass(serverVersion) { ics, err := client.GetIngressClasses() @@ -346,7 +346,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl return conf } -func (p *Provider) updateIngressStatus(ing *networkingv1.Ingress, k8sClient Client) error { +func (p *Provider) updateIngressStatus(ing *netv1.Ingress, k8sClient Client) error { // Only process if an EndpointIngress has been configured. if p.IngressEndpoint == nil { return nil @@ -357,7 +357,7 @@ func (p *Provider) updateIngressStatus(ing *networkingv1.Ingress, k8sClient Clie return errors.New("publishedService or ip or hostname must be defined") } - return k8sClient.UpdateIngressStatus(ing, []corev1.LoadBalancerIngress{{IP: p.IngressEndpoint.IP, Hostname: p.IngressEndpoint.Hostname}}) + return k8sClient.UpdateIngressStatus(ing, []netv1.IngressLoadBalancerIngress{{IP: p.IngressEndpoint.IP, Hostname: p.IngressEndpoint.Hostname}}) } serviceInfo := strings.Split(p.IngressEndpoint.PublishedService, "/") @@ -382,10 +382,15 @@ func (p *Provider) updateIngressStatus(ing *networkingv1.Ingress, k8sClient Clie return fmt.Errorf("missing service: %s", p.IngressEndpoint.PublishedService) } - return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress) + ingresses, err := convertSlice[netv1.IngressLoadBalancerIngress](service.Status.LoadBalancer.Ingress) + if err != nil { + return err + } + + return k8sClient.UpdateIngressStatus(ing, ingresses) } -func (p *Provider) shouldProcessIngress(ingress *networkingv1.Ingress, ingressClasses []*networkingv1.IngressClass) bool { +func (p *Provider) shouldProcessIngress(ingress *netv1.Ingress, ingressClasses []*netv1.IngressClass) bool { // configuration through the new kubernetes ingressClass if ingress.Spec.IngressClassName != nil { for _, ic := range ingressClasses { @@ -410,7 +415,7 @@ func buildHostRule(host string) string { return fmt.Sprintf("Host(`%s`)", host) } -func getCertificates(ctx context.Context, ingress *networkingv1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { +func getCertificates(ctx context.Context, ingress *netv1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error { for _, t := range ingress.Spec.TLS { if t.SecretName == "" { log.Ctx(ctx).Debug().Msg("Skipping TLS sub-section: No secret name provided") @@ -495,7 +500,7 @@ func getTLSConfig(tlsConfigs map[string]*tls.CertAndStores) []*tls.CertAndStores return configs } -func (p *Provider) loadService(client Client, namespace string, backend networkingv1.IngressBackend) (*dynamic.Service, error) { +func (p *Provider) loadService(client Client, namespace string, backend netv1.IngressBackend) (*dynamic.Service, error) { service, exists, err := client.GetService(namespace, backend.Service.Name) if err != nil { return nil, err @@ -645,7 +650,7 @@ func makeRouterKeyWithHash(key, rule string) (string, error) { return dupKey, nil } -func loadRouter(rule networkingv1.IngressRule, pa networkingv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router { +func loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router { var rules []string if len(rule.Host) > 0 { rules = []string{buildHostRule(rule.Host)} @@ -654,11 +659,11 @@ func loadRouter(rule networkingv1.IngressRule, pa networkingv1.HTTPIngressPath, if len(pa.Path) > 0 { matcher := defaultPathMatcher - if pa.PathType == nil || *pa.PathType == "" || *pa.PathType == networkingv1.PathTypeImplementationSpecific { + if pa.PathType == nil || *pa.PathType == "" || *pa.PathType == netv1.PathTypeImplementationSpecific { if rtConfig != nil && rtConfig.Router != nil && rtConfig.Router.PathMatcher != "" { matcher = rtConfig.Router.PathMatcher } - } else if *pa.PathType == networkingv1.PathTypeExact { + } else if *pa.PathType == netv1.PathTypeExact { matcher = "Path" } diff --git a/pkg/provider/kubernetes/ingress/kubernetes_test.go b/pkg/provider/kubernetes/ingress/kubernetes_test.go index 9a3e4e05f..6a3119f0c 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes_test.go +++ b/pkg/provider/kubernetes/ingress/kubernetes_test.go @@ -17,7 +17,7 @@ import ( "github.com/traefik/traefik/v3/pkg/tls" "github.com/traefik/traefik/v3/pkg/types" corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" + netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -2160,7 +2160,7 @@ func TestGetCertificates(t *testing.T) { testCases := []struct { desc string - ingress *networkingv1.Ingress + ingress *netv1.Ingress client Client result map[string]*tls.CertAndStores errResult string diff --git a/pkg/provider/kubernetes/k8s/event_handler_test.go b/pkg/provider/kubernetes/k8s/event_handler_test.go index 8f75ebbd2..e8b7a31a2 100644 --- a/pkg/provider/kubernetes/k8s/event_handler_test.go +++ b/pkg/provider/kubernetes/k8s/event_handler_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/networking/v1" + netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -63,12 +63,12 @@ func Test_detectChanges(t *testing.T) { }, { name: "Ingress With same version", - oldObj: &v1.Ingress{ + oldObj: &netv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ ResourceVersion: "1", }, }, - newObj: &v1.Ingress{ + newObj: &netv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ ResourceVersion: "1", }, @@ -76,12 +76,12 @@ func Test_detectChanges(t *testing.T) { }, { name: "Ingress With different version", - oldObj: &v1.Ingress{ + oldObj: &netv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ ResourceVersion: "1", }, }, - newObj: &v1.Ingress{ + newObj: &netv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ ResourceVersion: "2", }, diff --git a/pkg/provider/kubernetes/k8s/parser.go b/pkg/provider/kubernetes/k8s/parser.go index 6cea900dc..769d5edf5 100644 --- a/pkg/provider/kubernetes/k8s/parser.go +++ b/pkg/provider/kubernetes/k8s/parser.go @@ -7,7 +7,7 @@ import ( "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" + kscheme "k8s.io/client-go/kubernetes/scheme" ) // MustParseYaml parses a YAML to objects. @@ -21,7 +21,7 @@ func MustParseYaml(content []byte) []runtime.Object { continue } - decode := scheme.Codecs.UniversalDeserializer().Decode + decode := kscheme.Codecs.UniversalDeserializer().Decode obj, groupVersionKind, err := decode([]byte(file), nil, nil) if err != nil { panic(fmt.Sprintf("Error while decoding YAML object. Err was: %s", err)) diff --git a/pkg/server/service/roundtripper_test.go b/pkg/server/service/roundtripper_test.go index 971604d92..c9af07a17 100644 --- a/pkg/server/service/roundtripper_test.go +++ b/pkg/server/service/roundtripper_test.go @@ -467,9 +467,6 @@ func newFakeSpiffePKI(trustDomain spiffeid.TrustDomain) (fakeSpiffePKI, error) { IsCA: true, PublicKey: caPrivateKey.Public(), } - if err != nil { - return fakeSpiffePKI{}, err - } caCertDER, err := x509.CreateCertificate( rand.Reader, diff --git a/pkg/tracing/opentelemetry/opentelemetry.go b/pkg/tracing/opentelemetry/opentelemetry.go index af12c67a3..c59fbd410 100644 --- a/pkg/tracing/opentelemetry/opentelemetry.go +++ b/pkg/tracing/opentelemetry/opentelemetry.go @@ -27,7 +27,7 @@ import ( // Config provides configuration settings for the open-telemetry tracer. type Config struct { // NOTE: as no gRPC option is implemented yet, the type is empty and is used as a boolean for upward compatibility purposes. - GRPC *struct{} `description:"gRPC specific configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + GRPC *struct{} `description:"gRPC specific configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Address string `description:"Sets the address (host:port) of the collector endpoint." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` Path string `description:"Sets the URL path of the collector endpoint." json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"` diff --git a/pkg/types/metrics.go b/pkg/types/metrics.go index 2d8b4114d..665333630 100644 --- a/pkg/types/metrics.go +++ b/pkg/types/metrics.go @@ -107,7 +107,7 @@ func (i *InfluxDB2) SetDefaults() { // OpenTelemetry contains specific configuration used by the OpenTelemetry Metrics exporter. type OpenTelemetry struct { // NOTE: as no gRPC option is implemented yet, the type is empty and is used as a boolean for upward compatibility purposes. - GRPC *struct{} `description:"gRPC specific configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + GRPC *struct{} `description:"gRPC specific configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Address string `description:"Address (host:port) of the collector endpoint." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` diff --git a/webui/src/components/_commons/PanelMiddlewares.vue b/webui/src/components/_commons/PanelMiddlewares.vue index c85e6a312..f0a78a23b 100644 --- a/webui/src/components/_commons/PanelMiddlewares.vue +++ b/webui/src/components/_commons/PanelMiddlewares.vue @@ -723,7 +723,7 @@ - + @@ -742,6 +742,14 @@ {{ exData(middleware).burst }} + + Period + + {{ exData(middleware).period }} + +