├── .github └── workflows │ ├── go-cross.yml │ └── main.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── acme ├── acme.go ├── acme_test.go ├── fixtures │ ├── acme.json │ └── new-acme.json └── storeddata.go ├── docs ├── traefik-migration-tool.md ├── traefik-migration-tool_acme.md ├── traefik-migration-tool_ingress.md ├── traefik-migration-tool_static.md └── traefik-migration-tool_version.md ├── go.mod ├── go.sum ├── ingress ├── annotations.go ├── fixtures │ ├── input │ │ ├── ingress.yml │ │ ├── ingress_and_service.yml │ │ ├── ingress_extensions.yml │ │ ├── ingress_networking_v1beta1.yml │ │ ├── ingress_redirect_approot.yml │ │ ├── ingress_redirect_regex.yml │ │ ├── ingress_rewrite_target.yml │ │ ├── ingress_with_errorpage.yml │ │ ├── ingress_with_headers_annotations.yml │ │ ├── ingress_with_matcher.yml │ │ ├── ingress_with_matcher_modifier.yml │ │ ├── ingress_with_middleware_name.yml │ │ ├── ingress_with_passtlscert.yml │ │ ├── ingress_with_protocol.yml │ │ ├── ingress_with_ratelimit.yml │ │ ├── ingress_with_request_modifier.yml │ │ ├── ingress_with_whitelist.yml │ │ ├── ingress_with_whitelist_xforwarded.yml │ │ ├── items_ingress.yml │ │ ├── items_mix.yml │ │ └── service_only.yml │ ├── output_convertFile │ │ ├── ingress.yml │ │ ├── ingress_extensions.yml │ │ ├── ingress_networking_v1beta1.yml │ │ ├── ingress_redirect_approot.yml │ │ ├── ingress_redirect_regex.yml │ │ ├── ingress_rewrite_target.yml │ │ ├── ingress_with_headers_annotations.yml │ │ ├── ingress_with_matcher.yml │ │ ├── ingress_with_matcher_modifier.yml │ │ ├── ingress_with_middleware_name.yml │ │ ├── ingress_with_passtlscert.yml │ │ ├── ingress_with_protocol.yml │ │ ├── ingress_with_ratelimit.yml │ │ ├── ingress_with_request_modifier.yml │ │ ├── ingress_with_whitelist.yml │ │ ├── ingress_with_whitelist_xforwarded.yml │ │ ├── items_ingress.yml │ │ └── items_mix.yml │ └── output_convertIngress │ │ ├── ingress_01.yml │ │ ├── ingress_redirect_approot_01.yml │ │ ├── ingress_redirect_approot_02.yml │ │ ├── ingress_redirect_regex_01.yml │ │ ├── ingress_redirect_regex_02.yml │ │ ├── ingress_redirect_regex_03.yml │ │ ├── ingress_rewrite_target_01.yml │ │ ├── ingress_rewrite_target_02.yml │ │ ├── ingress_with_headers_annotations_01.yml │ │ ├── ingress_with_headers_annotations_02.yml │ │ ├── ingress_with_matcher_01.yml │ │ ├── ingress_with_matcher_modifier_01.yml │ │ ├── ingress_with_matcher_modifier_02.yml │ │ ├── ingress_with_matcher_modifier_03.yml │ │ ├── ingress_with_passtlscert_01.yml │ │ ├── ingress_with_passtlscert_02.yml │ │ ├── ingress_with_protocol_01.yml │ │ ├── ingress_with_ratelimit_01.yml │ │ ├── ingress_with_ratelimit_02.yml │ │ ├── ingress_with_ratelimit_03.yml │ │ ├── ingress_with_request_modifier_01.yml │ │ ├── ingress_with_request_modifier_02.yml │ │ ├── ingress_with_whitelist_01.yml │ │ ├── ingress_with_whitelist_02.yml │ │ ├── ingress_with_whitelist_xforwarded_01.yml │ │ └── ingress_with_whitelist_xforwarded_02.yml ├── ingress.go ├── ingress_test.go ├── middlewares.go └── parser.go ├── label └── label.go ├── main.go ├── readme.md ├── static ├── acme.go ├── configuration.go ├── convert.go ├── convert_test.go ├── fixtures │ ├── sample01.toml │ └── sample02.toml ├── logs.go ├── metrics.go ├── providers.go ├── tracing.go └── v1.go └── tmpl.Dockerfile /.github/workflows/go-cross.yml: -------------------------------------------------------------------------------- 1 | name: Go Matrix 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | 11 | cross: 12 | name: Go 13 | runs-on: ${{ matrix.os }} 14 | env: 15 | CGO_ENABLED: 0 16 | 17 | strategy: 18 | matrix: 19 | go-version: [ 1.17, 1.x ] 20 | os: [ubuntu-latest, macos-latest, windows-latest] 21 | 22 | steps: 23 | # https://github.com/marketplace/actions/setup-go-environment 24 | - name: Set up Go ${{ matrix.go-version }} 25 | uses: actions/setup-go@v2 26 | with: 27 | go-version: ${{ matrix.go-version }} 28 | 29 | # https://github.com/marketplace/actions/checkout 30 | - name: Checkout code 31 | uses: actions/checkout@v2 32 | 33 | # https://github.com/marketplace/actions/cache 34 | - name: Cache Go modules 35 | uses: actions/cache@v2 36 | with: 37 | # In order: 38 | # * Module download cache 39 | # * Build cache (Linux) 40 | # * Build cache (Mac) 41 | # * Build cache (Windows) 42 | path: | 43 | ~/go/pkg/mod 44 | ~/.cache/go-build 45 | ~/Library/Caches/go-build 46 | %LocalAppData%\go-build 47 | key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }} 48 | restore-keys: | 49 | ${{ runner.os }}-${{ matrix.go-version }}-go- 50 | 51 | - name: Test 52 | run: go test -v -cover ./... 53 | 54 | - name: Build 55 | run: go build -v -ldflags "-s -w" -trimpath 56 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - v* 9 | pull_request: 10 | 11 | jobs: 12 | 13 | main: 14 | name: Main Process 15 | runs-on: ubuntu-latest 16 | env: 17 | GO_VERSION: 1.17 18 | GOLANGCI_LINT_VERSION: v1.46.2 19 | SEIHON_VERSION: v0.8.3 20 | CGO_ENABLED: 0 21 | 22 | steps: 23 | 24 | # https://github.com/marketplace/actions/setup-go-environment 25 | - name: Set up Go ${{ env.GO_VERSION }} 26 | uses: actions/setup-go@v2 27 | with: 28 | go-version: ${{ env.GO_VERSION }} 29 | 30 | # https://github.com/marketplace/actions/checkout 31 | - name: Check out code 32 | uses: actions/checkout@v2 33 | with: 34 | fetch-depth: 0 35 | 36 | # https://github.com/marketplace/actions/cache 37 | - name: Cache Go modules 38 | uses: actions/cache@v2 39 | with: 40 | path: ~/go/pkg/mod 41 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 42 | restore-keys: | 43 | ${{ runner.os }}-go- 44 | 45 | - name: Check and get dependencies 46 | run: | 47 | go mod tidy 48 | git diff --exit-code go.mod 49 | git diff --exit-code go.sum 50 | 51 | # https://golangci-lint.run/usage/install#other-ci 52 | - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} 53 | run: | 54 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} 55 | golangci-lint --version 56 | 57 | - name: Make 58 | run: make 59 | 60 | # https://goreleaser.com/ci/actions/ 61 | - name: Run GoReleaser 62 | uses: goreleaser/goreleaser-action@v2 63 | if: startsWith(github.ref, 'refs/tags/v') 64 | with: 65 | version: latest 66 | args: release --rm-dist --timeout 60m 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }} 69 | 70 | # Install Docker image multi-arch builder 71 | - name: Install seihon ${{ env.SEIHON_VERSION }} 72 | if: startsWith(github.ref, 'refs/tags/v') 73 | run: | 74 | curl -sSfL https://raw.githubusercontent.com/ldez/seihon/master/godownloader.sh | sh -s -- -b $(go env GOPATH)/bin ${SEIHON_VERSION} 75 | seihon --version 76 | 77 | - name: Docker Login 78 | if: startsWith(github.ref, 'refs/tags/v') 79 | env: 80 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 81 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 82 | run: echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin 83 | 84 | - name: Deploy Docker Images (seihon) 85 | if: startsWith(github.ref, 'refs/tags/v') 86 | run: make publish-images 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | traefik-migration-tool 2 | .idea/ 3 | dist/ 4 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 5m 3 | skip-files: [] 4 | 5 | linters-settings: 6 | govet: 7 | check-shadowing: true 8 | gocyclo: 9 | min-complexity: 16 10 | goconst: 11 | min-len: 3 12 | min-occurrences: 3 13 | misspell: 14 | locale: US 15 | gofumpt: 16 | extra-rules: true 17 | depguard: 18 | list-type: blacklist 19 | include-go-root: false 20 | packages: 21 | - github.com/pkg/errors 22 | godox: 23 | keywords: 24 | - FIXME 25 | gocritic: 26 | enabled-tags: 27 | - diagnostic 28 | - style 29 | - performance 30 | disabled-checks: 31 | - unnamedResult 32 | - hugeParam 33 | - sloppyReassign 34 | - rangeValCopy 35 | - octalLiteral 36 | - paramTypeCombine # already handle by gofumpt.extra-rules 37 | forbidigo: 38 | forbid: 39 | - '^print(ln)?$' 40 | # - '^fmt\.Print(f|ln)?$' 41 | # - '^panic$' 42 | - '^spew\.Print(f|ln)?$' 43 | - '^spew\.Dump$' 44 | gomoddirectives: 45 | replace-local: false 46 | replace-allow-list: 47 | - github.com/abbot/go-http-auth 48 | - github.com/go-check/check 49 | - github.com/gorilla/mux 50 | - github.com/mailgun/minheap 51 | - github.com/mailgun/multibuf 52 | - github.com/docker/docker 53 | funlen: 54 | lines: 120 # default 60 55 | statements: 50 # default 40 56 | 57 | linters: 58 | enable-all: true 59 | disable: 60 | # Deprecated 61 | - interfacer 62 | - golint 63 | - maligned 64 | - scopelint 65 | 66 | # Too strict 67 | - dupl 68 | - forcetypeassert 69 | - gochecknoglobals 70 | - gochecknoinits 71 | - gocognit 72 | - godox 73 | - goerr113 74 | - gomnd 75 | - gosec 76 | - noctx 77 | - testpackage 78 | - unparam 79 | - wrapcheck 80 | - wsl 81 | 82 | # Not relevant 83 | - exhaustive 84 | - exhaustivestruct 85 | - exhaustruct 86 | - ifshort 87 | - lll 88 | - makezero 89 | - nlreturn 90 | - paralleltest 91 | - rowserrcheck # SQL 92 | - sqlclosecheck # SQL 93 | - tparallel 94 | - varnamelen 95 | - ireturn 96 | - nilnil 97 | 98 | # Too many false-positive. 99 | - nestif 100 | - prealloc 101 | - bodyclose 102 | 103 | - cyclop # Duplicate of gocyclo 104 | 105 | issues: 106 | exclude-use-default: false 107 | max-per-linter: 0 108 | max-same-issues: 0 109 | exclude: 110 | - 'ST1000: at least one file in a package should have a package comment' 111 | - 'exported: exported type (.+) should have comment or be unexported' 112 | exclude-rules: 113 | - path: annotations.go 114 | text: (compatibilityMapping) is a global variable 115 | - path: .*_test.go 116 | text: (updateExpected) is a global variable 117 | - path: main.go 118 | text: (Version|ShortCommit|Date) is a global variable 119 | - path: main.go 120 | text: exported var (Version|ShortCommit|Date) should have comment or be unexported 121 | - path: ingress/annotations.go 122 | text: '`getBoolValue` - `defaultValue` always receives `false`' 123 | - path: static/v1.go 124 | text: exported type `(.+)` should have comment or be unexported 125 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: traefik-migration-tool 2 | 3 | builds: 4 | - binary: traefik-migration-tool 5 | main: ./main.go 6 | 7 | goos: 8 | - linux 9 | - darwin 10 | - windows 11 | - freebsd 12 | - openbsd 13 | goarch: 14 | - amd64 15 | - 386 16 | - arm 17 | - arm64 18 | - ppc64le 19 | goarm: 20 | - 7 21 | - 6 22 | - 5 23 | ignore: 24 | - goos: darwin 25 | goarch: 386 26 | - goos: openbsd 27 | goarch: arm 28 | - goos: freebsd 29 | goarch: arm 30 | 31 | changelog: 32 | sort: asc 33 | filters: 34 | exclude: 35 | - '^docs:' 36 | - '^doc:' 37 | - '^chore:' 38 | - '^chore(deps):' 39 | - '^test:' 40 | - '^tests:' 41 | 42 | archives: 43 | - id: traefik-migration-tool 44 | name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 45 | format: tar.gz 46 | format_overrides: 47 | - goos: windows 48 | format: zip 49 | files: 50 | - docs/*.md 51 | - LICENSE 52 | 53 | checksum: 54 | name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt" 55 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Building app with golang container 2 | FROM golang:1.16-alpine as builder 3 | 4 | RUN apk --no-cache --no-progress add git make ca-certificates tzdata\ 5 | && rm -rf /var/cache/apk/* 6 | 7 | WORKDIR /go/traefik-migration-tool 8 | 9 | # Download go modules 10 | COPY go.mod . 11 | COPY go.sum . 12 | RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download 13 | 14 | COPY . . 15 | 16 | RUN make build 17 | 18 | ## IMAGE 19 | FROM alpine:3.13 20 | 21 | RUN apk --no-cache --no-progress add ca-certificates tzdata\ 22 | && rm -rf /var/cache/apk/* 23 | 24 | COPY --from=builder /go/traefik-migration-tool/traefik-migration-tool . 25 | 26 | ENTRYPOINT ["/traefik-migration-tool"] 27 | CMD ["-h"] 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Traefik Labs 190 | Copyright 2019 Containous SAS 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: check clean test build package package-snapshot docs 2 | 3 | export GO111MODULE=on 4 | 5 | TAG_NAME := $(shell git tag -l --contains HEAD) 6 | SHA := $(shell git rev-parse HEAD) 7 | VERSION := $(if $(TAG_NAME),$(TAG_NAME),$(SHA)) 8 | 9 | default: check test build 10 | 11 | test: 12 | go test -v -cover ./... 13 | 14 | clean: 15 | rm -rf dist/ 16 | 17 | build: clean 18 | @echo Version: $(VERSION) 19 | go build -v -ldflags '-X "main.Version=${VERSION}" -X "main.ShortCommit=${SHA}"' . 20 | 21 | check: 22 | golangci-lint run 23 | 24 | doc: 25 | go run . doc 26 | 27 | image: 28 | docker build -t traefik-migration-tool . 29 | 30 | publish-images: 31 | seihon publish -v "$(TAG_NAME)" -v "latest" --image-name traefik/traefik-migration-tool --dry-run=false 32 | 33 | package: 34 | goreleaser --skip-publish --skip-validate --rm-dist 35 | 36 | package-snapshot: 37 | goreleaser --skip-publish --skip-validate --rm-dist --snapshot 38 | -------------------------------------------------------------------------------- /acme/acme.go: -------------------------------------------------------------------------------- 1 | package acme 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/traefik/traefik/v2/pkg/provider/acme" 9 | "github.com/traefik/traefik/v2/pkg/types" 10 | ) 11 | 12 | // Convert a acme.json file. 13 | func Convert(srcFile, dstFile, resolverName string) error { 14 | src, err := os.Open(srcFile) 15 | if err != nil { 16 | return err 17 | } 18 | defer func() { _ = src.Close() }() 19 | 20 | oldData := StoredData{} 21 | err = json.NewDecoder(src).Decode(&oldData) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | data := acme.StoredData{} 27 | 28 | if oldData.Account != nil { 29 | data.Account = &acme.Account{ 30 | Email: oldData.Account.Email, 31 | Registration: oldData.Account.Registration, 32 | PrivateKey: oldData.Account.PrivateKey, 33 | KeyType: oldData.Account.KeyType, 34 | } 35 | } 36 | 37 | for _, c := range oldData.Certificates { 38 | data.Certificates = append(data.Certificates, &acme.CertAndStore{ 39 | Certificate: acme.Certificate{ 40 | Domain: types.Domain{ 41 | Main: c.Domain.Main, 42 | SANs: c.Domain.SANs, 43 | }, 44 | Certificate: c.Certificate, 45 | Key: c.Key, 46 | }, 47 | Store: "default", 48 | }) 49 | } 50 | 51 | err = os.MkdirAll(filepath.Dir(dstFile), 0o755) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | dst, err := os.Create(dstFile) 57 | if err != nil { 58 | return err 59 | } 60 | defer func() { _ = dst.Close() }() 61 | 62 | encoder := json.NewEncoder(dst) 63 | encoder.SetIndent("", " ") 64 | 65 | return encoder.Encode(map[string]*acme.StoredData{resolverName: &data}) 66 | } 67 | -------------------------------------------------------------------------------- /acme/acme_test.go: -------------------------------------------------------------------------------- 1 | package acme 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata") 16 | 17 | func TestConvert(t *testing.T) { 18 | srcFile := "./fixtures/acme.json" 19 | fixtureFile := "./fixtures/new-acme.json" 20 | 21 | dir := t.TempDir() 22 | 23 | dstFile := filepath.Join(dir, "new-acme.json") 24 | 25 | err := Convert(srcFile, dstFile, "myresolver") 26 | require.NoError(t, err) 27 | 28 | actual, err := os.ReadFile(dstFile) 29 | require.NoError(t, err) 30 | 31 | fmt.Println(dstFile) 32 | 33 | if *updateExpected { 34 | var dst *os.File 35 | dst, err = os.Open(dstFile) 36 | require.NoError(t, err) 37 | var fixture *os.File 38 | fixture, err = os.Create(fixtureFile) 39 | require.NoError(t, err) 40 | 41 | _, err = io.Copy(fixture, dst) 42 | require.NoError(t, err) 43 | } 44 | 45 | expected, err := os.ReadFile(fixtureFile) 46 | require.NoError(t, err) 47 | 48 | assert.JSONEq(t, string(expected), string(actual)) 49 | } 50 | -------------------------------------------------------------------------------- /acme/fixtures/acme.json: -------------------------------------------------------------------------------- 1 | { 2 | "Account": { 3 | "Email": "test@example.com", 4 | "Registration": { 5 | "body": { 6 | "status": "valid", 7 | "contact": [ 8 | "mailto:test@example.com" 9 | ] 10 | }, 11 | "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/00000001" 12 | }, 13 | "PrivateKey": "UHJpdmF0ZUtleQ==", 14 | "KeyType": "4096" 15 | }, 16 | "Certificates": [ 17 | { 18 | "Domain": { 19 | "Main": "test.example.com", 20 | "SANs": null 21 | }, 22 | "Certificate": "Q2VydGlmaWNhdGU=", 23 | "Key": "Q2VydGlmaWNhdGUgS2V5" 24 | } 25 | ], 26 | "HTTPChallenges": null, 27 | "TLSChallenges": {} 28 | } 29 | -------------------------------------------------------------------------------- /acme/fixtures/new-acme.json: -------------------------------------------------------------------------------- 1 | { 2 | "myresolver": { 3 | "Account": { 4 | "Email": "test@example.com", 5 | "Registration": { 6 | "body": { 7 | "status": "valid", 8 | "contact": [ 9 | "mailto:test@example.com" 10 | ] 11 | }, 12 | "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/00000001" 13 | }, 14 | "PrivateKey": "UHJpdmF0ZUtleQ==", 15 | "KeyType": "4096" 16 | }, 17 | "Certificates": [ 18 | { 19 | "domain": { 20 | "main": "test.example.com" 21 | }, 22 | "certificate": "Q2VydGlmaWNhdGU=", 23 | "key": "Q2VydGlmaWNhdGUgS2V5", 24 | "Store": "default" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /acme/storeddata.go: -------------------------------------------------------------------------------- 1 | package acme 2 | 3 | import ( 4 | "github.com/go-acme/lego/v4/certcrypto" 5 | "github.com/go-acme/lego/v4/registration" 6 | ) 7 | 8 | // StoredData represents the data managed by the Store. 9 | type StoredData struct { 10 | Account *Account 11 | Certificates []*Certificate 12 | HTTPChallenges map[string]map[string][]byte 13 | TLSChallenges map[string]*Certificate 14 | } 15 | 16 | // Certificate is a struct which contains all data needed from an ACME certificate. 17 | type Certificate struct { 18 | Domain Domain 19 | Certificate []byte 20 | Key []byte 21 | } 22 | 23 | // Domain holds a domain name with SANs. 24 | type Domain struct { 25 | Main string 26 | SANs []string 27 | } 28 | 29 | // Account is used to store lets encrypt registration info. 30 | type Account struct { 31 | Email string 32 | Registration *registration.Resource 33 | PrivateKey []byte 34 | KeyType certcrypto.KeyType 35 | } 36 | -------------------------------------------------------------------------------- /docs/traefik-migration-tool.md: -------------------------------------------------------------------------------- 1 | ## traefik-migration-tool 2 | 3 | A tool to migrate from Traefik v1 to Traefik v2. 4 | 5 | ### Synopsis 6 | 7 | A tool to migrate from Traefik v1 to Traefik v2. 8 | 9 | ### Options 10 | 11 | ``` 12 | -h, --help help for traefik-migration-tool 13 | ``` 14 | 15 | ### SEE ALSO 16 | 17 | * [traefik-migration-tool acme](traefik-migration-tool_acme.md) - Migrate acme.json file from Traefik v1 to Traefik v2. 18 | * [traefik-migration-tool ingress](traefik-migration-tool_ingress.md) - Migrate 'Ingress' to Traefik 'IngressRoute' resources. 19 | * [traefik-migration-tool static](traefik-migration-tool_static.md) - Migrate static configuration file from Traefik v1 to Traefik v2. 20 | * [traefik-migration-tool version](traefik-migration-tool_version.md) - Display version 21 | 22 | ###### Auto generated by spf13/cobra on 20-Sep-2019 23 | -------------------------------------------------------------------------------- /docs/traefik-migration-tool_acme.md: -------------------------------------------------------------------------------- 1 | ## traefik-migration-tool acme 2 | 3 | Migrate acme.json file from Traefik v1 to Traefik v2. 4 | 5 | ### Synopsis 6 | 7 | Migrate acme.json file from Traefik v1 to Traefik v2. 8 | 9 | ``` 10 | traefik-migration-tool acme [flags] 11 | ``` 12 | 13 | ### Options 14 | 15 | ``` 16 | -h, --help help for acme 17 | -i, --input string Path to the acme.json file from Traefik v1. (default "./acme.json") 18 | -o, --output string Path to the acme.json file for Traefik v2. (default "./acme-new.json") 19 | --resolver string The name of the certificates resolver. (default "default") 20 | ``` 21 | 22 | ### SEE ALSO 23 | 24 | * [traefik-migration-tool](traefik-migration-tool.md) - A tool to migrate from Traefik v1 to Traefik v2. 25 | 26 | ###### Auto generated by spf13/cobra on 20-Sep-2019 27 | -------------------------------------------------------------------------------- /docs/traefik-migration-tool_ingress.md: -------------------------------------------------------------------------------- 1 | ## traefik-migration-tool ingress 2 | 3 | Migrate 'Ingress' to Traefik 'IngressRoute' resources. 4 | 5 | ### Synopsis 6 | 7 | Migrate 'Ingress' to Traefik 'IngressRoute' resources. 8 | 9 | ``` 10 | traefik-migration-tool ingress [flags] 11 | ``` 12 | 13 | ### Options 14 | 15 | ``` 16 | -h, --help help for ingress 17 | -i, --input string Input directory. 18 | -o, --output string Output directory. (default "./output") 19 | ``` 20 | 21 | ### SEE ALSO 22 | 23 | * [traefik-migration-tool](traefik-migration-tool.md) - A tool to migrate from Traefik v1 to Traefik v2. 24 | 25 | ###### Auto generated by spf13/cobra on 20-Sep-2019 26 | -------------------------------------------------------------------------------- /docs/traefik-migration-tool_static.md: -------------------------------------------------------------------------------- 1 | ## traefik-migration-tool static 2 | 3 | Migrate static configuration file from Traefik v1 to Traefik v2. 4 | 5 | ### Synopsis 6 | 7 | Migrate static configuration file from Traefik v1 to Traefik v2. 8 | Convert only the static configuration. 9 | 10 | ``` 11 | traefik-migration-tool static [flags] 12 | ``` 13 | 14 | ### Options 15 | 16 | ``` 17 | -h, --help help for static 18 | -i, --input string Path to the traefik.toml file from Traefik v1. (default "./traefik.toml") 19 | -d, --output-dir string Path to the directory of the created files (default "./static") 20 | ``` 21 | 22 | ### SEE ALSO 23 | 24 | * [traefik-migration-tool](traefik-migration-tool.md) - A tool to migrate from Traefik v1 to Traefik v2. 25 | 26 | ###### Auto generated by spf13/cobra on 20-Sep-2019 27 | -------------------------------------------------------------------------------- /docs/traefik-migration-tool_version.md: -------------------------------------------------------------------------------- 1 | ## traefik-migration-tool version 2 | 3 | Display version 4 | 5 | ### Synopsis 6 | 7 | Display version 8 | 9 | ``` 10 | traefik-migration-tool version [flags] 11 | ``` 12 | 13 | ### Options 14 | 15 | ``` 16 | -h, --help help for version 17 | ``` 18 | 19 | ### SEE ALSO 20 | 21 | * [traefik-migration-tool](traefik-migration-tool.md) - A tool to migrate from Traefik v1 to Traefik v2. 22 | 23 | ###### Auto generated by spf13/cobra on 20-Sep-2019 24 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/traefik/traefik-migration-tool 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/BurntSushi/toml v1.1.0 7 | github.com/containous/flaeg v1.4.1 8 | github.com/go-acme/lego/v4 v4.7.0 9 | github.com/mitchellh/hashstructure v1.1.0 10 | github.com/spf13/cobra v1.5.0 11 | github.com/stretchr/testify v1.8.0 12 | github.com/traefik/paerser v0.1.5 13 | github.com/traefik/traefik/v2 v2.8.0 14 | gopkg.in/yaml.v2 v2.4.0 15 | k8s.io/api v0.22.1 16 | k8s.io/apimachinery v0.22.1 17 | k8s.io/client-go v0.22.1 18 | sigs.k8s.io/yaml v1.3.0 19 | ) 20 | 21 | require ( 22 | cloud.google.com/go v0.81.0 // indirect 23 | github.com/Azure/azure-sdk-for-go v40.3.0+incompatible // indirect 24 | github.com/Azure/go-autorest v14.2.0+incompatible // indirect 25 | github.com/Azure/go-autorest/autorest v0.11.19 // indirect 26 | github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect 27 | github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect 28 | github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect 29 | github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect 30 | github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect 31 | github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect 32 | github.com/Azure/go-autorest/logger v0.2.1 // indirect 33 | github.com/Azure/go-autorest/tracing v0.6.0 // indirect 34 | github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 // indirect 35 | github.com/DataDog/datadog-go v4.8.2+incompatible // indirect 36 | github.com/DataDog/datadog-go/v5 v5.0.2 // indirect 37 | github.com/DataDog/sketches-go v1.0.0 // indirect 38 | github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 //indirect 39 | github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61 // indirect 40 | github.com/Masterminds/goutils v1.1.1 // indirect 41 | github.com/Masterminds/semver/v3 v3.1.1 // indirect 42 | github.com/Masterminds/sprig/v3 v3.2.2 // indirect 43 | github.com/Microsoft/go-winio v0.5.1 // indirect 44 | github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect 45 | github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect 46 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 // indirect 47 | github.com/armon/go-metrics v0.3.10 // indirect 48 | github.com/armon/go-radix v1.0.0 // indirect 49 | github.com/aws/aws-sdk-go v1.39.0 // indirect 50 | github.com/beorn7/perks v1.0.1 // indirect 51 | github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect 52 | github.com/cenkalti/backoff/v4 v4.1.1 // indirect 53 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 54 | github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect 55 | github.com/circonus-labs/circonusllhist v0.1.3 // indirect 56 | github.com/cloudflare/cloudflare-go v0.20.0 // indirect 57 | github.com/containerd/containerd v1.5.9 // indirect 58 | github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd // indirect 59 | github.com/coreos/go-semver v0.3.0 // indirect 60 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 61 | github.com/cpu/goacmedns v0.1.1 // indirect 62 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect 63 | github.com/davecgh/go-spew v1.1.1 // indirect 64 | github.com/deepmap/oapi-codegen v1.8.2 // indirect 65 | github.com/dgraph-io/ristretto v0.1.0 // indirect 66 | github.com/dimchansky/utfbom v1.1.1 // indirect 67 | github.com/dnsimple/dnsimple-go v0.70.1 // indirect 68 | github.com/docker/cli v20.10.11+incompatible // indirect 69 | github.com/docker/distribution v2.7.1+incompatible // indirect 70 | github.com/docker/docker v20.10.7+incompatible // indirect 71 | github.com/docker/go-connections v0.4.0 // indirect 72 | github.com/docker/go-units v0.4.0 // indirect 73 | github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect 74 | github.com/dustin/go-humanize v1.0.0 // indirect 75 | github.com/elastic/go-licenser v0.3.1 // indirect 76 | github.com/elastic/go-sysinfo v1.1.1 // indirect 77 | github.com/elastic/go-windows v1.0.0 // indirect 78 | github.com/exoscale/egoscale v0.67.0 // indirect 79 | github.com/fatih/color v1.12.0 // indirect 80 | github.com/fatih/structs v1.1.0 // indirect 81 | github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect 82 | github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 // indirect 83 | github.com/go-errors/errors v1.0.1 // indirect 84 | github.com/go-logr/logr v0.4.0 // indirect 85 | github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect 86 | github.com/go-zookeeper/zk v1.0.2 // indirect 87 | github.com/gofrs/uuid v4.0.0+incompatible // indirect 88 | github.com/gogo/protobuf v1.3.2 // indirect 89 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect 90 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 91 | github.com/golang/protobuf v1.5.2 // indirect 92 | github.com/google/btree v1.0.1 // indirect 93 | github.com/google/go-cmp v0.5.7 // indirect 94 | github.com/google/go-github/v28 v28.1.1 // indirect 95 | github.com/google/go-querystring v1.1.0 // indirect 96 | github.com/google/gofuzz v1.2.0 // indirect 97 | github.com/google/uuid v1.3.0 // indirect 98 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect 99 | github.com/googleapis/gnostic v0.5.5 // indirect 100 | github.com/gophercloud/gophercloud v0.16.0 // indirect 101 | github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect 102 | github.com/gorilla/mux v1.8.0 // indirect 103 | github.com/gorilla/websocket v1.5.0 // indirect 104 | github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect 105 | github.com/hashicorp/consul v1.10.4 // indirect 106 | github.com/hashicorp/consul/api v1.12.0 // indirect 107 | github.com/hashicorp/consul/sdk v0.8.0 // indirect 108 | github.com/hashicorp/cronexpr v1.1.1 // indirect 109 | github.com/hashicorp/errwrap v1.1.0 // indirect 110 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 111 | github.com/hashicorp/go-hclog v0.16.2 // indirect 112 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect 113 | github.com/hashicorp/go-msgpack v0.5.5 // indirect 114 | github.com/hashicorp/go-multierror v1.1.1 // indirect 115 | github.com/hashicorp/go-retryablehttp v0.7.1 // indirect 116 | github.com/hashicorp/go-rootcerts v1.0.2 // indirect 117 | github.com/hashicorp/go-sockaddr v1.0.2 // indirect 118 | github.com/hashicorp/go-uuid v1.0.2 // indirect 119 | github.com/hashicorp/go-version v1.3.0 // indirect 120 | github.com/hashicorp/golang-lru v0.5.4 // indirect 121 | github.com/hashicorp/hcl v1.0.0 // indirect 122 | github.com/hashicorp/memberlist v0.3.0 // indirect 123 | github.com/hashicorp/nomad/api v0.0.0-20220506174431-b5665129cd1f // indirect 124 | github.com/hashicorp/raft v1.3.2 // indirect 125 | github.com/hashicorp/raft-autopilot v0.1.5 // indirect 126 | github.com/hashicorp/serf v0.9.6 // indirect 127 | github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 // indirect 128 | github.com/huandu/xstrings v1.3.1 // indirect 129 | github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect 130 | github.com/imdario/mergo v0.3.12 // indirect 131 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 132 | github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect 133 | github.com/instana/go-sensor v1.38.3 // indirect 134 | github.com/jarcoal/httpmock v1.0.8 // indirect 135 | github.com/jcchavezs/porto v0.1.0 // indirect 136 | github.com/jcmturner/gofork v1.0.0 // indirect 137 | github.com/jmespath/go-jmespath v0.4.0 // indirect 138 | github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect 139 | github.com/jonboulle/clockwork v0.2.2 // indirect 140 | github.com/josharian/intern v1.0.0 // indirect 141 | github.com/json-iterator/go v1.1.12 // indirect 142 | github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect 143 | github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b // indirect 144 | github.com/kvtools/valkeyrie v0.4.0 // indirect 145 | github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect 146 | github.com/labbsr0x/goh v1.0.1 // indirect 147 | github.com/linode/linodego v0.31.1 // indirect 148 | github.com/liquidweb/go-lwApi v0.0.5 // indirect 149 | github.com/liquidweb/liquidweb-cli v0.6.9 // indirect 150 | github.com/liquidweb/liquidweb-go v1.6.3 // indirect 151 | github.com/looplab/fsm v0.1.0 // indirect 152 | github.com/mailru/easyjson v0.7.7 // indirect 153 | github.com/mattn/go-colorable v0.1.11 // indirect 154 | github.com/mattn/go-isatty v0.0.14 // indirect 155 | github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect 156 | github.com/miekg/dns v1.1.47 // indirect 157 | github.com/mimuret/golang-iij-dpf v0.7.1 // indirect 158 | github.com/mitchellh/copystructure v1.0.0 // indirect 159 | github.com/mitchellh/go-homedir v1.1.0 // indirect 160 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 161 | github.com/mitchellh/mapstructure v1.4.3 // indirect 162 | github.com/mitchellh/reflectwalk v1.0.1 // indirect 163 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 164 | github.com/modern-go/reflect2 v1.0.2 // indirect 165 | github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect 166 | github.com/nrdcg/auroradns v1.0.1 // indirect 167 | github.com/nrdcg/desec v0.6.0 // indirect 168 | github.com/nrdcg/dnspod-go v0.4.0 // indirect 169 | github.com/nrdcg/freemyip v0.2.0 // indirect 170 | github.com/nrdcg/goinwx v0.8.1 // indirect 171 | github.com/nrdcg/namesilo v0.2.1 // indirect 172 | github.com/nrdcg/porkbun v0.1.1 // indirect 173 | github.com/opencontainers/go-digest v1.0.0 // indirect 174 | github.com/opencontainers/image-spec v1.0.2 // indirect 175 | github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect 176 | github.com/opentracing/opentracing-go v1.2.0 // indirect 177 | github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 // indirect 178 | github.com/openzipkin/zipkin-go v0.2.2 // indirect 179 | github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect 180 | github.com/ovh/go-ovh v1.1.0 // indirect 181 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 182 | github.com/philhofer/fwd v1.1.1 // indirect 183 | github.com/pires/go-proxyproto v0.6.1 // indirect 184 | github.com/pkg/errors v0.9.1 // indirect 185 | github.com/pmezard/go-difflib v1.0.0 // indirect 186 | github.com/pquerna/otp v1.3.0 // indirect 187 | github.com/prometheus/client_golang v1.11.0 // indirect 188 | github.com/prometheus/client_model v0.2.0 // indirect 189 | github.com/prometheus/common v0.26.0 // indirect 190 | github.com/prometheus/procfs v0.6.0 // indirect 191 | github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac // indirect 192 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 193 | github.com/sacloud/libsacloud v1.36.2 // indirect 194 | github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect 195 | github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f // indirect 196 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect 197 | github.com/shopspring/decimal v1.2.0 // indirect 198 | github.com/sirupsen/logrus v1.8.1 // indirect 199 | github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect 200 | github.com/softlayer/softlayer-go v1.0.3 // indirect 201 | github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect 202 | github.com/spf13/cast v1.3.1 // indirect 203 | github.com/spf13/pflag v1.0.5 // indirect 204 | github.com/stretchr/objx v0.4.0 // indirect 205 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.287 // indirect 206 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.287 // indirect 207 | github.com/tinylib/msgp v1.1.2 // indirect 208 | github.com/traefik/yaegi v0.13.0 // indirect 209 | github.com/transip/gotransip/v6 v6.6.1 // indirect 210 | github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect 211 | github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect 212 | github.com/uber/jaeger-lib v2.3.0+incompatible // indirect 213 | github.com/unrolled/render v1.0.2 // indirect 214 | github.com/vinyldns/go-vinyldns v0.9.16 // indirect 215 | github.com/vulcand/predicate v1.2.0 // indirect 216 | github.com/vultr/govultr/v2 v2.16.0 // indirect 217 | go.elastic.co/apm v1.13.1 // indirect 218 | go.elastic.co/apm/module/apmhttp v1.13.1 // indirect 219 | go.elastic.co/apm/module/apmot v1.13.1 // indirect 220 | go.elastic.co/fastjson v1.1.0 // indirect 221 | go.etcd.io/etcd/api/v3 v3.5.0 // indirect 222 | go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect 223 | go.etcd.io/etcd/client/v3 v3.5.0 // indirect 224 | go.opencensus.io v0.23.0 // indirect 225 | go.uber.org/atomic v1.7.0 // indirect 226 | go.uber.org/multierr v1.6.0 // indirect 227 | go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect 228 | go.uber.org/zap v1.18.1 // indirect 229 | golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect 230 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 231 | golang.org/x/mod v0.4.2 // indirect 232 | golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect 233 | golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect 234 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 235 | golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect 236 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 237 | golang.org/x/text v0.3.7 // indirect 238 | golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect 239 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect 240 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 241 | google.golang.org/api v0.44.0 // indirect 242 | google.golang.org/appengine v1.6.7 // indirect 243 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 244 | google.golang.org/grpc v1.38.0 // indirect 245 | google.golang.org/protobuf v1.27.1 // indirect 246 | gopkg.in/DataDog/dd-trace-go.v1 v1.38.1 // indirect 247 | gopkg.in/fsnotify.v1 v1.4.7 // indirect 248 | gopkg.in/inf.v0 v0.9.1 // indirect 249 | gopkg.in/ini.v1 v1.62.0 // indirect 250 | gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect 251 | gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect 252 | gopkg.in/jcmturner/gokrb5.v7 v7.5.0 // indirect 253 | gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect 254 | gopkg.in/ns1/ns1-go.v2 v2.6.2 // indirect 255 | gopkg.in/redis.v5 v5.2.9 // indirect 256 | gopkg.in/square/go-jose.v2 v2.6.0 // indirect 257 | gopkg.in/yaml.v3 v3.0.1 // indirect 258 | howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect 259 | k8s.io/apiextensions-apiserver v0.21.3 // indirect 260 | k8s.io/klog/v2 v2.10.0 // indirect 261 | k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e // indirect 262 | sigs.k8s.io/gateway-api v0.4.0 // indirect 263 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 264 | ) 265 | 266 | // Docker v19.03.6 267 | replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20200204220554-5f6d6f3f2203 268 | 269 | // Containous forks 270 | replace ( 271 | github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e 272 | github.com/go-check/check => github.com/containous/check v0.0.0-20170915194414-ca0bf163426a 273 | github.com/gorilla/mux => github.com/containous/mux v0.0.0-20220627093034-b2dd784e613f 274 | github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 275 | ) 276 | 277 | // ambiguous import: found package github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http in multiple modules 278 | // tencentcloud uses monorepo with multimodule but the go.mod files are incomplete. 279 | exclude github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible 280 | -------------------------------------------------------------------------------- /ingress/annotations.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/traefik/traefik-migration-tool/label" 7 | ) 8 | 9 | const ( 10 | annotationKubernetesProtocol = "ingress.kubernetes.io/protocol" 11 | annotationKubernetesRuleType = "ingress.kubernetes.io/rule-type" 12 | annotationKubernetesIngressClass = "kubernetes.io/ingress.class" 13 | annotationKubernetesFrontendEntryPoints = "ingress.kubernetes.io/frontend-entry-points" 14 | annotationKubernetesPriority = "ingress.kubernetes.io/priority" 15 | annotationKubernetesRewriteTarget = "ingress.kubernetes.io/rewrite-target" 16 | 17 | // CustomHeadersMiddleware. 18 | annotationKubernetesSSLForceHost = "ingress.kubernetes.io/ssl-force-host" 19 | annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect" 20 | annotationKubernetesHSTSMaxAge = "ingress.kubernetes.io/hsts-max-age" 21 | annotationKubernetesHSTSIncludeSubdomains = "ingress.kubernetes.io/hsts-include-subdomains" 22 | annotationKubernetesCustomRequestHeaders = "ingress.kubernetes.io/custom-request-headers" 23 | annotationKubernetesCustomResponseHeaders = "ingress.kubernetes.io/custom-response-headers" 24 | annotationKubernetesAllowedHosts = "ingress.kubernetes.io/allowed-hosts" 25 | annotationKubernetesProxyHeaders = "ingress.kubernetes.io/proxy-headers" 26 | annotationKubernetesSSLTemporaryRedirect = "ingress.kubernetes.io/ssl-temporary-redirect" 27 | annotationKubernetesSSLHost = "ingress.kubernetes.io/ssl-host" 28 | annotationKubernetesSSLProxyHeaders = "ingress.kubernetes.io/ssl-proxy-headers" 29 | annotationKubernetesHSTSPreload = "ingress.kubernetes.io/hsts-preload" 30 | annotationKubernetesForceHSTSHeader = "ingress.kubernetes.io/force-hsts" 31 | annotationKubernetesFrameDeny = "ingress.kubernetes.io/frame-deny" 32 | annotationKubernetesCustomFrameOptionsValue = "ingress.kubernetes.io/custom-frame-options-value" 33 | annotationKubernetesContentTypeNosniff = "ingress.kubernetes.io/content-type-nosniff" 34 | annotationKubernetesBrowserXSSFilter = "ingress.kubernetes.io/browser-xss-filter" 35 | annotationKubernetesCustomBrowserXSSValue = "ingress.kubernetes.io/custom-browser-xss-value" 36 | annotationKubernetesContentSecurityPolicy = "ingress.kubernetes.io/content-security-policy" 37 | annotationKubernetesPublicKey = "ingress.kubernetes.io/public-key" 38 | annotationKubernetesReferrerPolicy = "ingress.kubernetes.io/referrer-policy" 39 | annotationKubernetesIsDevelopment = "ingress.kubernetes.io/is-development" 40 | 41 | // WhitelistMiddleware. 42 | annotationKubernetesWhiteListSourceRange = "ingress.kubernetes.io/whitelist-source-range" 43 | annotationKubernetesWhiteListUseXForwardedFor = "ingress.kubernetes.io/whitelist-x-forwarded-for" 44 | 45 | // AuthMiddleware. 46 | annotationKubernetesAuthType = "ingress.kubernetes.io/auth-type" 47 | annotationKubernetesAuthHeaderField = "ingress.kubernetes.io/auth-header-field" 48 | annotationKubernetesAuthForwardResponseHeaders = "ingress.kubernetes.io/auth-response-headers" 49 | annotationKubernetesAuthRemoveHeader = "ingress.kubernetes.io/auth-remove-header" 50 | annotationKubernetesAuthForwardURL = "ingress.kubernetes.io/auth-url" 51 | annotationKubernetesAuthForwardTrustHeaders = "ingress.kubernetes.io/auth-trust-headers" 52 | annotationKubernetesAuthSecret = "ingress.kubernetes.io/auth-secret" 53 | annotationKubernetesAuthForwardTLSSecret = "ingress.kubernetes.io/auth-tls-secret" 54 | annotationKubernetesAuthForwardTLSInsecure = "ingress.kubernetes.io/auth-tls-insecure" 55 | 56 | // PassTLSCertMiddleware. 57 | annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert" // Deprecated 58 | annotationKubernetesPassTLSClientCert = "ingress.kubernetes.io/pass-client-tls-cert" 59 | 60 | // RedirectMiddleware. 61 | annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root" 62 | annotationKubernetesRedirectEntryPoint = "ingress.kubernetes.io/redirect-entry-point" 63 | annotationKubernetesRedirectPermanent = "ingress.kubernetes.io/redirect-permanent" 64 | annotationKubernetesRedirectRegex = "ingress.kubernetes.io/redirect-regex" 65 | annotationKubernetesRedirectReplacement = "ingress.kubernetes.io/redirect-replacement" 66 | 67 | // RateLimitMiddleware. 68 | annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit" 69 | 70 | // Modifiers Middlewares. 71 | annotationKubernetesRequestModifier = "ingress.kubernetes.io/request-modifier" 72 | 73 | // TODO ErrorPagesMiddleware. 74 | annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages" 75 | 76 | // TODO service annotation. 77 | 78 | // TODO BufferingMiddleware. 79 | annotationKubernetesBuffering = "ingress.kubernetes.io/buffering" 80 | 81 | // TODO CircuitBreakMiddleware. 82 | annotationKubernetesCircuitBreakerExpression = "ingress.kubernetes.io/circuit-breaker-expression" 83 | 84 | // TODO InFlightReqMiddleware. 85 | annotationKubernetesMaxConnAmount = "ingress.kubernetes.io/max-conn-amount" 86 | annotationKubernetesMaxConnExtractorFunc = "ingress.kubernetes.io/max-conn-extractor-func" 87 | 88 | annotationKubernetesResponseForwardingFlushInterval = "ingress.kubernetes.io/responseforwarding-flushinterval" 89 | annotationKubernetesLoadBalancerMethod = "ingress.kubernetes.io/load-balancer-method" 90 | 91 | // FIXME Not possible yet. 92 | annotationKubernetesPreserveHost = "ingress.kubernetes.io/preserve-host" 93 | annotationKubernetesSessionCookieName = "ingress.kubernetes.io/session-cookie-name" 94 | annotationKubernetesAffinity = "ingress.kubernetes.io/affinity" 95 | 96 | // TODO ?? 97 | annotationKubernetesAuthRealm = "ingress.kubernetes.io/auth-realm" 98 | annotationKubernetesServiceWeights = "ingress.kubernetes.io/service-weights" 99 | 100 | // FIXME global backend. 101 | ) 102 | 103 | var compatibilityMapping = map[string]string{ 104 | annotationKubernetesPreserveHost: "traefik.frontend.passHostHeader", 105 | annotationKubernetesPassTLSCert: "traefik.frontend.passTLSCert", 106 | annotationKubernetesFrontendEntryPoints: "traefik.frontend.entryPoints", 107 | annotationKubernetesPriority: "traefik.frontend.priority", 108 | annotationKubernetesCircuitBreakerExpression: "traefik.backend.circuitbreaker", 109 | annotationKubernetesLoadBalancerMethod: "traefik.backend.loadbalancer.method", 110 | annotationKubernetesAffinity: "traefik.backend.loadbalancer.stickiness", 111 | annotationKubernetesSessionCookieName: "traefik.backend.loadbalancer.stickiness.cookieName", 112 | annotationKubernetesRuleType: "traefik.frontend.rule.type", 113 | annotationKubernetesRedirectEntryPoint: "traefik.frontend.redirect.entrypoint", 114 | annotationKubernetesRedirectRegex: "traefik.frontend.redirect.regex", 115 | annotationKubernetesRedirectReplacement: "traefik.frontend.redirect.replacement", 116 | } 117 | 118 | func getAnnotationName(annotations map[string]string, name string) string { 119 | if _, ok := annotations[name]; ok { 120 | return name 121 | } 122 | 123 | if _, ok := annotations[label.Prefix+name]; ok { 124 | return label.Prefix + name 125 | } 126 | 127 | if lbl, compat := compatibilityMapping[name]; compat { 128 | if _, ok := annotations[lbl]; ok { 129 | return lbl 130 | } 131 | } 132 | 133 | return name 134 | } 135 | 136 | func getStringValue(annotations map[string]string, annotation, defaultValue string) string { 137 | annotationName := getAnnotationName(annotations, annotation) 138 | return label.GetStringValue(annotations, annotationName, defaultValue) 139 | } 140 | 141 | func getStringSafeValue(annotations map[string]string, annotation, defaultValue string) (string, error) { 142 | annotationName := getAnnotationName(annotations, annotation) 143 | value := label.GetStringValue(annotations, annotationName, defaultValue) 144 | _, err := strconv.Unquote(`"` + value + `"`) 145 | return value, err 146 | } 147 | 148 | func getBoolValue(annotations map[string]string, annotation string, defaultValue bool) bool { 149 | annotationName := getAnnotationName(annotations, annotation) 150 | return label.GetBoolValue(annotations, annotationName, defaultValue) 151 | } 152 | 153 | func getIntValue(annotations map[string]string, annotation string, defaultValue int) int { 154 | annotationName := getAnnotationName(annotations, annotation) 155 | return label.GetIntValue(annotations, annotationName, defaultValue) 156 | } 157 | 158 | func getInt64Value(annotations map[string]string, annotation string, defaultValue int64) int64 { 159 | annotationName := getAnnotationName(annotations, annotation) 160 | return label.GetInt64Value(annotations, annotationName, defaultValue) 161 | } 162 | 163 | func getSliceStringValue(annotations map[string]string, annotation string) []string { 164 | annotationName := getAnnotationName(annotations, annotation) 165 | return label.GetSliceStringValue(annotations, annotationName) 166 | } 167 | 168 | func getMapValue(annotations map[string]string, annotation string) map[string]string { 169 | annotationName := getAnnotationName(annotations, annotation) 170 | return label.GetMapValue(annotations, annotationName) 171 | } 172 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/priority: "10" 9 | spec: 10 | rules: 11 | - host: traefik.tchouk 12 | http: 13 | paths: 14 | - path: /bar 15 | backend: 16 | service: 17 | name: service1 18 | port: 19 | number: 80 20 | - path: /foo 21 | backend: 22 | service: 23 | name: service1 24 | port: 25 | number: 80 26 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_and_service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | 7 | spec: 8 | rules: 9 | - host: traefik.tchouk 10 | http: 11 | paths: 12 | - path: /bar 13 | backend: 14 | service: 15 | name: service1 16 | port: 17 | number: 80 18 | - path: /foo 19 | backend: 20 | service: 21 | name: service1 22 | port: 23 | number: 80 24 | --- 25 | kind: Service 26 | apiVersion: v1 27 | metadata: 28 | name: service1 29 | namespace: testing 30 | 31 | spec: 32 | ports: 33 | - port: 80 34 | clusterIP: 10.0.0.1 35 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_extensions.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/priority: "10" 9 | spec: 10 | rules: 11 | - host: traefik.tchouk 12 | http: 13 | paths: 14 | - path: /bar 15 | backend: 16 | serviceName: service1 17 | servicePort: 80 18 | - path: /foo 19 | backend: 20 | serviceName: service1 21 | servicePort: 80 22 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_networking_v1beta1.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/priority: "10" 9 | spec: 10 | rules: 11 | - host: traefik.tchouk 12 | http: 13 | paths: 14 | - path: /bar 15 | backend: 16 | serviceName: service1 17 | servicePort: 80 18 | - path: /foo 19 | backend: 20 | serviceName: service1 21 | servicePort: 80 22 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_redirect_approot.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/app-root: "index.html" 8 | spec: 9 | rules: 10 | - host: traefik.tchouk 11 | http: 12 | paths: 13 | - path: / 14 | backend: 15 | service: 16 | name: service1 17 | port: 18 | number: 80 19 | - host: traefik.tchouk 20 | http: 21 | paths: 22 | - path: /bar 23 | backend: 24 | service: 25 | name: service1 26 | port: 27 | number: 80 28 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_redirect_regex.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/redirect-regex: "foo" 8 | ingress.kubernetes.io/redirect-replacement: "bar" 9 | ingress.kubernetes.io/redirect-permanent: "true" 10 | spec: 11 | rules: 12 | - host: traefik.tchouk 13 | http: 14 | paths: 15 | - path: / 16 | backend: 17 | service: 18 | name: service1 19 | port: 20 | number: 80 21 | - host: traefik.tchouk 22 | http: 23 | paths: 24 | - path: /bar 25 | backend: 26 | service: 27 | name: service1 28 | port: 29 | number: 80 30 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_rewrite_target.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/rewrite-target: / 6 | namespace: testing 7 | spec: 8 | rules: 9 | - host: rewrite 10 | http: 11 | paths: 12 | - backend: 13 | service: 14 | name: service1 15 | port: 16 | number: 80 17 | path: /api 18 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_errorpage.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/error-pages: |2 6 | 7 | foo: 8 | status: 9 | - "123" 10 | - "456" 11 | backend: bar 12 | query: /bar 13 | bar: 14 | status: 15 | - "404" 16 | - "501" 17 | backend: foo 18 | query: /foo 19 | kubernetes.io/ingress.class: traefik 20 | namespace: testing 21 | spec: 22 | rules: 23 | - host: error-pages 24 | http: 25 | paths: 26 | - backend: 27 | service: 28 | name: service1 29 | port: 30 | number: 80 31 | path: /errorpages 32 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_headers_annotations.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/allowed-hosts: foo, fii, fuu 6 | ingress.kubernetes.io/browser-xss-filter: "true" 7 | ingress.kubernetes.io/content-security-policy: foo 8 | ingress.kubernetes.io/content-type-nosniff: "true" 9 | ingress.kubernetes.io/custom-browser-xss-value: foo 10 | ingress.kubernetes.io/custom-frame-options-value: foo 11 | ingress.kubernetes.io/custom-request-headers: 'Access-Control-Allow-Methods:POST,GET,OPTIONS 12 | || Content-type: application/json; charset=utf-8' 13 | ingress.kubernetes.io/custom-response-headers: 'Access-Control-Allow-Methods:POST,GET,OPTIONS 14 | || Content-type: application/json; charset=utf-8' 15 | ingress.kubernetes.io/force-hsts: "true" 16 | ingress.kubernetes.io/frame-deny: "true" 17 | ingress.kubernetes.io/hsts-include-subdomains: "true" 18 | ingress.kubernetes.io/hsts-max-age: "666" 19 | ingress.kubernetes.io/hsts-preload: "true" 20 | ingress.kubernetes.io/is-development: "true" 21 | ingress.kubernetes.io/proxy-headers: foo, fii, fuu 22 | ingress.kubernetes.io/public-key: foo 23 | ingress.kubernetes.io/referrer-policy: foo 24 | ingress.kubernetes.io/ssl-force-host: "true" 25 | ingress.kubernetes.io/ssl-host: foo 26 | ingress.kubernetes.io/ssl-proxy-headers: 'Access-Control-Allow-Methods:POST,GET,OPTIONS 27 | || Content-type: application/json; charset=utf-8' 28 | ingress.kubernetes.io/ssl-redirect: "true" 29 | ingress.kubernetes.io/ssl-temporary-redirect: "true" 30 | kubernetes.io/ingress.class: traefik 31 | namespace: testing 32 | 33 | spec: 34 | rules: 35 | - host: custom-headers 36 | http: 37 | paths: 38 | - backend: 39 | service: 40 | name: service1 41 | port: 42 | number: 80 43 | path: /customheaders 44 | 45 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_matcher.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/rule-type: "Path" 9 | spec: 10 | rules: 11 | - host: traefik.tchouk 12 | http: 13 | paths: 14 | - path: /bar 15 | backend: 16 | service: 17 | name: service1 18 | port: 19 | number: 80 20 | - path: /foo 21 | backend: 22 | service: 23 | name: service1 24 | port: 25 | number: 80 26 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_matcher_modifier.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/rule-type: "PathPrefixStrip" 9 | spec: 10 | rules: 11 | - host: traefik.tchouk 12 | http: 13 | paths: 14 | - path: /bar 15 | backend: 16 | service: 17 | name: service1 18 | port: 19 | number: 80 20 | - path: /foo 21 | backend: 22 | service: 23 | name: service1 24 | port: 25 | number: 80 26 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_middleware_name.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/frontend-entry-points: "web" 8 | ingress.kubernetes.io/rule-type: "PathPrefixStrip" 9 | spec: 10 | rules: 11 | - http: 12 | paths: 13 | - path: /bar 14 | backend: 15 | service: 16 | name: service1 17 | port: 18 | number: 80 19 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_passtlscert.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/pass-client-tls-cert: |2 6 | 7 | pem: true 8 | infos: 9 | notafter: true 10 | notbefore: true 11 | sans: true 12 | subject: 13 | country: true 14 | province: true 15 | locality: true 16 | organization: true 17 | commonname: true 18 | serialnumber: true 19 | domaincomponent: true 20 | issuer: 21 | country: true 22 | province: true 23 | locality: true 24 | organization: true 25 | commonname: true 26 | serialnumber: true 27 | domaincomponent: true 28 | ingress.kubernetes.io/pass-tls-cert: "true" 29 | kubernetes.io/ingress.class: traefik 30 | namespace: testing 31 | spec: 32 | rules: 33 | - host: other 34 | http: 35 | paths: 36 | - backend: 37 | service: 38 | name: service1 39 | port: 40 | number: 80 41 | path: /sslstuff 42 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_protocol.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/protocol: "h2c" 8 | spec: 9 | rules: 10 | - host: traefik.tchouk 11 | http: 12 | paths: 13 | - path: /bar 14 | backend: 15 | service: 16 | name: service1 17 | port: 18 | number: 80 19 | - path: /foo 20 | backend: 21 | service: 22 | name: service1 23 | port: 24 | number: 80 25 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_ratelimit.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/rate-limit: |2 6 | 7 | extractorfunc: client.ip 8 | rateset: 9 | bar: 10 | period: 3s 11 | average: 12 12 | burst: 9 13 | foo: 14 | period: 6s 15 | average: 12 16 | burst: 18 17 | kubernetes.io/ingress.class: traefik 18 | namespace: testing 19 | spec: 20 | rules: 21 | - host: rate-limit 22 | http: 23 | paths: 24 | - backend: 25 | service: 26 | name: service1 27 | port: 28 | number: 80 29 | path: /ratelimit 30 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_request_modifier.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: test 5 | namespace: testing 6 | annotations: 7 | ingress.kubernetes.io/request-modifier: "AddPrefix: toto" 8 | spec: 9 | rules: 10 | - host: traefik.tchouk 11 | http: 12 | paths: 13 | - path: /bar 14 | backend: 15 | service: 16 | name: service1 17 | port: 18 | number: 80 19 | - path: /foo 20 | backend: 21 | service: 22 | name: service1 23 | port: 24 | number: 80 25 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_whitelist.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/whitelist-source-range: 1.1.1.1/24, 1234:abcd::42/32 6 | namespace: testing 7 | spec: 8 | rules: 9 | - host: test 10 | http: 11 | paths: 12 | - backend: 13 | service: 14 | name: service1 15 | port: 16 | number: 80 17 | path: /whitelist-source-range 18 | -------------------------------------------------------------------------------- /ingress/fixtures/input/ingress_with_whitelist_xforwarded.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | ingress.kubernetes.io/whitelist-source-range: 1.1.1.1/24, 1234:abcd::42/32 6 | ingress.kubernetes.io/whitelist-x-forwarded-for: "true" 7 | namespace: testing 8 | spec: 9 | rules: 10 | - host: test 11 | http: 12 | paths: 13 | - backend: 14 | service: 15 | name: service1 16 | port: 17 | number: 80 18 | path: /whitelist-source-range-x-forwarded 19 | -------------------------------------------------------------------------------- /ingress/fixtures/input/items_ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | items: 3 | - apiVersion: extensions/v1beta1 4 | kind: Ingress 5 | metadata: 6 | annotations: 7 | ingress.kubernetes.io/auth-secret: basic-auth-document-db 8 | ingress.kubernetes.io/auth-type: basic 9 | ingress.kubernetes.io/custom-request-headers: XYZ-My-Custom-Header:dev 10 | kubernetes.io/ingress.class: traefik 11 | creationTimestamp: "2018-02-27T10:03:59Z" 12 | generation: 9 13 | name: dev-protected 14 | namespace: dev 15 | resourceVersion: "277178439" 16 | selfLink: /apis/extensions/v1beta1/namespaces/dev/ingresses/dev-protected 17 | uid: 87d8d657-1ba5-11e8-a9cd-06fa2d724cac 18 | spec: 19 | rules: 20 | - host: svc.test.migrate.traefik.to.v2.com 21 | http: 22 | paths: 23 | - backend: 24 | serviceName: v2 25 | servicePort: 80 -------------------------------------------------------------------------------- /ingress/fixtures/input/items_mix.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | items: 3 | - apiVersion: v1 4 | data: 5 | traefik.toml: | 6 | # traefik.toml 7 | logLevel = "DEBUG" 8 | debug = false 9 | sendAnonymousUsage = true 10 | defaultEntryPoints = ["http","https"] 11 | 12 | [entryPoints] 13 | [entryPoints.http] 14 | address = ":80" 15 | compress = true 16 | [entryPoints.http.redirect] 17 | regex = "^http://(.*)" 18 | replacement = "https://$1" 19 | [entryPoints.http.forwardedHeaders] 20 | trustedIPs = ["127.0.0.1/32"] 21 | [entryPoints.https] 22 | address = ":443" 23 | compress = true 24 | [entryPoints.https.forwardedHeaders] 25 | trustedIPs = ["127.0.0.1/32"] 26 | [entryPoints.https.tls] 27 | # Exclude old tls versions, whitelist known still-strong cipher suites 28 | minVersion = "VersionTLS12" 29 | cipherSuites = [ 30 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 31 | "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 32 | "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 33 | "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" 34 | ] 35 | [entryPoints.httpn] 36 | address = ":8880" 37 | compress = true 38 | [kubernetes] 39 | 40 | [traefikLog] 41 | 42 | [accessLog] 43 | 44 | [metrics] 45 | [metrics.prometheus] 46 | [metrics.statistics] 47 | 48 | [ping] 49 | 50 | [api] 51 | 52 | [retry] 53 | attempts = 2 54 | kind: ConfigMap 55 | metadata: 56 | name: traefik-config 57 | namespace: ingress 58 | 59 | - apiVersion: v1 60 | kind: Pod 61 | metadata: 62 | annotations: 63 | checksum/config: bd0bd0dafbb6f0ae3b471f35e0c73750f887121d0494eee81fb55a2e25520459 64 | cni.projectcalico.org/podIP: 10.244.7.111/32 65 | labels: 66 | name: traefik-ingress-controller 67 | name: traefik-ingress-controller-86949d84c5-p9m8w 68 | namespace: ingress 69 | spec: 70 | containers: 71 | - args: 72 | - --configfile=/config/traefik.toml 73 | image: traefik:1.7.2-alpine 74 | imagePullPolicy: Always 75 | name: traefik-ingress-controller 76 | ports: 77 | - containerPort: 80 78 | name: http 79 | protocol: TCP 80 | - containerPort: 443 81 | name: https 82 | protocol: TCP 83 | - containerPort: 8880 84 | name: httpn 85 | protocol: TCP 86 | - containerPort: 8080 87 | name: dashboard 88 | protocol: TCP 89 | volumeMounts: 90 | - mountPath: /config 91 | name: config 92 | readOnly: true 93 | dnsPolicy: ClusterFirst 94 | restartPolicy: Always 95 | volumes: 96 | - configMap: 97 | defaultMode: 420 98 | name: traefik-config 99 | name: config 100 | 101 | - apiVersion: extensions/v1beta1 102 | kind: Ingress 103 | metadata: 104 | annotations: 105 | ingress.kubernetes.io/auth-secret: basic-auth-document-db 106 | ingress.kubernetes.io/auth-type: basic 107 | ingress.kubernetes.io/custom-request-headers: XYZ-My-Custom-Header:dev 108 | kubernetes.io/ingress.class: traefik 109 | creationTimestamp: "2018-02-27T10:03:59Z" 110 | generation: 9 111 | name: dev-protected 112 | namespace: dev 113 | resourceVersion: "277178439" 114 | selfLink: /apis/extensions/v1beta1/namespaces/dev/ingresses/dev-protected 115 | uid: 87d8d657-1ba5-11e8-a9cd-06fa2d724cac 116 | spec: 117 | rules: 118 | - host: svc.test.migrate.traefik.to.v2.com 119 | http: 120 | paths: 121 | - backend: 122 | serviceName: v2 123 | servicePort: 80 -------------------------------------------------------------------------------- /ingress/fixtures/input/service_only.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Service 3 | metadata: 4 | name: service1 5 | namespace: testing 6 | 7 | spec: 8 | clusterIP: 10.0.0.1 9 | ports: 10 | - port: 80 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | priority: 10 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | priority: 10 22 | services: 23 | - kind: Service 24 | name: service1 25 | namespace: testing 26 | port: 80 27 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_extensions.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | priority: 10 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | priority: 10 22 | services: 23 | - kind: Service 24 | name: service1 25 | namespace: testing 26 | port: 80 27 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_networking_v1beta1.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | priority: 10 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | priority: 10 22 | services: 23 | - kind: Service 24 | name: service1 25 | namespace: testing 26 | port: 80 27 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_redirect_approot.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/`) 11 | middlewares: 12 | - name: redirect-17591616686595916377 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 21 | services: 22 | - kind: Service 23 | name: service1 24 | namespace: testing 25 | port: 80 26 | --- 27 | apiVersion: traefik.containo.us/v1alpha1 28 | kind: Middleware 29 | metadata: 30 | creationTimestamp: null 31 | name: redirect-17591616686595916377 32 | namespace: testing 33 | spec: 34 | redirectRegex: 35 | regex: traefik.tchouk/$ 36 | replacement: traefik.tchouk/index.html 37 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_redirect_regex.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/`) 11 | middlewares: 12 | - name: redirect-11227837511975166935 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 21 | middlewares: 22 | - name: redirect-11227837511975166935 23 | namespace: testing 24 | services: 25 | - kind: Service 26 | name: service1 27 | namespace: testing 28 | port: 80 29 | --- 30 | apiVersion: traefik.containo.us/v1alpha1 31 | kind: Middleware 32 | metadata: 33 | creationTimestamp: null 34 | name: redirect-11227837511975166935 35 | namespace: testing 36 | spec: 37 | redirectRegex: 38 | permanent: true 39 | regex: foo 40 | replacement: bar 41 | --- 42 | apiVersion: traefik.containo.us/v1alpha1 43 | kind: Middleware 44 | metadata: 45 | creationTimestamp: null 46 | name: redirect-11227837511975166935 47 | namespace: testing 48 | spec: 49 | redirectRegex: 50 | permanent: true 51 | regex: foo 52 | replacement: bar 53 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_rewrite_target.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`rewrite`) && PathPrefix(`/api`) 10 | middlewares: 11 | - name: replace-path-rewrite-api 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | --- 19 | apiVersion: traefik.containo.us/v1alpha1 20 | kind: Middleware 21 | metadata: 22 | creationTimestamp: null 23 | name: replace-path-rewrite-api 24 | namespace: testing 25 | spec: 26 | replacePathRegex: 27 | regex: ^/api(.*) 28 | replacement: $1 29 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_headers_annotations.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`custom-headers`) && PathPrefix(`/customheaders`) 12 | middlewares: 13 | - name: headers-8935542931745555077 14 | namespace: testing 15 | services: 16 | - kind: Service 17 | name: service1 18 | namespace: testing 19 | port: 80 20 | --- 21 | apiVersion: traefik.containo.us/v1alpha1 22 | kind: Middleware 23 | metadata: 24 | creationTimestamp: null 25 | name: headers-8935542931745555077 26 | namespace: testing 27 | spec: 28 | headers: 29 | allowedHosts: 30 | - foo 31 | - fii 32 | - fuu 33 | browserXssFilter: true 34 | contentSecurityPolicy: foo 35 | contentTypeNosniff: true 36 | customBrowserXSSValue: foo 37 | customFrameOptionsValue: foo 38 | customRequestHeaders: 39 | Access-Control-Allow-Methods: POST,GET,OPTIONS 40 | Content-Type: application/json; charset=utf-8 41 | customResponseHeaders: 42 | Access-Control-Allow-Methods: POST,GET,OPTIONS 43 | Content-Type: application/json; charset=utf-8 44 | forceSTSHeader: true 45 | frameDeny: true 46 | hostsProxyHeaders: 47 | - foo 48 | - fii 49 | - fuu 50 | isDevelopment: true 51 | publicKey: foo 52 | referrerPolicy: foo 53 | sslForceHost: true 54 | sslHost: foo 55 | sslProxyHeaders: 56 | Access-Control-Allow-Methods: POST,GET,OPTIONS 57 | Content-Type: application/json; charset=utf-8 58 | sslRedirect: true 59 | sslTemporaryRedirect: true 60 | stsIncludeSubdomains: true 61 | stsPreload: true 62 | stsSeconds: 666 63 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_matcher.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && Path(`/bar`) 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | - kind: Rule 19 | match: Host(`traefik.tchouk`) && Path(`/foo`) 20 | services: 21 | - kind: Service 22 | name: service1 23 | namespace: testing 24 | port: 80 25 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_matcher_modifier.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | middlewares: 14 | - name: traefik.tchouk-bar 15 | namespace: testing 16 | services: 17 | - kind: Service 18 | name: service1 19 | namespace: testing 20 | port: 80 21 | - kind: Rule 22 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 23 | middlewares: 24 | - name: traefik.tchouk-foo 25 | namespace: testing 26 | services: 27 | - kind: Service 28 | name: service1 29 | namespace: testing 30 | port: 80 31 | --- 32 | apiVersion: traefik.containo.us/v1alpha1 33 | kind: Middleware 34 | metadata: 35 | creationTimestamp: null 36 | name: traefik.tchouk-bar 37 | namespace: testing 38 | spec: 39 | stripPrefix: 40 | prefixes: 41 | - /bar 42 | --- 43 | apiVersion: traefik.containo.us/v1alpha1 44 | kind: Middleware 45 | metadata: 46 | creationTimestamp: null 47 | name: traefik.tchouk-foo 48 | namespace: testing 49 | spec: 50 | stripPrefix: 51 | prefixes: 52 | - /foo 53 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_middleware_name.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: PathPrefix(`/bar`) 13 | middlewares: 14 | - name: bar 15 | namespace: testing 16 | services: 17 | - kind: Service 18 | name: service1 19 | namespace: testing 20 | port: 80 21 | --- 22 | apiVersion: traefik.containo.us/v1alpha1 23 | kind: Middleware 24 | metadata: 25 | creationTimestamp: null 26 | name: bar 27 | namespace: testing 28 | spec: 29 | stripPrefix: 30 | prefixes: 31 | - /bar 32 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_passtlscert.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`other`) && PathPrefix(`/sslstuff`) 12 | middlewares: 13 | - name: passtlscert-3246125301495933582 14 | namespace: testing 15 | services: 16 | - kind: Service 17 | name: service1 18 | namespace: testing 19 | port: 80 20 | --- 21 | apiVersion: traefik.containo.us/v1alpha1 22 | kind: Middleware 23 | metadata: 24 | creationTimestamp: null 25 | name: passtlscert-3246125301495933582 26 | namespace: testing 27 | spec: 28 | passTLSClientCert: 29 | info: 30 | issuer: 31 | commonName: true 32 | country: true 33 | domainComponent: true 34 | locality: true 35 | organization: true 36 | province: true 37 | serialNumber: true 38 | notAfter: true 39 | notBefore: true 40 | sans: true 41 | subject: 42 | commonName: true 43 | country: true 44 | domainComponent: true 45 | locality: true 46 | organization: true 47 | province: true 48 | serialNumber: true 49 | pem: true 50 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_protocol.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 11 | services: 12 | - kind: Service 13 | name: service1 14 | namespace: testing 15 | port: 80 16 | scheme: h2c 17 | - kind: Rule 18 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 19 | services: 20 | - kind: Service 21 | name: service1 22 | namespace: testing 23 | port: 80 24 | scheme: h2c 25 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_ratelimit.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`rate-limit`) && PathPrefix(`/ratelimit`) 12 | middlewares: 13 | - name: middleware-bar-866989432264405247 14 | namespace: testing 15 | - name: middleware-foo-12133503655065674466 16 | namespace: testing 17 | services: 18 | - kind: Service 19 | name: service1 20 | namespace: testing 21 | port: 80 22 | --- 23 | apiVersion: traefik.containo.us/v1alpha1 24 | kind: Middleware 25 | metadata: 26 | creationTimestamp: null 27 | name: middleware-bar-866989432264405247 28 | namespace: testing 29 | spec: 30 | rateLimit: 31 | average: 4 32 | burst: 9 33 | --- 34 | apiVersion: traefik.containo.us/v1alpha1 35 | kind: Middleware 36 | metadata: 37 | creationTimestamp: null 38 | name: middleware-foo-12133503655065674466 39 | namespace: testing 40 | spec: 41 | rateLimit: 42 | average: 2 43 | burst: 18 44 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_request_modifier.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 11 | middlewares: 12 | - name: requestmodifier-8146275261313797339 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | middlewares: 22 | - name: requestmodifier-8146275261313797339 23 | namespace: testing 24 | services: 25 | - kind: Service 26 | name: service1 27 | namespace: testing 28 | port: 80 29 | --- 30 | apiVersion: traefik.containo.us/v1alpha1 31 | kind: Middleware 32 | metadata: 33 | creationTimestamp: null 34 | name: requestmodifier-8146275261313797339 35 | namespace: testing 36 | spec: 37 | addPrefix: 38 | prefix: toto 39 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_whitelist.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`test`) && PathPrefix(`/whitelist-source-range`) 10 | middlewares: 11 | - name: whitelist-18383239725786710617 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | --- 19 | apiVersion: traefik.containo.us/v1alpha1 20 | kind: Middleware 21 | metadata: 22 | creationTimestamp: null 23 | name: whitelist-18383239725786710617 24 | namespace: testing 25 | spec: 26 | ipWhiteList: 27 | sourceRange: 28 | - 1.1.1.1/24 29 | - 1234:abcd::42/32 30 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/ingress_with_whitelist_xforwarded.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`test`) && PathPrefix(`/whitelist-source-range-x-forwarded`) 10 | middlewares: 11 | - name: whitelist-7070660606098377859 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | --- 19 | apiVersion: traefik.containo.us/v1alpha1 20 | kind: Middleware 21 | metadata: 22 | creationTimestamp: null 23 | name: whitelist-7070660606098377859 24 | namespace: testing 25 | spec: 26 | ipWhiteList: 27 | ipStrategy: {} 28 | sourceRange: 29 | - 1.1.1.1/24 30 | - 1234:abcd::42/32 31 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/items_ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | name: dev-protected 8 | namespace: dev 9 | spec: 10 | routes: 11 | - kind: Rule 12 | match: Host(`svc.test.migrate.traefik.to.v2.com`) 13 | middlewares: 14 | - name: auth-11564652807627220706 15 | namespace: dev 16 | - name: headers-8031222136039699794 17 | namespace: dev 18 | services: 19 | - kind: Service 20 | name: v2 21 | namespace: dev 22 | port: 80 23 | --- 24 | apiVersion: traefik.containo.us/v1alpha1 25 | kind: Middleware 26 | metadata: 27 | creationTimestamp: null 28 | name: auth-11564652807627220706 29 | namespace: dev 30 | spec: 31 | basicAuth: 32 | secret: basic-auth-document-db 33 | --- 34 | apiVersion: traefik.containo.us/v1alpha1 35 | kind: Middleware 36 | metadata: 37 | creationTimestamp: null 38 | name: headers-8031222136039699794 39 | namespace: dev 40 | spec: 41 | headers: 42 | customRequestHeaders: 43 | Xyz-My-Custom-Header: dev 44 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertFile/items_mix.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | items: 3 | - apiVersion: v1 4 | data: 5 | traefik.toml: | 6 | # traefik.toml 7 | logLevel = "DEBUG" 8 | debug = false 9 | sendAnonymousUsage = true 10 | defaultEntryPoints = ["http","https"] 11 | 12 | [entryPoints] 13 | [entryPoints.http] 14 | address = ":80" 15 | compress = true 16 | [entryPoints.http.redirect] 17 | regex = "^http://(.*)" 18 | replacement = "https://$1" 19 | [entryPoints.http.forwardedHeaders] 20 | trustedIPs = ["127.0.0.1/32"] 21 | [entryPoints.https] 22 | address = ":443" 23 | compress = true 24 | [entryPoints.https.forwardedHeaders] 25 | trustedIPs = ["127.0.0.1/32"] 26 | [entryPoints.https.tls] 27 | # Exclude old tls versions, whitelist known still-strong cipher suites 28 | minVersion = "VersionTLS12" 29 | cipherSuites = [ 30 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 31 | "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 32 | "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 33 | "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" 34 | ] 35 | [entryPoints.httpn] 36 | address = ":8880" 37 | compress = true 38 | [kubernetes] 39 | 40 | [traefikLog] 41 | 42 | [accessLog] 43 | 44 | [metrics] 45 | [metrics.prometheus] 46 | [metrics.statistics] 47 | 48 | [ping] 49 | 50 | [api] 51 | 52 | [retry] 53 | attempts = 2 54 | kind: ConfigMap 55 | metadata: 56 | name: traefik-config 57 | namespace: ingress 58 | - apiVersion: v1 59 | kind: Pod 60 | metadata: 61 | annotations: 62 | checksum/config: bd0bd0dafbb6f0ae3b471f35e0c73750f887121d0494eee81fb55a2e25520459 63 | cni.projectcalico.org/podIP: 10.244.7.111/32 64 | labels: 65 | name: traefik-ingress-controller 66 | name: traefik-ingress-controller-86949d84c5-p9m8w 67 | namespace: ingress 68 | spec: 69 | containers: 70 | - args: 71 | - --configfile=/config/traefik.toml 72 | image: traefik:1.7.2-alpine 73 | imagePullPolicy: Always 74 | name: traefik-ingress-controller 75 | ports: 76 | - containerPort: 80 77 | name: http 78 | protocol: TCP 79 | - containerPort: 443 80 | name: https 81 | protocol: TCP 82 | - containerPort: 8880 83 | name: httpn 84 | protocol: TCP 85 | - containerPort: 8080 86 | name: dashboard 87 | protocol: TCP 88 | volumeMounts: 89 | - mountPath: /config 90 | name: config 91 | readOnly: true 92 | dnsPolicy: ClusterFirst 93 | restartPolicy: Always 94 | volumes: 95 | - configMap: 96 | defaultMode: 420 97 | name: traefik-config 98 | name: config 99 | --- 100 | apiVersion: traefik.containo.us/v1alpha1 101 | kind: IngressRoute 102 | metadata: 103 | annotations: 104 | kubernetes.io/ingress.class: traefik 105 | creationTimestamp: null 106 | name: dev-protected 107 | namespace: dev 108 | spec: 109 | routes: 110 | - kind: Rule 111 | match: Host(`svc.test.migrate.traefik.to.v2.com`) 112 | middlewares: 113 | - name: auth-11564652807627220706 114 | namespace: dev 115 | - name: headers-8031222136039699794 116 | namespace: dev 117 | services: 118 | - kind: Service 119 | name: v2 120 | namespace: dev 121 | port: 80 122 | --- 123 | apiVersion: traefik.containo.us/v1alpha1 124 | kind: Middleware 125 | metadata: 126 | creationTimestamp: null 127 | name: auth-11564652807627220706 128 | namespace: dev 129 | spec: 130 | basicAuth: 131 | secret: basic-auth-document-db 132 | --- 133 | apiVersion: traefik.containo.us/v1alpha1 134 | kind: Middleware 135 | metadata: 136 | creationTimestamp: null 137 | name: headers-8031222136039699794 138 | namespace: dev 139 | spec: 140 | headers: 141 | customRequestHeaders: 142 | Xyz-My-Custom-Header: dev 143 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | priority: 10 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | priority: 10 22 | services: 23 | - kind: Service 24 | name: service1 25 | namespace: testing 26 | port: 80 27 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_redirect_approot_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/`) 11 | middlewares: 12 | - name: redirect-17591616686595916377 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 21 | services: 22 | - kind: Service 23 | name: service1 24 | namespace: testing 25 | port: 80 26 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_redirect_approot_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: redirect-17591616686595916377 6 | namespace: testing 7 | spec: 8 | redirectRegex: 9 | regex: traefik.tchouk/$ 10 | replacement: traefik.tchouk/index.html 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_redirect_regex_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/`) 11 | middlewares: 12 | - name: redirect-11227837511975166935 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 21 | middlewares: 22 | - name: redirect-11227837511975166935 23 | namespace: testing 24 | services: 25 | - kind: Service 26 | name: service1 27 | namespace: testing 28 | port: 80 29 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_redirect_regex_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: redirect-11227837511975166935 6 | namespace: testing 7 | spec: 8 | redirectRegex: 9 | permanent: true 10 | regex: foo 11 | replacement: bar 12 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_redirect_regex_03.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: redirect-11227837511975166935 6 | namespace: testing 7 | spec: 8 | redirectRegex: 9 | permanent: true 10 | regex: foo 11 | replacement: bar 12 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_rewrite_target_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`rewrite`) && PathPrefix(`/api`) 10 | middlewares: 11 | - name: replace-path-rewrite-api 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_rewrite_target_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: replace-path-rewrite-api 6 | namespace: testing 7 | spec: 8 | replacePathRegex: 9 | regex: ^/api(.*) 10 | replacement: $1 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_headers_annotations_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`custom-headers`) && PathPrefix(`/customheaders`) 12 | middlewares: 13 | - name: headers-8935542931745555077 14 | namespace: testing 15 | services: 16 | - kind: Service 17 | name: service1 18 | namespace: testing 19 | port: 80 20 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_headers_annotations_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: headers-8935542931745555077 6 | namespace: testing 7 | spec: 8 | headers: 9 | allowedHosts: 10 | - foo 11 | - fii 12 | - fuu 13 | browserXssFilter: true 14 | contentSecurityPolicy: foo 15 | contentTypeNosniff: true 16 | customBrowserXSSValue: foo 17 | customFrameOptionsValue: foo 18 | customRequestHeaders: 19 | Access-Control-Allow-Methods: POST,GET,OPTIONS 20 | Content-Type: application/json; charset=utf-8 21 | customResponseHeaders: 22 | Access-Control-Allow-Methods: POST,GET,OPTIONS 23 | Content-Type: application/json; charset=utf-8 24 | forceSTSHeader: true 25 | frameDeny: true 26 | hostsProxyHeaders: 27 | - foo 28 | - fii 29 | - fuu 30 | isDevelopment: true 31 | publicKey: foo 32 | referrerPolicy: foo 33 | sslForceHost: true 34 | sslHost: foo 35 | sslProxyHeaders: 36 | Access-Control-Allow-Methods: POST,GET,OPTIONS 37 | Content-Type: application/json; charset=utf-8 38 | sslRedirect: true 39 | sslTemporaryRedirect: true 40 | stsIncludeSubdomains: true 41 | stsPreload: true 42 | stsSeconds: 666 43 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_matcher_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && Path(`/bar`) 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | - kind: Rule 19 | match: Host(`traefik.tchouk`) && Path(`/foo`) 20 | services: 21 | - kind: Service 22 | name: service1 23 | namespace: testing 24 | port: 80 25 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_matcher_modifier_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | entryPoints: 9 | - web 10 | routes: 11 | - kind: Rule 12 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 13 | middlewares: 14 | - name: traefik.tchouk-bar 15 | namespace: testing 16 | services: 17 | - kind: Service 18 | name: service1 19 | namespace: testing 20 | port: 80 21 | - kind: Rule 22 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 23 | middlewares: 24 | - name: traefik.tchouk-foo 25 | namespace: testing 26 | services: 27 | - kind: Service 28 | name: service1 29 | namespace: testing 30 | port: 80 31 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_matcher_modifier_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: traefik.tchouk-bar 6 | namespace: testing 7 | spec: 8 | stripPrefix: 9 | prefixes: 10 | - /bar 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_matcher_modifier_03.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: traefik.tchouk-foo 6 | namespace: testing 7 | spec: 8 | stripPrefix: 9 | prefixes: 10 | - /foo 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_passtlscert_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`other`) && PathPrefix(`/sslstuff`) 12 | middlewares: 13 | - name: passtlscert-3246125301495933582 14 | namespace: testing 15 | services: 16 | - kind: Service 17 | name: service1 18 | namespace: testing 19 | port: 80 20 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_passtlscert_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: passtlscert-3246125301495933582 6 | namespace: testing 7 | spec: 8 | passTLSClientCert: 9 | info: 10 | issuer: 11 | commonName: true 12 | country: true 13 | domainComponent: true 14 | locality: true 15 | organization: true 16 | province: true 17 | serialNumber: true 18 | notAfter: true 19 | notBefore: true 20 | sans: true 21 | subject: 22 | commonName: true 23 | country: true 24 | domainComponent: true 25 | locality: true 26 | organization: true 27 | province: true 28 | serialNumber: true 29 | pem: true 30 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_protocol_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 11 | services: 12 | - kind: Service 13 | name: service1 14 | namespace: testing 15 | port: 80 16 | scheme: h2c 17 | - kind: Rule 18 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 19 | services: 20 | - kind: Service 21 | name: service1 22 | namespace: testing 23 | port: 80 24 | scheme: h2c 25 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_ratelimit_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: traefik 6 | creationTimestamp: null 7 | namespace: testing 8 | spec: 9 | routes: 10 | - kind: Rule 11 | match: Host(`rate-limit`) && PathPrefix(`/ratelimit`) 12 | middlewares: 13 | - name: middleware-bar-866989432264405247 14 | namespace: testing 15 | - name: middleware-foo-12133503655065674466 16 | namespace: testing 17 | services: 18 | - kind: Service 19 | name: service1 20 | namespace: testing 21 | port: 80 22 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_ratelimit_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: middleware-bar-866989432264405247 6 | namespace: testing 7 | spec: 8 | rateLimit: 9 | average: 4 10 | burst: 9 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_ratelimit_03.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: middleware-foo-12133503655065674466 6 | namespace: testing 7 | spec: 8 | rateLimit: 9 | average: 2 10 | burst: 18 11 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_request_modifier_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | name: test 6 | namespace: testing 7 | spec: 8 | routes: 9 | - kind: Rule 10 | match: Host(`traefik.tchouk`) && PathPrefix(`/bar`) 11 | middlewares: 12 | - name: requestmodifier-8146275261313797339 13 | namespace: testing 14 | services: 15 | - kind: Service 16 | name: service1 17 | namespace: testing 18 | port: 80 19 | - kind: Rule 20 | match: Host(`traefik.tchouk`) && PathPrefix(`/foo`) 21 | middlewares: 22 | - name: requestmodifier-8146275261313797339 23 | namespace: testing 24 | services: 25 | - kind: Service 26 | name: service1 27 | namespace: testing 28 | port: 80 29 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_request_modifier_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: requestmodifier-8146275261313797339 6 | namespace: testing 7 | spec: 8 | addPrefix: 9 | prefix: toto 10 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_whitelist_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`test`) && PathPrefix(`/whitelist-source-range`) 10 | middlewares: 11 | - name: whitelist-18383239725786710617 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_whitelist_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: whitelist-18383239725786710617 6 | namespace: testing 7 | spec: 8 | ipWhiteList: 9 | sourceRange: 10 | - 1.1.1.1/24 11 | - 1234:abcd::42/32 12 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_whitelist_xforwarded_01.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: IngressRoute 3 | metadata: 4 | creationTimestamp: null 5 | namespace: testing 6 | spec: 7 | routes: 8 | - kind: Rule 9 | match: Host(`test`) && PathPrefix(`/whitelist-source-range-x-forwarded`) 10 | middlewares: 11 | - name: whitelist-7070660606098377859 12 | namespace: testing 13 | services: 14 | - kind: Service 15 | name: service1 16 | namespace: testing 17 | port: 80 18 | -------------------------------------------------------------------------------- /ingress/fixtures/output_convertIngress/ingress_with_whitelist_xforwarded_02.yml: -------------------------------------------------------------------------------- 1 | apiVersion: traefik.containo.us/v1alpha1 2 | kind: Middleware 3 | metadata: 4 | creationTimestamp: null 5 | name: whitelist-7070660606098377859 6 | namespace: testing 7 | spec: 8 | ipWhiteList: 9 | ipStrategy: {} 10 | sourceRange: 11 | - 1.1.1.1/24 12 | - 1234:abcd::42/32 13 | -------------------------------------------------------------------------------- /ingress/ingress.go: -------------------------------------------------------------------------------- 1 | // Package ingress convert Ingress to IngressRoute. 2 | package ingress 3 | 4 | import ( 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "sort" 10 | "strings" 11 | "unicode" 12 | 13 | "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1" 14 | extv1beta1 "k8s.io/api/extensions/v1beta1" 15 | netv1 "k8s.io/api/networking/v1" 16 | netv1beta1 "k8s.io/api/networking/v1beta1" 17 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 19 | "k8s.io/apimachinery/pkg/runtime" 20 | "k8s.io/apimachinery/pkg/util/intstr" 21 | "sigs.k8s.io/yaml" 22 | ) 23 | 24 | const separator = "---" 25 | 26 | const groupSuffix = "/v1alpha1" 27 | 28 | const ( 29 | ruleTypePath = "Path" 30 | ruleTypePathPrefix = "PathPrefix" 31 | ruleTypePathStrip = "PathStrip" 32 | ruleTypePathPrefixStrip = "PathPrefixStrip" 33 | ruleTypeAddPrefix = "AddPrefix" 34 | ruleTypeReplacePath = "ReplacePath" 35 | ruleTypeReplacePathRegex = "ReplacePathRegex" 36 | ) 37 | 38 | // Convert converts all ingress in a src into a dstDir. 39 | func Convert(src, dstDir string) error { 40 | info, err := os.Stat(src) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | if !info.IsDir() { 46 | filename := info.Name() 47 | srcPath := filepath.Dir(src) 48 | return convertFile(srcPath, dstDir, filename) 49 | } 50 | 51 | dir := info.Name() 52 | infos, err := os.ReadDir(src) 53 | if err != nil { 54 | return err 55 | } 56 | 57 | for _, info := range infos { 58 | newSrc := filepath.Join(src, info.Name()) 59 | newDst := filepath.Join(dstDir, dir) 60 | err := Convert(newSrc, newDst) 61 | if err != nil { 62 | return err 63 | } 64 | } 65 | return nil 66 | } 67 | 68 | func convertFile(srcDir, dstDir, filename string) error { 69 | content, err := expandFileContent(filepath.Join(srcDir, filename)) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | err = os.MkdirAll(dstDir, 0o755) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | parts := strings.Split(string(content), separator) 80 | var fragments []string 81 | for _, part := range parts { 82 | if part == "\n" || part == "" { 83 | continue 84 | } 85 | 86 | unstruct, err := createUnstructured([]byte(part)) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | if unstruct.IsList() { 92 | fragments = append(fragments, part) 93 | continue 94 | } 95 | 96 | object, err := parseYaml([]byte(part)) 97 | if err != nil { 98 | log.Printf("err while reading yaml: %v", err) 99 | fragments = append(fragments, part) 100 | continue 101 | } 102 | 103 | var ingress *netv1.Ingress 104 | switch obj := object.(type) { 105 | case *extv1beta1.Ingress: 106 | ingress, err = extensionsToNetworkingV1(obj) 107 | if err != nil { 108 | return err 109 | } 110 | case *netv1beta1.Ingress: 111 | ingress, err = networkingV1beta1ToV1(obj) 112 | if err != nil { 113 | return err 114 | } 115 | case *netv1.Ingress: 116 | ingress = obj 117 | default: 118 | log.Printf("the object is skipped because is not an Ingress: %T", object) 119 | fragments = append(fragments, part) 120 | continue 121 | } 122 | 123 | objects := convertIngress(ingress) 124 | for _, object := range objects { 125 | yml, err := encodeYaml(object, v1alpha1.GroupName+groupSuffix) 126 | if err != nil { 127 | return err 128 | } 129 | fragments = append(fragments, yml) 130 | } 131 | } 132 | 133 | return os.WriteFile(filepath.Join(dstDir, filename), []byte(strings.Join(fragments, separator+"\n")), 0o666) 134 | } 135 | 136 | func expandFileContent(filePath string) ([]byte, error) { 137 | content, err := os.ReadFile(filePath) 138 | if err != nil { 139 | return nil, err 140 | } 141 | 142 | parts := strings.Split(string(content), separator) 143 | var fragments []string 144 | for _, part := range parts { 145 | if part == "\n" || part == "" { 146 | continue 147 | } 148 | 149 | listObj, err := createUnstructured(content) 150 | if err != nil { 151 | return nil, err 152 | } 153 | 154 | if !listObj.IsList() { 155 | fragments = append(fragments, part) 156 | continue 157 | } 158 | 159 | items, _, err := unstructured.NestedSlice(listObj.Object, "items") 160 | if err != nil { 161 | return nil, err 162 | } 163 | 164 | toKeep, toConvert := extractItems(items) 165 | 166 | if len(items) == len(toKeep) { 167 | fragments = append(fragments, part) 168 | continue 169 | } 170 | 171 | if len(toKeep) > 0 { 172 | newObj := listObj.DeepCopy() 173 | 174 | err = unstructured.SetNestedSlice(newObj.Object, toKeep, "items") 175 | if err != nil { 176 | return nil, err 177 | } 178 | 179 | m, err := yaml.Marshal(newObj) 180 | if err != nil { 181 | return nil, err 182 | } 183 | 184 | fragments = append(fragments, string(m)) 185 | } 186 | 187 | for _, elt := range toConvert { 188 | m, err := yaml.Marshal(elt.Object) 189 | if err != nil { 190 | return nil, err 191 | } 192 | fragments = append(fragments, string(m)) 193 | } 194 | } 195 | 196 | return []byte(strings.Join(fragments, separator+"\n")), nil 197 | } 198 | 199 | func createUnstructured(content []byte) (*unstructured.Unstructured, error) { 200 | listObj := &unstructured.Unstructured{Object: map[string]interface{}{}} 201 | 202 | if err := yaml.Unmarshal(content, &listObj.Object); err != nil { 203 | return nil, fmt.Errorf("error decoding YAML: %w\noriginal YAML: %s", err, string(content)) 204 | } 205 | 206 | return listObj, nil 207 | } 208 | 209 | func extractItems(items []interface{}) ([]interface{}, []unstructured.Unstructured) { 210 | var toKeep []interface{} 211 | var toConvert []unstructured.Unstructured 212 | 213 | for _, elt := range items { 214 | obj := unstructured.Unstructured{Object: elt.(map[string]interface{})} 215 | apiVersion := obj.GetAPIVersion() 216 | 217 | if (apiVersion == "extensions/v1beta1" || apiVersion == "networking.k8s.io/v1beta1" || apiVersion == "networking.k8s.io/v1") && obj.GetKind() == "Ingress" { 218 | toConvert = append(toConvert, obj) 219 | } else { 220 | toKeep = append(toKeep, elt) 221 | } 222 | } 223 | 224 | return toKeep, toConvert 225 | } 226 | 227 | // convertIngress converts an *networking.Ingress to a slice of runtime.Object (IngressRoute and Middlewares). 228 | func convertIngress(ingress *netv1.Ingress) []runtime.Object { 229 | logUnsupported(ingress) 230 | 231 | ingressRoute := &v1alpha1.IngressRoute{ 232 | ObjectMeta: v1.ObjectMeta{Name: ingress.GetName(), Namespace: ingress.GetNamespace(), Annotations: map[string]string{}}, 233 | Spec: v1alpha1.IngressRouteSpec{ 234 | EntryPoints: getSliceStringValue(ingress.GetAnnotations(), annotationKubernetesFrontendEntryPoints), 235 | }, 236 | } 237 | 238 | ingressClass := getStringValue(ingress.GetAnnotations(), annotationKubernetesIngressClass, "") 239 | if len(ingressClass) > 0 { 240 | ingressRoute.GetAnnotations()[annotationKubernetesIngressClass] = ingressClass 241 | } 242 | 243 | var middlewares []*v1alpha1.Middleware 244 | 245 | // Headers middleware 246 | headers := getHeadersMiddleware(ingress) 247 | if headers != nil { 248 | middlewares = append(middlewares, headers) 249 | } 250 | 251 | // Auth middleware 252 | auth := getAuthMiddleware(ingress) 253 | if auth != nil { 254 | middlewares = append(middlewares, auth) 255 | } 256 | 257 | // Whitelist middleware 258 | whiteList := getWhiteList(ingress) 259 | if whiteList != nil { 260 | middlewares = append(middlewares, whiteList) 261 | } 262 | 263 | // PassTLSCert middleware 264 | passTLSCert := getPassTLSClientCert(ingress) 265 | if passTLSCert != nil { 266 | middlewares = append(middlewares, passTLSCert) 267 | } 268 | 269 | // rateLimit middleware 270 | middlewares = append(middlewares, getRateLimit(ingress)...) 271 | 272 | requestModifier := getStringValue(ingress.GetAnnotations(), annotationKubernetesRequestModifier, "") 273 | if requestModifier != "" { 274 | middleware, err := parseRequestModifier(ingress.GetNamespace(), requestModifier) 275 | if err != nil { 276 | log.Printf("Invalid %s: %v", annotationKubernetesRequestModifier, err) 277 | } 278 | 279 | middlewares = append(middlewares, middleware) 280 | } 281 | 282 | var miRefs []v1alpha1.MiddlewareRef 283 | for _, mi := range middlewares { 284 | miRefs = append(miRefs, toRef(mi)) 285 | } 286 | 287 | routes, mis, err := createRoutes(ingress.GetNamespace(), ingress.Spec.Rules, ingress.GetAnnotations(), miRefs) 288 | if err != nil { 289 | log.Println(err) 290 | return nil 291 | } 292 | ingressRoute.Spec.Routes = routes 293 | 294 | middlewares = append(middlewares, mis...) 295 | 296 | sort.Slice(middlewares, func(i, j int) bool { return middlewares[i].Name < middlewares[j].Name }) 297 | 298 | objects := []runtime.Object{ingressRoute} 299 | for _, middleware := range middlewares { 300 | objects = append(objects, middleware) 301 | } 302 | 303 | return objects 304 | } 305 | 306 | func createRoutes(namespace string, rules []netv1.IngressRule, annotations map[string]string, middlewareRefs []v1alpha1.MiddlewareRef) ([]v1alpha1.Route, []*v1alpha1.Middleware, error) { 307 | ruleType, stripPrefix, err := extractRuleType(annotations) 308 | if err != nil { 309 | return nil, nil, err 310 | } 311 | 312 | var mis []*v1alpha1.Middleware 313 | 314 | var routes []v1alpha1.Route 315 | 316 | for _, rule := range rules { 317 | for _, path := range rule.HTTP.Paths { 318 | miRefs := make([]v1alpha1.MiddlewareRef, 0, 1) 319 | miRefs = append(miRefs, middlewareRefs...) 320 | 321 | var rules []string 322 | 323 | if len(rule.Host) > 0 { 324 | rules = append(rules, fmt.Sprintf("Host(`%s`)", rule.Host)) 325 | } 326 | 327 | if len(path.Path) > 0 { 328 | rules = append(rules, fmt.Sprintf("%s(`%s`)", ruleType, path.Path)) 329 | 330 | if stripPrefix { 331 | mi := getStripPrefix(path, rule.Host+path.Path, namespace) 332 | mis = append(mis, mi) 333 | miRefs = append(miRefs, toRef(mi)) 334 | } 335 | 336 | rewriteTarget := getStringValue(annotations, annotationKubernetesRewriteTarget, "") 337 | if rewriteTarget != "" { 338 | if ruleType == ruleTypeReplacePath { 339 | return nil, nil, fmt.Errorf("rewrite-target must not be used together with annotation %q", annotationKubernetesRuleType) 340 | } 341 | 342 | mi := getReplacePathRegex(rule, path, namespace, rewriteTarget) 343 | mis = append(mis, mi) 344 | miRefs = append(miRefs, toRef(mi)) 345 | } 346 | } 347 | 348 | redirect := getFrontendRedirect(namespace, annotations, rule.Host+path.Path, path.Path) 349 | if redirect != nil { 350 | mis = append(mis, redirect) 351 | miRefs = append(miRefs, toRef(redirect)) 352 | } 353 | 354 | if len(rules) > 0 { 355 | sort.Slice(miRefs, func(i, j int) bool { return miRefs[i].Name < miRefs[j].Name }) 356 | 357 | routes = append(routes, v1alpha1.Route{ 358 | Match: strings.Join(rules, " && "), 359 | Kind: "Rule", 360 | Priority: getIntValue(annotations, annotationKubernetesPriority, 0), 361 | Services: []v1alpha1.Service{ 362 | { 363 | LoadBalancerSpec: v1alpha1.LoadBalancerSpec{ 364 | Name: path.Backend.Service.Name, 365 | Namespace: namespace, 366 | Kind: "Service", 367 | Port: toPort(path.Backend.Service.Port), 368 | Scheme: getStringValue(annotations, annotationKubernetesProtocol, ""), 369 | }, 370 | }, 371 | }, 372 | Middlewares: miRefs, 373 | }) 374 | } 375 | } 376 | } 377 | 378 | return routes, mis, nil 379 | } 380 | 381 | func extractRuleType(annotations map[string]string) (string, bool, error) { 382 | var stripPrefix bool 383 | ruleType := getStringValue(annotations, annotationKubernetesRuleType, ruleTypePathPrefix) 384 | 385 | switch ruleType { 386 | case ruleTypePath, ruleTypePathPrefix: 387 | case ruleTypePathStrip: 388 | ruleType = ruleTypePath 389 | stripPrefix = true 390 | case ruleTypePathPrefixStrip: 391 | ruleType = ruleTypePathPrefix 392 | stripPrefix = true 393 | case ruleTypeReplacePath: 394 | log.Printf("Using %s as %s will be deprecated in the future. Please use the %s annotation instead", ruleType, annotationKubernetesRuleType, annotationKubernetesRequestModifier) 395 | default: 396 | return "", false, fmt.Errorf("cannot use non-matcher rule: %q", ruleType) 397 | } 398 | 399 | return ruleType, stripPrefix, nil 400 | } 401 | 402 | func toRef(mi *v1alpha1.Middleware) v1alpha1.MiddlewareRef { 403 | return v1alpha1.MiddlewareRef{ 404 | Name: mi.Name, 405 | Namespace: mi.Namespace, 406 | } 407 | } 408 | 409 | func toPort(p netv1.ServiceBackendPort) intstr.IntOrString { 410 | if p.Name != "" { 411 | return intstr.FromString(p.Name) 412 | } 413 | 414 | return intstr.FromInt(int(p.Number)) 415 | } 416 | 417 | func logUnsupported(ingress *netv1.Ingress) { 418 | unsupportedAnnotations := map[string]string{ 419 | annotationKubernetesErrorPages: "See https://docs.traefik.io/middlewares/errorpages/", 420 | annotationKubernetesBuffering: "See https://docs.traefik.io/middlewares/buffering/", 421 | annotationKubernetesCircuitBreakerExpression: "See https://docs.traefik.io/middlewares/circuitbreaker/", 422 | annotationKubernetesMaxConnAmount: "See https://docs.traefik.io/middlewares/inflightreq/", 423 | annotationKubernetesMaxConnExtractorFunc: "See https://docs.traefik.io/middlewares/inflightreq/", 424 | annotationKubernetesResponseForwardingFlushInterval: "See https://docs.traefik.io/providers/kubernetes-crd/", 425 | annotationKubernetesLoadBalancerMethod: "See https://docs.traefik.io/providers/kubernetes-crd/", 426 | annotationKubernetesPreserveHost: "See https://docs.traefik.io/providers/kubernetes-crd/", 427 | annotationKubernetesSessionCookieName: "Not supported yet.", 428 | annotationKubernetesAffinity: "Not supported yet.", 429 | annotationKubernetesAuthRealm: "See https://docs.traefik.io/middlewares/basicauth/", 430 | annotationKubernetesServiceWeights: "See https://docs.traefik.io/providers/kubernetes-crd/", 431 | } 432 | 433 | for annot, msg := range unsupportedAnnotations { 434 | if getStringValue(ingress.GetAnnotations(), annot, "") != "" { 435 | fmt.Printf("%s/%s: The annotation %s must be converted manually. %s", ingress.GetNamespace(), ingress.GetName(), annot, msg) 436 | } 437 | } 438 | } 439 | 440 | // https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 441 | func normalizeObjectName(name string) string { 442 | fn := func(c rune) bool { 443 | return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '-' 444 | } 445 | 446 | return strings.Join(strings.FieldsFunc(name, fn), "-") 447 | } 448 | -------------------------------------------------------------------------------- /ingress/ingress_test.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | "github.com/stretchr/testify/require" 14 | "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1" 15 | netv1 "k8s.io/api/networking/v1" 16 | ) 17 | 18 | var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata") 19 | 20 | func Test_convertIngress(t *testing.T) { 21 | testCases := []struct { 22 | ingressFile string 23 | objectCount int 24 | }{ 25 | { 26 | ingressFile: "ingress.yml", 27 | objectCount: 1, 28 | }, 29 | { 30 | ingressFile: "ingress_with_protocol.yml", 31 | objectCount: 1, 32 | }, 33 | { 34 | ingressFile: "ingress_with_matcher.yml", 35 | objectCount: 1, 36 | }, 37 | { 38 | ingressFile: "ingress_with_matcher_modifier.yml", 39 | objectCount: 3, 40 | }, 41 | { 42 | ingressFile: "ingress_with_headers_annotations.yml", 43 | objectCount: 2, 44 | }, 45 | { 46 | ingressFile: "ingress_rewrite_target.yml", 47 | objectCount: 2, 48 | }, 49 | { 50 | ingressFile: "ingress_with_whitelist.yml", 51 | objectCount: 2, 52 | }, 53 | { 54 | ingressFile: "ingress_with_whitelist_xforwarded.yml", 55 | objectCount: 2, 56 | }, 57 | { 58 | ingressFile: "ingress_with_passtlscert.yml", 59 | objectCount: 2, 60 | }, 61 | { 62 | ingressFile: "ingress_redirect_approot.yml", 63 | objectCount: 2, 64 | }, 65 | { 66 | ingressFile: "ingress_redirect_regex.yml", 67 | objectCount: 3, 68 | }, 69 | // FIXME errorPages middleware 70 | // { 71 | // ingressFile: "ingress_with_errorpage.yml", 72 | // objectCount: 3, 73 | // }, 74 | { 75 | ingressFile: "ingress_with_ratelimit.yml", 76 | objectCount: 3, 77 | }, 78 | { 79 | ingressFile: "ingress_with_request_modifier.yml", 80 | objectCount: 2, 81 | }, 82 | } 83 | 84 | outputDir := filepath.Join("fixtures", "output_convertIngress") 85 | if *updateExpected { 86 | require.NoError(t, os.RemoveAll(outputDir)) 87 | require.NoError(t, os.MkdirAll(outputDir, 0o755)) 88 | } 89 | 90 | for _, test := range testCases { 91 | t.Run(test.ingressFile, func(t *testing.T) { 92 | bytes, err := os.ReadFile(filepath.Join("fixtures", "input", test.ingressFile)) 93 | require.NoError(t, err) 94 | 95 | object, err := parseYaml(bytes) 96 | require.NoError(t, err) 97 | 98 | objects := convertIngress(object.(*netv1.Ingress)) 99 | 100 | if !*updateExpected { 101 | require.Len(t, objects, test.objectCount) 102 | } 103 | 104 | for i, object := range objects { 105 | s, err := encodeYaml(object, v1alpha1.GroupName+groupSuffix) 106 | require.NoError(t, err) 107 | 108 | filename := fmt.Sprintf("%s_%.2d.yml", strings.TrimSuffix(filepath.Base(test.ingressFile), filepath.Ext(test.ingressFile)), i+1) 109 | fixtureFile := filepath.Join(outputDir, filename) 110 | 111 | if *updateExpected { 112 | require.NoError(t, os.WriteFile(fixtureFile, []byte(s), 0o666)) 113 | } 114 | 115 | file, err := os.ReadFile(fixtureFile) 116 | require.NoError(t, err) 117 | 118 | assert.YAMLEq(t, string(file), s) 119 | } 120 | }) 121 | } 122 | } 123 | 124 | func Test_convertFile(t *testing.T) { 125 | tempDir := t.TempDir() 126 | 127 | testCases := []struct { 128 | ingressFile string 129 | objectCount int 130 | }{ 131 | { 132 | ingressFile: "ingress.yml", 133 | objectCount: 1, 134 | }, 135 | { 136 | ingressFile: "items_ingress.yml", 137 | objectCount: 1, 138 | }, 139 | { 140 | ingressFile: "items_mix.yml", 141 | objectCount: 1, 142 | }, 143 | { 144 | ingressFile: "ingress_extensions.yml", 145 | objectCount: 1, 146 | }, 147 | { 148 | ingressFile: "ingress_networking_v1beta1.yml", 149 | objectCount: 1, 150 | }, 151 | { 152 | ingressFile: "ingress_with_protocol.yml", 153 | objectCount: 1, 154 | }, 155 | { 156 | ingressFile: "ingress_with_matcher.yml", 157 | objectCount: 1, 158 | }, 159 | { 160 | ingressFile: "ingress_with_matcher_modifier.yml", 161 | objectCount: 3, 162 | }, 163 | { 164 | ingressFile: "ingress_with_headers_annotations.yml", 165 | objectCount: 2, 166 | }, 167 | { 168 | ingressFile: "ingress_rewrite_target.yml", 169 | objectCount: 2, 170 | }, 171 | { 172 | ingressFile: "ingress_with_whitelist.yml", 173 | objectCount: 2, 174 | }, 175 | { 176 | ingressFile: "ingress_with_whitelist_xforwarded.yml", 177 | objectCount: 2, 178 | }, 179 | { 180 | ingressFile: "ingress_with_passtlscert.yml", 181 | objectCount: 2, 182 | }, 183 | { 184 | ingressFile: "ingress_redirect_approot.yml", 185 | objectCount: 2, 186 | }, 187 | { 188 | ingressFile: "ingress_redirect_regex.yml", 189 | objectCount: 3, 190 | }, 191 | // FIXME errorPages middleware 192 | // { 193 | // ingressFile: "ingress_with_errorpage.yml", 194 | // objectCount: 3, 195 | // }, 196 | { 197 | ingressFile: "ingress_with_ratelimit.yml", 198 | objectCount: 3, 199 | }, 200 | { 201 | ingressFile: "ingress_with_request_modifier.yml", 202 | objectCount: 2, 203 | }, 204 | { 205 | ingressFile: "ingress_with_middleware_name.yml", 206 | objectCount: 1, 207 | }, 208 | } 209 | 210 | fixturesDir := filepath.Join("fixtures", "output_convertFile") 211 | if *updateExpected { 212 | require.NoError(t, os.RemoveAll(fixturesDir)) 213 | require.NoError(t, os.MkdirAll(fixturesDir, 0o755)) 214 | } 215 | 216 | for _, test := range testCases { 217 | t.Run(test.ingressFile, func(t *testing.T) { 218 | err := convertFile(filepath.Join("fixtures", "input"), tempDir, test.ingressFile) 219 | require.NoError(t, err) 220 | 221 | require.FileExists(t, filepath.Join(tempDir, test.ingressFile)) 222 | 223 | if *updateExpected { 224 | var src *os.File 225 | src, err = os.Open(filepath.Join(tempDir, test.ingressFile)) 226 | require.NoError(t, err) 227 | var dst *os.File 228 | dst, err = os.Create(filepath.Join(fixturesDir, test.ingressFile)) 229 | require.NoError(t, err) 230 | _, err = io.Copy(dst, src) 231 | require.NoError(t, err) 232 | } 233 | 234 | fixture, err := os.ReadFile(filepath.Join(fixturesDir, test.ingressFile)) 235 | require.NoError(t, err) 236 | 237 | output, err := os.ReadFile(filepath.Join(tempDir, test.ingressFile)) 238 | require.NoError(t, err) 239 | 240 | assert.YAMLEq(t, string(fixture), string(output)) 241 | }) 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /ingress/parser.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1" 9 | extv1beta1 "k8s.io/api/extensions/v1beta1" 10 | netv1 "k8s.io/api/networking/v1" 11 | netv1beta1 "k8s.io/api/networking/v1beta1" 12 | "k8s.io/apimachinery/pkg/runtime" 13 | "k8s.io/apimachinery/pkg/runtime/schema" 14 | "k8s.io/apimachinery/pkg/util/intstr" 15 | "k8s.io/client-go/kubernetes/scheme" 16 | ) 17 | 18 | func extensionsToNetworkingV1(ing *extv1beta1.Ingress) (*netv1.Ingress, error) { 19 | data, err := ing.Marshal() 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | ni := &netv1beta1.Ingress{} 25 | if err := ni.Unmarshal(data); err != nil { 26 | return nil, err 27 | } 28 | 29 | return networkingV1beta1ToV1(ni) 30 | } 31 | 32 | func networkingV1beta1ToV1(ing *netv1beta1.Ingress) (*netv1.Ingress, error) { 33 | data, err := ing.Marshal() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | in := &netv1.Ingress{} 39 | if err := in.Unmarshal(data); err != nil { 40 | return nil, err 41 | } 42 | 43 | if ing.Spec.Backend != nil { 44 | in.Spec.DefaultBackend = &netv1.IngressBackend{ 45 | Resource: ing.Spec.Backend.Resource, 46 | Service: &netv1.IngressServiceBackend{ 47 | Name: ing.Spec.Backend.ServiceName, 48 | Port: toServiceBackendPort(ing.Spec.Backend.ServicePort), 49 | }, 50 | } 51 | } 52 | 53 | for ri, rule := range ing.Spec.Rules { 54 | for pi, path := range rule.HTTP.Paths { 55 | in.Spec.Rules[ri].HTTP.Paths[pi].Backend = netv1.IngressBackend{ 56 | Service: &netv1.IngressServiceBackend{ 57 | Name: path.Backend.ServiceName, 58 | Port: toServiceBackendPort(path.Backend.ServicePort), 59 | }, 60 | } 61 | } 62 | } 63 | 64 | return in, nil 65 | } 66 | 67 | func toServiceBackendPort(p intstr.IntOrString) netv1.ServiceBackendPort { 68 | var port netv1.ServiceBackendPort 69 | switch p.Type { 70 | case intstr.Int: 71 | port.Number = p.IntVal 72 | case intstr.String: 73 | port.Name = p.StrVal 74 | } 75 | 76 | return port 77 | } 78 | 79 | func encodeYaml(object runtime.Object, groupName string) (string, error) { 80 | err := v1alpha1.AddToScheme(scheme.Scheme) 81 | if err != nil { 82 | return "", err 83 | } 84 | 85 | info, ok := runtime.SerializerInfoForMediaType(scheme.Codecs.SupportedMediaTypes(), "application/yaml") 86 | if !ok { 87 | return "", errors.New("unsupported media type application/yaml") 88 | } 89 | 90 | gv, err := schema.ParseGroupVersion(groupName) 91 | if err != nil { 92 | return "", err 93 | } 94 | 95 | buffer := bytes.NewBuffer([]byte{}) 96 | err = scheme.Codecs.EncoderForVersion(info.Serializer, gv).Encode(object, buffer) 97 | if err != nil { 98 | return "", err 99 | } 100 | return buffer.String(), nil 101 | } 102 | 103 | func parseYaml(content []byte) (runtime.Object, error) { 104 | decode := scheme.Codecs.UniversalDeserializer().Decode 105 | 106 | obj, _, err := decode(content, nil, nil) 107 | if err != nil { 108 | return nil, fmt.Errorf("error while decoding YAML object. Err was: %w", err) 109 | } 110 | 111 | return obj, nil 112 | } 113 | -------------------------------------------------------------------------------- /label/label.go: -------------------------------------------------------------------------------- 1 | package label 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | const ( 12 | // Prefix of the Traefik labels. 13 | Prefix = "traefik." 14 | ) 15 | 16 | const ( 17 | mapEntrySeparator = "||" 18 | mapValueSeparator = ":" 19 | ) 20 | 21 | // GetStringValue get string value associated to a label. 22 | func GetStringValue(labels map[string]string, labelName, defaultValue string) string { 23 | if value, ok := labels[labelName]; ok && len(value) > 0 { 24 | return value 25 | } 26 | return defaultValue 27 | } 28 | 29 | // GetBoolValue get bool value associated to a label. 30 | func GetBoolValue(labels map[string]string, labelName string, defaultValue bool) bool { 31 | rawValue, ok := labels[labelName] 32 | if ok { 33 | v, err := strconv.ParseBool(rawValue) 34 | if err == nil { 35 | return v 36 | } 37 | log.Printf("Unable to parse %q: %q, falling back to %v. %v", labelName, rawValue, defaultValue, err) 38 | } 39 | return defaultValue 40 | } 41 | 42 | // GetIntValue get int value associated to a label. 43 | func GetIntValue(labels map[string]string, labelName string, defaultValue int) int { 44 | if rawValue, ok := labels[labelName]; ok { 45 | value, err := strconv.Atoi(rawValue) 46 | if err == nil { 47 | return value 48 | } 49 | log.Printf("Unable to parse %q: %q, falling back to %v. %v", labelName, rawValue, defaultValue, err) 50 | } 51 | return defaultValue 52 | } 53 | 54 | // GetInt64Value get int64 value associated to a label. 55 | func GetInt64Value(labels map[string]string, labelName string, defaultValue int64) int64 { 56 | if rawValue, ok := labels[labelName]; ok { 57 | value, err := strconv.ParseInt(rawValue, 10, 64) 58 | if err == nil { 59 | return value 60 | } 61 | log.Printf("Unable to parse %q: %q, falling back to %v. %v", labelName, rawValue, defaultValue, err) 62 | } 63 | return defaultValue 64 | } 65 | 66 | // GetSliceStringValue get a slice of string associated to a label. 67 | func GetSliceStringValue(labels map[string]string, labelName string) []string { 68 | value := make([]string, 0, 1) 69 | 70 | if values, ok := labels[labelName]; ok { 71 | value = SplitAndTrimString(values, ",") 72 | 73 | if len(value) == 0 { 74 | log.Printf("Could not load %q.", labelName) 75 | } 76 | } 77 | return value 78 | } 79 | 80 | // ParseMapValue get Map value for a label value. 81 | func ParseMapValue(labelName, values string) map[string]string { 82 | mapValue := make(map[string]string) 83 | 84 | for _, parts := range strings.Split(values, mapEntrySeparator) { 85 | pair := strings.SplitN(parts, mapValueSeparator, 2) 86 | if len(pair) != 2 { 87 | log.Printf("Could not load %q: %q, skipping...", labelName, parts) 88 | } else { 89 | mapValue[http.CanonicalHeaderKey(strings.TrimSpace(pair[0]))] = strings.TrimSpace(pair[1]) 90 | } 91 | } 92 | 93 | if len(mapValue) == 0 { 94 | log.Printf("Could not load %q, skipping...", labelName) 95 | return nil 96 | } 97 | return mapValue 98 | } 99 | 100 | // GetMapValue get Map value associated to a label. 101 | func GetMapValue(labels map[string]string, labelName string) map[string]string { 102 | if values, ok := labels[labelName]; ok { 103 | if values == "" { 104 | log.Printf("Missing value for %q, skipping...", labelName) 105 | return nil 106 | } 107 | 108 | return ParseMapValue(labelName, values) 109 | } 110 | 111 | return nil 112 | } 113 | 114 | // GetStringMultipleStrict get multiple string values associated to several labels. 115 | // Fail if one label is missing. 116 | func GetStringMultipleStrict(labels map[string]string, labelNames ...string) (map[string]string, error) { 117 | foundLabels := map[string]string{} 118 | for _, name := range labelNames { 119 | value := GetStringValue(labels, name, "") 120 | // Error out only if one of them is not defined. 121 | if value == "" { 122 | return nil, fmt.Errorf("label not found: %s", name) 123 | } 124 | foundLabels[name] = value 125 | } 126 | return foundLabels, nil 127 | } 128 | 129 | // Has Check if a value is associated to a label. 130 | func Has(labels map[string]string, labelName string) bool { 131 | value, ok := labels[labelName] 132 | return ok && len(value) > 0 133 | } 134 | 135 | // HasPrefix Check if a value is associated to a less one label with a prefix. 136 | func HasPrefix(labels map[string]string, prefix string) bool { 137 | for name, value := range labels { 138 | if strings.HasPrefix(name, prefix) && len(value) > 0 { 139 | return true 140 | } 141 | } 142 | return false 143 | } 144 | 145 | // SplitAndTrimString splits separatedString at the separator character and trims each piece, filtering out empty pieces. 146 | // Returns the list of pieces or nil if the input did not contain a non-empty piece. 147 | func SplitAndTrimString(base, sep string) []string { 148 | var trimmedStrings []string 149 | 150 | for _, s := range strings.Split(base, sep) { 151 | s = strings.TrimSpace(s) 152 | if len(s) > 0 { 153 | trimmedStrings = append(trimmedStrings, s) 154 | } 155 | } 156 | 157 | return trimmedStrings 158 | } 159 | 160 | // GetFuncString a func related to GetStringValue. 161 | func GetFuncString(labelName, defaultValue string) func(map[string]string) string { 162 | return func(labels map[string]string) string { 163 | return GetStringValue(labels, labelName, defaultValue) 164 | } 165 | } 166 | 167 | // GetFuncInt a func related to GetIntValue. 168 | func GetFuncInt(labelName string, defaultValue int) func(map[string]string) int { 169 | return func(labels map[string]string) int { 170 | return GetIntValue(labels, labelName, defaultValue) 171 | } 172 | } 173 | 174 | // GetFuncBool a func related to GetBoolValue. 175 | func GetFuncBool(labelName string, defaultValue bool) func(map[string]string) bool { 176 | return func(labels map[string]string) bool { 177 | return GetBoolValue(labels, labelName, defaultValue) 178 | } 179 | } 180 | 181 | // GetFuncSliceString a func related to GetSliceStringValue. 182 | func GetFuncSliceString(labelName string) func(map[string]string) []string { 183 | return func(labels map[string]string) []string { 184 | return GetSliceStringValue(labels, labelName) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "os" 8 | "runtime" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/spf13/cobra/doc" 12 | "github.com/traefik/traefik-migration-tool/acme" 13 | "github.com/traefik/traefik-migration-tool/ingress" 14 | "github.com/traefik/traefik-migration-tool/static" 15 | ) 16 | 17 | var ( 18 | Version = "dev" 19 | ShortCommit = "" 20 | Date = "" 21 | ) 22 | 23 | type acmeConfig struct { 24 | input string 25 | output string 26 | resolverName string 27 | } 28 | 29 | type ingressConfig struct { 30 | input string 31 | output string 32 | } 33 | 34 | type staticConfig struct { 35 | input string 36 | outputDir string 37 | } 38 | 39 | func main() { 40 | log.SetFlags(log.Lshortfile) 41 | 42 | rootCmd := &cobra.Command{ 43 | Use: "traefik-migration-tool", 44 | Short: "A tool to migrate from Traefik v1 to Traefik v2.", 45 | Long: `A tool to migrate from Traefik v1 to Traefik v2.`, 46 | Version: Version, 47 | } 48 | 49 | var ingressCfg ingressConfig 50 | 51 | ingressCmd := &cobra.Command{ 52 | Use: "ingress", 53 | Short: "Migrate 'Ingress' to Traefik 'IngressRoute' resources.", 54 | Long: "Migrate 'Ingress' to Traefik 'IngressRoute' resources.", 55 | PreRunE: func(_ *cobra.Command, _ []string) error { 56 | fmt.Printf("Traefik Migration: %s - %s - %s\n", Version, Date, ShortCommit) 57 | 58 | if ingressCfg.input == "" || ingressCfg.output == "" { 59 | return errors.New("input and output flags are requires") 60 | } 61 | 62 | info, err := os.Stat(ingressCfg.output) 63 | if err != nil { 64 | if !os.IsNotExist(err) { 65 | return err 66 | } 67 | err = os.MkdirAll(ingressCfg.output, 0o755) 68 | if err != nil { 69 | return err 70 | } 71 | } else if !info.IsDir() { 72 | return errors.New("output must be a directory") 73 | } 74 | 75 | return nil 76 | }, 77 | RunE: func(_ *cobra.Command, _ []string) error { 78 | return ingress.Convert(ingressCfg.input, ingressCfg.output) 79 | }, 80 | } 81 | 82 | ingressCmd.Flags().StringVarP(&ingressCfg.input, "input", "i", "", "Input directory.") 83 | ingressCmd.Flags().StringVarP(&ingressCfg.output, "output", "o", "./output", "Output directory.") 84 | 85 | rootCmd.AddCommand(ingressCmd) 86 | 87 | acmeCfg := acmeConfig{} 88 | 89 | acmeCmd := &cobra.Command{ 90 | Use: "acme", 91 | Short: "Migrate acme.json file from Traefik v1 to Traefik v2.", 92 | Long: "Migrate acme.json file from Traefik v1 to Traefik v2.", 93 | RunE: func(_ *cobra.Command, _ []string) error { 94 | return acme.Convert(acmeCfg.input, acmeCfg.output, acmeCfg.resolverName) 95 | }, 96 | } 97 | 98 | acmeCmd.Flags().StringVarP(&acmeCfg.input, "input", "i", "./acme.json", "Path to the acme.json file from Traefik v1.") 99 | acmeCmd.Flags().StringVarP(&acmeCfg.output, "output", "o", "./acme-new.json", "Path to the acme.json file for Traefik v2.") 100 | acmeCmd.Flags().StringVar(&acmeCfg.resolverName, "resolver", "default", "The name of the certificates resolver.") 101 | 102 | rootCmd.AddCommand(acmeCmd) 103 | 104 | staticCfg := staticConfig{} 105 | 106 | staticCmd := &cobra.Command{ 107 | Use: "static", 108 | Short: "Migrate static configuration file from Traefik v1 to Traefik v2.", 109 | Long: `Migrate static configuration file from Traefik v1 to Traefik v2. 110 | Convert only the static configuration.`, 111 | RunE: func(_ *cobra.Command, _ []string) error { 112 | return static.Convert(staticCfg.input, staticCfg.outputDir) 113 | }, 114 | } 115 | 116 | staticCmd.Flags().StringVarP(&staticCfg.input, "input", "i", "./traefik.toml", "Path to the traefik.toml file from Traefik v1.") 117 | staticCmd.Flags().StringVarP(&staticCfg.outputDir, "output-dir", "d", "./static", "Path to the directory of the created files") 118 | 119 | rootCmd.AddCommand(staticCmd) 120 | 121 | docCmd := &cobra.Command{ 122 | Use: "doc", 123 | Short: "Generate documentation", 124 | Hidden: true, 125 | RunE: func(cmd *cobra.Command, args []string) error { 126 | return doc.GenMarkdownTree(rootCmd, "./docs") 127 | }, 128 | } 129 | 130 | rootCmd.AddCommand(docCmd) 131 | 132 | versionCmd := &cobra.Command{ 133 | Use: "version", 134 | Short: "Display version", 135 | Run: func(_ *cobra.Command, _ []string) { 136 | displayVersion(rootCmd.Name()) 137 | }, 138 | } 139 | 140 | rootCmd.AddCommand(versionCmd) 141 | 142 | if err := rootCmd.Execute(); err != nil { 143 | fmt.Println(err) 144 | os.Exit(1) 145 | } 146 | } 147 | 148 | func displayVersion(name string) { 149 | fmt.Printf(name+`: 150 | version : %s 151 | commit : %s 152 | build date : %s 153 | go version : %s 154 | go compiler : %s 155 | platform : %s/%s 156 | `, Version, ShortCommit, Date, runtime.Version(), runtime.Compiler, runtime.GOOS, runtime.GOARCH) 157 | } 158 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # traefik-migration-tool 2 | 3 | [![GitHub release](https://img.shields.io/github/release/traefik/traefik-migration-tool.svg)](https://github.com/traefik/traefik-migration-tool/releases/latest) 4 | [![Build Status](https://github.com/traefik/traefik-migration-tool/actions/workflows/main.yml/badge.svg)](https://github.com/traefik/traefik-migration-tool/actions) 5 | 6 | A migration tool from Traefik v1 to Traefik v2. 7 | 8 | Features: 9 | 10 | - ⛵ Migrate 'Ingress' to Traefik 'IngressRoute' resources. 11 | - 🔒 Migrate acme.json file from Traefik v1 to Traefik v2. 12 | - 🖹 Migrate the static configuration contained in the file `traefik.toml` to a Traefik v2 file. 13 | 14 | ## Usage 15 | 16 | - [Commands documentation](docs/traefik-migration-tool.md) 17 | 18 | ## Install 19 | 20 | ### From Binaries 21 | 22 | You can use pre-compiled binaries: 23 | 24 | * To get the binary just download the latest release for your OS/Arch from [the releases page](https://github.com/traefik/traefik-migration-tool/releases) 25 | * Unzip the archive. 26 | * Add `traefik-migration-tool` in your `PATH`. 27 | 28 | ### With Docker 29 | 30 | You can use a Docker image: 31 | 32 | ```sh 33 | docker run --rm -w /data -v ${PWD}:/data traefik/traefik-migration-tool 34 | ``` 35 | 36 | ## Limits 37 | 38 | Unsupported annotations: 39 | 40 | - `ingress.kubernetes.io/preserve-host` 41 | - `ingress.kubernetes.io/session-cookie-name` 42 | - `ingress.kubernetes.io/affinity` 43 | - `ingress.kubernetes.io/buffering` 44 | - `ingress.kubernetes.io/circuit-breaker-expression` 45 | - `ingress.kubernetes.io/max-conn-amount` 46 | - `ingress.kubernetes.io/max-conn-extractor-func` 47 | - `ingress.kubernetes.io/responseforwarding-flushinterval` 48 | - `ingress.kubernetes.io/load-balancer-method` 49 | - `ingress.kubernetes.io/auth-realm` 50 | - `ingress.kubernetes.io/service-weights` 51 | - `ingress.kubernetes.io/error-pages` 52 | -------------------------------------------------------------------------------- /static/acme.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/traefik/traefik/v2/pkg/config/static" 7 | "github.com/traefik/traefik/v2/pkg/provider/acme" 8 | ) 9 | 10 | func migrateACME(oldCfg Configuration) map[string]static.CertificateResolver { 11 | if oldCfg.ACME == nil { 12 | return nil 13 | } 14 | 15 | if oldCfg.ACME.EntryPoint != "" { 16 | fmt.Printf("The entry point (%s) defined in the ACME configuration must be converted manually. See https://docs.traefik.io/routing/routers/#certresolver\n", oldCfg.ACME.EntryPoint) 17 | } 18 | 19 | return map[string]static.CertificateResolver{ 20 | "default": { 21 | ACME: &acme.Configuration{ 22 | Email: oldCfg.ACME.Email, 23 | CAServer: oldCfg.ACME.CAServer, 24 | Storage: oldCfg.ACME.Storage, 25 | KeyType: oldCfg.ACME.KeyType, 26 | DNSChallenge: migrateDNSChallenge(oldCfg), 27 | HTTPChallenge: migrateHTTPChallenge(oldCfg), 28 | TLSChallenge: migrateTLSChallenge(oldCfg), 29 | }, 30 | }, 31 | } 32 | } 33 | 34 | func migrateHTTPChallenge(oldCfg Configuration) *acme.HTTPChallenge { 35 | if oldCfg.ACME.HTTPChallenge == nil { 36 | return nil 37 | } 38 | 39 | return &acme.HTTPChallenge{ 40 | EntryPoint: oldCfg.ACME.HTTPChallenge.EntryPoint, 41 | } 42 | } 43 | 44 | func migrateTLSChallenge(oldCfg Configuration) *acme.TLSChallenge { 45 | if oldCfg.ACME.TLSChallenge == nil { 46 | return nil 47 | } 48 | 49 | return &acme.TLSChallenge{} 50 | } 51 | 52 | func migrateDNSChallenge(oldCfg Configuration) *acme.DNSChallenge { 53 | if oldCfg.ACME.DNSChallenge == nil { 54 | return nil 55 | } 56 | 57 | return &acme.DNSChallenge{ 58 | Provider: oldCfg.ACME.DNSChallenge.Provider, 59 | DelayBeforeCheck: convertDuration(oldCfg.ACME.DNSChallenge.DelayBeforeCheck, 0), 60 | Resolvers: oldCfg.ACME.DNSChallenge.Resolvers, 61 | DisablePropagationCheck: oldCfg.ACME.DNSChallenge.DisablePropagationCheck, 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /static/configuration.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/containous/flaeg/parse" 8 | ptypes "github.com/traefik/paerser/types" 9 | "github.com/traefik/traefik/v2/pkg/config/static" 10 | "github.com/traefik/traefik/v2/pkg/ping" 11 | "github.com/traefik/traefik/v2/pkg/tls" 12 | "github.com/traefik/traefik/v2/pkg/types" 13 | ) 14 | 15 | func migrateConfiguration(oldCfg Configuration) static.Configuration { 16 | if oldCfg.Retry != nil { 17 | fmt.Println("Retry must be converted manually. See https://docs.traefik.io/middlewares/http/retry/") 18 | } 19 | 20 | if oldCfg.Constraints != nil { 21 | fmt.Println("Global Constraints must be converted manually to provider constraints. See https://docs.traefik.io/providers/docker/#constraints") 22 | } 23 | 24 | if oldCfg.Web != nil { 25 | fmt.Println("Web must be converted manually. See https://docs.traefik.io/operations/api/") 26 | } 27 | 28 | return static.Configuration{ 29 | Global: &static.Global{ 30 | CheckNewVersion: oldCfg.CheckNewVersion, 31 | SendAnonymousUsage: oldCfg.SendAnonymousUsage, 32 | }, 33 | ServersTransport: migrateServersTransport(oldCfg), 34 | EntryPoints: migrateEntryPoints(oldCfg), 35 | Providers: migrateProviders(oldCfg), 36 | API: migrateAPI(oldCfg), 37 | Metrics: migrateMetrics(oldCfg), 38 | Ping: migratePing(oldCfg), 39 | Log: migrateTraefikLog(oldCfg), 40 | AccessLog: migrateAccessLog(oldCfg), 41 | Tracing: migrateTracing(oldCfg), 42 | HostResolver: migrateHostResolver(oldCfg), 43 | CertificatesResolvers: migrateACME(oldCfg), 44 | } 45 | } 46 | 47 | func migratePing(oldCfg Configuration) *ping.Handler { 48 | if oldCfg.Ping == nil { 49 | return nil 50 | } 51 | 52 | return &ping.Handler{ 53 | EntryPoint: oldCfg.Ping.EntryPoint, 54 | } 55 | } 56 | 57 | func migrateAPI(oldCfg Configuration) *static.API { 58 | if oldCfg.API == nil { 59 | return nil 60 | } 61 | 62 | if oldCfg.API.EntryPoint != "" { 63 | fmt.Printf("The entry point (%s) defined in API must be converted manually. See https://docs.traefik.io/operations/api/\n", oldCfg.API.EntryPoint) 64 | } 65 | 66 | return &static.API{ 67 | Insecure: true, 68 | Dashboard: oldCfg.API.Dashboard, 69 | Debug: oldCfg.API.Debug, 70 | } 71 | } 72 | 73 | func migrateEntryPoints(oldCfg Configuration) static.EntryPoints { 74 | if oldCfg.EntryPoints == nil { 75 | return nil 76 | } 77 | 78 | eps := static.EntryPoints{} 79 | for name, entryPoint := range *oldCfg.EntryPoints { 80 | if entryPoint.Compress { 81 | fmt.Printf("Compress on entry point %q must be converted manually. See https://docs.traefik.io/middlewares/http/compress/\n", name) 82 | } 83 | if entryPoint.TLS != nil { 84 | fmt.Printf("TLS on entry point %q must be converted manually. See https://docs.traefik.io/routing/routers/#tls\n", name) 85 | } 86 | if entryPoint.Redirect != nil { 87 | fmt.Printf("Redirect on entry point %q must be converted manually. See https://docs.traefik.io/middlewares/http/redirectscheme/\n", name) 88 | } 89 | if entryPoint.WhiteList != nil { 90 | fmt.Printf("WhiteList on entry point %q must be converted manually. See https://docs.traefik.io/middlewares/http/ipwhitelist/\n", name) 91 | } 92 | if len(entryPoint.WhitelistSourceRange) != 0 { 93 | fmt.Printf("WhitelistSourceRange on entry point %q must be converted manually. See https://docs.traefik.io/middlewares/http/ipwhitelist/\n", name) 94 | } 95 | 96 | eps[name] = &static.EntryPoint{ 97 | Address: entryPoint.Address, 98 | Transport: migrateEntryPointsTransport(oldCfg), 99 | ProxyProtocol: migrateProxyProtocol(entryPoint), 100 | ForwardedHeaders: migrateEntryPointForwardedHeaders(entryPoint), 101 | } 102 | } 103 | return eps 104 | } 105 | 106 | func migrateEntryPointsTransport(oldCfg Configuration) *static.EntryPointsTransport { 107 | if oldCfg.LifeCycle == nil || oldCfg.RespondingTimeouts == nil { 108 | return nil 109 | } 110 | 111 | return &static.EntryPointsTransport{ 112 | LifeCycle: migrateLifeCycle(oldCfg), 113 | RespondingTimeouts: migrateRespondingTimeouts(oldCfg), 114 | } 115 | } 116 | 117 | func migrateHostResolver(oldCfg Configuration) *types.HostResolverConfig { 118 | if oldCfg.HostResolver == nil { 119 | return nil 120 | } 121 | 122 | // TODO SKIP ? 123 | return &types.HostResolverConfig{ 124 | CnameFlattening: oldCfg.HostResolver.CnameFlattening, 125 | ResolvConfig: oldCfg.HostResolver.ResolvConfig, 126 | ResolvDepth: oldCfg.HostResolver.ResolvDepth, 127 | } 128 | } 129 | 130 | func migrateRespondingTimeouts(oldCfg Configuration) *static.RespondingTimeouts { 131 | if oldCfg.RespondingTimeouts == nil { 132 | return nil 133 | } 134 | 135 | return &static.RespondingTimeouts{ 136 | ReadTimeout: convertDuration(oldCfg.RespondingTimeouts.ReadTimeout, 0), 137 | WriteTimeout: convertDuration(oldCfg.RespondingTimeouts.WriteTimeout, 0), 138 | IdleTimeout: convertDuration(oldCfg.RespondingTimeouts.IdleTimeout, 180*time.Second), 139 | } 140 | } 141 | 142 | func migrateLifeCycle(oldCfg Configuration) *static.LifeCycle { 143 | if oldCfg.LifeCycle == nil { 144 | return nil 145 | } 146 | 147 | return &static.LifeCycle{ 148 | RequestAcceptGraceTimeout: convertDuration(oldCfg.LifeCycle.RequestAcceptGraceTimeout, 0), 149 | GraceTimeOut: convertDuration(oldCfg.LifeCycle.GraceTimeOut, 10*time.Second), 150 | } 151 | } 152 | 153 | func migrateEntryPointForwardedHeaders(entryPoint EntryPoint) *static.ForwardedHeaders { 154 | if entryPoint.ForwardedHeaders == nil { 155 | return nil 156 | } 157 | 158 | return &static.ForwardedHeaders{ 159 | Insecure: entryPoint.ForwardedHeaders.Insecure, 160 | TrustedIPs: entryPoint.ForwardedHeaders.TrustedIPs, 161 | } 162 | } 163 | 164 | func migrateProxyProtocol(entryPoint EntryPoint) *static.ProxyProtocol { 165 | if entryPoint.ProxyProtocol == nil { 166 | return nil 167 | } 168 | 169 | return &static.ProxyProtocol{ 170 | Insecure: entryPoint.ProxyProtocol.Insecure, 171 | TrustedIPs: entryPoint.ProxyProtocol.TrustedIPs, 172 | } 173 | } 174 | 175 | func migrateServersTransport(oldCfg Configuration) *static.ServersTransport { 176 | var serversTransport *static.ServersTransport 177 | if oldCfg.InsecureSkipVerify || oldCfg.MaxIdleConnsPerHost > 0 { 178 | serversTransport = &static.ServersTransport{ 179 | InsecureSkipVerify: oldCfg.InsecureSkipVerify, 180 | MaxIdleConnsPerHost: oldCfg.MaxIdleConnsPerHost, 181 | } 182 | } 183 | 184 | if len(oldCfg.RootCAs) > 0 { 185 | if serversTransport == nil { 186 | serversTransport = &static.ServersTransport{} 187 | } 188 | 189 | var rootCas []tls.FileOrContent 190 | for _, ca := range oldCfg.RootCAs { 191 | rootCas = append(rootCas, tls.FileOrContent(ca)) 192 | } 193 | serversTransport.RootCAs = rootCas 194 | } 195 | 196 | if oldCfg.ForwardingTimeouts != nil { 197 | if serversTransport == nil { 198 | serversTransport = &static.ServersTransport{} 199 | } 200 | 201 | timeouts := &static.ForwardingTimeouts{ 202 | DialTimeout: convertDuration(oldCfg.ForwardingTimeouts.DialTimeout, 30*time.Second), 203 | ResponseHeaderTimeout: convertDuration(oldCfg.ForwardingTimeouts.ResponseHeaderTimeout, 0), 204 | IdleConnTimeout: convertDuration(oldCfg.IdleTimeout, 180*time.Second), 205 | } 206 | 207 | serversTransport.ForwardingTimeouts = timeouts 208 | } 209 | 210 | return serversTransport 211 | } 212 | 213 | func convertDuration(value parse.Duration, defaultDuration time.Duration) ptypes.Duration { 214 | if value == 0 { 215 | return ptypes.Duration(defaultDuration) 216 | } 217 | 218 | return ptypes.Duration(value) 219 | } 220 | -------------------------------------------------------------------------------- /static/convert.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/BurntSushi/toml" 9 | "github.com/traefik/traefik/v2/pkg/config/static" 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | type encoder interface { 14 | Encode(v interface{}) error 15 | } 16 | 17 | // Convert old static configuration file to the Traefik v2 static configuration files. 18 | func Convert(oldFilename, outputDir string) error { 19 | err := os.MkdirAll(outputDir, 0o755) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | oldCfg := Configuration{} 25 | 26 | _, err = toml.DecodeFile(oldFilename, &oldCfg) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | newCfg := migrateConfiguration(oldCfg) 32 | 33 | err = writeFile(filepath.Join(outputDir, "new-traefik.yml"), func(w io.Writer) encoder { 34 | return yaml.NewEncoder(w) 35 | }, newCfg) 36 | if err != nil { 37 | return err 38 | } 39 | 40 | err = writeFile(filepath.Join(outputDir, "new-traefik.toml"), func(w io.Writer) encoder { 41 | return toml.NewEncoder(w) 42 | }, newCfg) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | 50 | func writeFile(filename string, enc func(w io.Writer) encoder, newCfg static.Configuration) error { 51 | cfgFile, err := os.Create(filename) 52 | if err != nil { 53 | return err 54 | } 55 | defer func() { _ = cfgFile.Close() }() 56 | 57 | return enc(cfgFile).Encode(newCfg) 58 | } 59 | -------------------------------------------------------------------------------- /static/convert_test.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/BurntSushi/toml" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | "github.com/traefik/traefik/v2/pkg/config/static" 12 | "gopkg.in/yaml.v2" 13 | ) 14 | 15 | func TestConvert(t *testing.T) { 16 | testCases := []string{ 17 | "./fixtures/sample01.toml", 18 | "./fixtures/sample02.toml", 19 | } 20 | 21 | for _, test := range testCases { 22 | test := test 23 | t.Run(test, func(t *testing.T) { 24 | t.Parallel() 25 | 26 | dir := t.TempDir() 27 | 28 | err := Convert(test, dir) 29 | require.NoError(t, err) 30 | 31 | cfgToml := static.Configuration{} 32 | _, err = toml.DecodeFile(filepath.Join(dir, "new-traefik.toml"), &cfgToml) 33 | require.NoError(t, err) 34 | 35 | cfgYaml := static.Configuration{} 36 | ymlData, err := os.ReadFile(filepath.Join(dir, "new-traefik.yml")) 37 | require.NoError(t, err) 38 | 39 | err = yaml.Unmarshal(ymlData, &cfgYaml) 40 | require.NoError(t, err) 41 | 42 | assert.Equal(t, &cfgToml, &cfgYaml) 43 | }) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /static/fixtures/sample01.toml: -------------------------------------------------------------------------------- 1 | defaultEntryPoints = ["http", "https"] 2 | 3 | [entryPoints] 4 | [entryPoints.http] 5 | address = ":80" 6 | [entryPoints.http.redirect] 7 | entryPoint = "https" 8 | [entryPoints.https] 9 | address = ":443" 10 | [entryPoints.https.tls] 11 | [entryPoints.https.tls.ClientCA] 12 | files = ["/app/CA.crt"] 13 | optional = true 14 | [[entryPoints.https.tls.certificates]] 15 | certFile = "/app/tls.crt" 16 | keyFile = "/app/tls.key" 17 | 18 | [api] 19 | 20 | [Docker] 21 | swarmmode = true 22 | watch = true 23 | network = "traefik" 24 | 25 | [Metrics] 26 | [Metrics.Prometheus] 27 | Buckets = [42.0, 42.0] 28 | EntryPoint = "foobar" 29 | [Metrics.Datadog] 30 | Address = "foobar" 31 | [Metrics.StatsD] 32 | Address = "foobar" 33 | [Metrics.InfluxDB] 34 | Address = "foobar" 35 | Protocol = "foobar" 36 | Database = "foobar" 37 | RetentionPolicy = "foobar" 38 | 39 | [file] 40 | -------------------------------------------------------------------------------- /static/fixtures/sample02.toml: -------------------------------------------------------------------------------- 1 | GraceTimeOut = 42 2 | Debug = true 3 | CheckNewVersion = true 4 | SendAnonymousUsage = true 5 | AccessLogsFile = "foobar" 6 | TraefikLogsFile = "foobar" 7 | LogLevel = "foobar" 8 | DefaultEntryPoints = ["foobar", "foobar"] 9 | ProvidersThrottleDuration = 42 10 | MaxIdleConnsPerHost = 42 11 | IdleTimeout = 42 12 | InsecureSkipVerify = true 13 | RootCAs = ["foobar", "foobar"] 14 | AllowMinWeightZero = true 15 | KeepTrailingSlash = true 16 | Constraints = ["tag==api"] 17 | 18 | [LifeCycle] 19 | RequestAcceptGraceTimeout = 42 20 | GraceTimeOut = 42 21 | 22 | [AccessLog] 23 | FilePath = "foobar" 24 | Format = "foobar" 25 | BufferingSize = 42 26 | [AccessLog.Filters] 27 | StatusCodes = ["foobar", "foobar"] 28 | RetryAttempts = true 29 | MinDuration = 42 30 | [AccessLog.Fields] 31 | DefaultMode = "foobar" 32 | [AccessLog.Fields.Names] 33 | name0 = "foobar" 34 | [AccessLog.Fields.Headers] 35 | DefaultMode = "foobar" 36 | [AccessLog.Fields.Headers.Names] 37 | name0 = "foobar" 38 | 39 | [TraefikLog] 40 | FilePath = "foobar" 41 | Format = "foobar" 42 | 43 | [Tracing] 44 | Backend = "foobar" 45 | ServiceName = "foobar" 46 | SpanNameLimit = 42 47 | [Tracing.Jaeger] 48 | SamplingServerURL = "foobar" 49 | SamplingType = "foobar" 50 | SamplingParam = 42.0 51 | LocalAgentHostPort = "foobar" 52 | TraceContextHeaderName = "foobar" 53 | [Tracing.Zipkin] 54 | HTTPEndpoint = "foobar" 55 | SameSpan = true 56 | ID128Bit = true 57 | Debug = true 58 | [Tracing.DataDog] 59 | LocalAgentHostPort = "foobar" 60 | GlobalTag = "foobar" 61 | Debug = true 62 | PrioritySampling = true 63 | TraceIDHeaderName = "foobar" 64 | ParentIDHeaderName = "foobar" 65 | SamplingPriorityHeaderName = "foobar" 66 | BagagePrefixHeaderName = "foobar" 67 | 68 | [EntryPoints] 69 | [EntryPoints.EntryPoint0] 70 | Address = "foobar" 71 | WhitelistSourceRange = ["foobar", "foobar"] 72 | Compress = true 73 | [EntryPoints.EntryPoint0.TLS] 74 | MinVersion = "foobar" 75 | CipherSuites = ["foobar", "foobar"] 76 | ClientCAFiles = ["foobar", "foobar"] 77 | SniStrict = true 78 | 79 | [[EntryPoints.EntryPoint0.TLS.Certificates]] 80 | CertFile = "foobar" 81 | KeyFile = "foobar" 82 | 83 | [[EntryPoints.EntryPoint0.TLS.Certificates]] 84 | CertFile = "foobar" 85 | KeyFile = "foobar" 86 | [EntryPoints.EntryPoint0.TLS.ClientCA] 87 | Files = ["foobar", "foobar"] 88 | Optional = true 89 | [EntryPoints.EntryPoint0.TLS.DefaultCertificate] 90 | CertFile = "foobar" 91 | KeyFile = "foobar" 92 | [EntryPoints.EntryPoint0.Redirect] 93 | EntryPoint = "foobar" 94 | Regex = "foobar" 95 | Replacement = "foobar" 96 | Permanent = true 97 | [EntryPoints.EntryPoint0.Auth] 98 | HeaderField = "foobar" 99 | [EntryPoints.EntryPoint0.Auth.Basic] 100 | Users = ["foobar", "foobar"] 101 | UsersFile = "foobar" 102 | RemoveHeader = true 103 | [EntryPoints.EntryPoint0.Auth.Digest] 104 | Users = ["foobar", "foobar"] 105 | UsersFile = "foobar" 106 | RemoveHeader = true 107 | [EntryPoints.EntryPoint0.Auth.Forward] 108 | Address = "foobar" 109 | TrustForwardHeader = true 110 | AuthResponseHeaders = ["foobar", "foobar"] 111 | [EntryPoints.EntryPoint0.Auth.Forward.TLS] 112 | CA = "foobar" 113 | CAOptional = true 114 | Cert = "foobar" 115 | Key = "foobar" 116 | InsecureSkipVerify = true 117 | [EntryPoints.EntryPoint0.WhiteList] 118 | SourceRange = ["foobar", "foobar"] 119 | UseXForwardedFor = true 120 | [EntryPoints.EntryPoint0.ProxyProtocol] 121 | Insecure = true 122 | TrustedIPs = ["foobar", "foobar"] 123 | [EntryPoints.EntryPoint0.ForwardedHeaders] 124 | Insecure = true 125 | TrustedIPs = ["foobar", "foobar"] 126 | 127 | [Cluster] 128 | Node = "foobar" 129 | [Cluster.Store] 130 | Prefix = "foobar" 131 | 132 | [ACME] 133 | Email = "foobar" 134 | Storage = "foobar" 135 | StorageFile = "foobar" 136 | OnDemand = true 137 | OnHostRule = true 138 | CAServer = "foobar" 139 | EntryPoint = "foobar" 140 | KeyType = "foobar" 141 | DNSProvider = "foobar" 142 | DelayDontCheckDNS = 42 143 | ACMELogging = true 144 | OverrideCertificates = true 145 | 146 | [[ACME.Domains]] 147 | Main = "foobar" 148 | SANs = ["foobar", "foobar"] 149 | 150 | [[ACME.Domains]] 151 | Main = "foobar" 152 | SANs = ["foobar", "foobar"] 153 | [ACME.DNSChallenge] 154 | Provider = "foobar" 155 | DelayBeforeCheck = 42 156 | Resolvers = ["foobar", "foobar"] 157 | DisablePropagationCheck = true 158 | [ACME.HTTPChallenge] 159 | EntryPoint = "foobar" 160 | [ACME.TLSChallenge] 161 | 162 | [Retry] 163 | Attempts = 42 164 | 165 | [HealthCheck] 166 | Interval = 42 167 | 168 | [RespondingTimeouts] 169 | ReadTimeout = 42 170 | WriteTimeout = 42 171 | IdleTimeout = 42 172 | 173 | [ForwardingTimeouts] 174 | DialTimeout = 42 175 | ResponseHeaderTimeout = 42 176 | 177 | [Web] 178 | Address = "foobar" 179 | CertFile = "foobar" 180 | KeyFile = "foobar" 181 | ReadOnly = true 182 | Path = "foobar" 183 | Debug = true 184 | [Web.Statistics] 185 | RecentErrors = 42 186 | [Web.Metrics] 187 | [Web.Metrics.Prometheus] 188 | Buckets = [42.0, 42.0] 189 | EntryPoint = "foobar" 190 | [Web.Metrics.Datadog] 191 | Address = "foobar" 192 | PushInterval = "10s" 193 | [Web.Metrics.StatsD] 194 | Address = "foobar" 195 | PushInterval = "10s" 196 | [Web.Metrics.InfluxDB] 197 | Address = "foobar" 198 | Protocol = "foobar" 199 | PushInterval = "10s" 200 | Database = "foobar" 201 | RetentionPolicy = "foobar" 202 | [Web.Auth] 203 | HeaderField = "foobar" 204 | [Web.Auth.Basic] 205 | Users = ["foobar", "foobar"] 206 | UsersFile = "foobar" 207 | RemoveHeader = true 208 | [Web.Auth.Digest] 209 | Users = ["foobar", "foobar"] 210 | UsersFile = "foobar" 211 | RemoveHeader = true 212 | [Web.Auth.Forward] 213 | Address = "foobar" 214 | TrustForwardHeader = true 215 | AuthResponseHeaders = ["foobar", "foobar"] 216 | [Web.Auth.Forward.TLS] 217 | CA = "foobar" 218 | CAOptional = true 219 | Cert = "foobar" 220 | Key = "foobar" 221 | InsecureSkipVerify = true 222 | 223 | [Docker] 224 | Watch = true 225 | Filename = "foobar" 226 | Trace = true 227 | TemplateVersion = 42 228 | DebugLogGeneratedTemplate = true 229 | Endpoint = "foobar" 230 | Domain = "foobar" 231 | ExposedByDefault = true 232 | UseBindPortIP = true 233 | SwarmMode = true 234 | Network = "foobar" 235 | SwarmModeRefreshSeconds = 42 236 | Constraints = ["tag==api"] 237 | 238 | [Docker.TLS] 239 | CA = "foobar" 240 | CAOptional = true 241 | Cert = "foobar" 242 | Key = "foobar" 243 | InsecureSkipVerify = true 244 | 245 | [File] 246 | Watch = true 247 | Filename = "foobar" 248 | Trace = true 249 | TemplateVersion = 42 250 | DebugLogGeneratedTemplate = true 251 | Directory = "foobar" 252 | TraefikFile = "foobar" 253 | Constraints = ["tag==api"] 254 | 255 | [Marathon] 256 | Watch = true 257 | Filename = "foobar" 258 | Trace = true 259 | TemplateVersion = 42 260 | DebugLogGeneratedTemplate = true 261 | Endpoint = "foobar" 262 | Domain = "foobar" 263 | ExposedByDefault = true 264 | GroupsAsSubDomains = true 265 | DCOSToken = "foobar" 266 | MarathonLBCompatibility = true 267 | FilterMarathonConstraints = true 268 | DialerTimeout = 42 269 | ResponseHeaderTimeout = 42 270 | TLSHandshakeTimeout = 42 271 | KeepAlive = 42 272 | ForceTaskHostname = true 273 | RespectReadinessChecks = true 274 | Constraints = ["tag==api"] 275 | 276 | [Marathon.TLS] 277 | CA = "foobar" 278 | CAOptional = true 279 | Cert = "foobar" 280 | Key = "foobar" 281 | InsecureSkipVerify = true 282 | 283 | [Marathon.Basic] 284 | HTTPBasicAuthUser = "foobar" 285 | HTTPBasicPassword = "foobar" 286 | 287 | [Consul] 288 | Watch = true 289 | Filename = "foobar" 290 | Trace = true 291 | TemplateVersion = 42 292 | DebugLogGeneratedTemplate = true 293 | Endpoint = "foobar" 294 | Username = "foobar" 295 | Password = "foobar" 296 | Prefix = "foobar" 297 | Constraints = ["tag==api"] 298 | 299 | [Consul.TLS] 300 | CA = "foobar" 301 | CAOptional = true 302 | Cert = "foobar" 303 | Key = "foobar" 304 | InsecureSkipVerify = true 305 | 306 | [ConsulCatalog] 307 | Watch = true 308 | Filename = "foobar" 309 | Trace = true 310 | TemplateVersion = 42 311 | DebugLogGeneratedTemplate = true 312 | Endpoint = "foobar" 313 | Domain = "foobar" 314 | Stale = true 315 | ExposedByDefault = true 316 | Prefix = "foobar" 317 | StrictChecks = true 318 | FrontEndRule = "foobar" 319 | Constraints = ["tag==api"] 320 | 321 | [ConsulCatalog.TLS] 322 | CA = "foobar" 323 | CAOptional = true 324 | Cert = "foobar" 325 | Key = "foobar" 326 | InsecureSkipVerify = true 327 | 328 | [Etcd] 329 | Watch = true 330 | Filename = "foobar" 331 | Trace = true 332 | TemplateVersion = 42 333 | DebugLogGeneratedTemplate = true 334 | Endpoint = "foobar" 335 | Username = "foobar" 336 | Password = "foobar" 337 | UseAPIV3 = true 338 | Prefix = "foobar" 339 | Constraints = ["tag==api"] 340 | 341 | [Etcd.TLS] 342 | CA = "foobar" 343 | CAOptional = true 344 | Cert = "foobar" 345 | Key = "foobar" 346 | InsecureSkipVerify = true 347 | 348 | [Zookeeper] 349 | Watch = true 350 | Filename = "foobar" 351 | Trace = true 352 | TemplateVersion = 42 353 | DebugLogGeneratedTemplate = true 354 | Regex = "foobar" 355 | Endpoint = "foobar" 356 | Username = "foobar" 357 | Password = "foobar" 358 | Prefix = "foobar" 359 | Constraints = ["tag==api"] 360 | 361 | [Zookeeper.TLS] 362 | CA = "foobar" 363 | CAOptional = true 364 | Cert = "foobar" 365 | Key = "foobar" 366 | InsecureSkipVerify = true 367 | 368 | [Boltdb] 369 | Watch = true 370 | Filename = "foobar" 371 | Trace = true 372 | TemplateVersion = 42 373 | DebugLogGeneratedTemplate = true 374 | Endpoint = "foobar" 375 | Username = "foobar" 376 | Password = "foobar" 377 | Prefix = "foobar" 378 | Constraints = ["tag==api"] 379 | 380 | [Boltdb.TLS] 381 | CA = "foobar" 382 | CAOptional = true 383 | Cert = "foobar" 384 | Key = "foobar" 385 | InsecureSkipVerify = true 386 | 387 | [Kubernetes] 388 | Watch = true 389 | Filename = "foobar" 390 | Trace = true 391 | TemplateVersion = 42 392 | DebugLogGeneratedTemplate = true 393 | Endpoint = "foobar" 394 | Token = "foobar" 395 | CertAuthFilePath = "foobar" 396 | DisablePassHostHeaders = true 397 | EnablePassTLSCert = true 398 | Namespaces = ["foobar", "foobar"] 399 | LabelSelector = "foobar" 400 | IngressClass = "foobar" 401 | ThrottleDuration = 42 402 | Constraints = ["tag==api"] 403 | 404 | [Kubernetes.IngressEndpoint] 405 | IP = "foobar" 406 | Hostname = "foobar" 407 | PublishedService = "foobar" 408 | 409 | [Mesos] 410 | Watch = true 411 | Filename = "foobar" 412 | Trace = true 413 | TemplateVersion = 42 414 | DebugLogGeneratedTemplate = true 415 | Endpoint = "foobar" 416 | Domain = "foobar" 417 | ExposedByDefault = true 418 | GroupsAsSubDomains = true 419 | ZkDetectionTimeout = 42 420 | RefreshSeconds = 42 421 | IPSources = "foobar" 422 | StateTimeoutSecond = 42 423 | Masters = ["foobar", "foobar"] 424 | Constraints = ["tag==api"] 425 | 426 | [Eureka] 427 | Watch = true 428 | Filename = "foobar" 429 | Trace = true 430 | TemplateVersion = 42 431 | DebugLogGeneratedTemplate = true 432 | Endpoint = "foobar" 433 | Delay = 42 434 | RefreshSeconds = 42 435 | Constraints = ["tag==api"] 436 | 437 | [ECS] 438 | Watch = true 439 | Filename = "foobar" 440 | Trace = true 441 | TemplateVersion = 42 442 | DebugLogGeneratedTemplate = true 443 | Domain = "foobar" 444 | ExposedByDefault = true 445 | RefreshSeconds = 42 446 | Clusters = ["foobar", "foobar"] 447 | Cluster = "foobar" 448 | AutoDiscoverClusters = true 449 | Region = "foobar" 450 | AccessKeyID = "foobar" 451 | SecretAccessKey = "foobar" 452 | Constraints = ["tag==api"] 453 | 454 | [Rancher] 455 | Watch = true 456 | Filename = "foobar" 457 | Trace = true 458 | TemplateVersion = 42 459 | DebugLogGeneratedTemplate = true 460 | Endpoint = "foobar" 461 | AccessKey = "foobar" 462 | SecretKey = "foobar" 463 | Domain = "foobar" 464 | RefreshSeconds = 42 465 | ExposedByDefault = true 466 | EnableServiceHealthFilter = true 467 | Constraints = ["tag==api"] 468 | 469 | [Rancher.API] 470 | Endpoint = "foobar" 471 | AccessKey = "foobar" 472 | SecretKey = "foobar" 473 | [Rancher.Metadata] 474 | IntervalPoll = true 475 | Prefix = "foobar" 476 | 477 | [DynamoDB] 478 | Watch = true 479 | Filename = "foobar" 480 | Trace = true 481 | TemplateVersion = 42 482 | DebugLogGeneratedTemplate = true 483 | AccessKeyID = "foobar" 484 | RefreshSeconds = 42 485 | Region = "foobar" 486 | SecretAccessKey = "foobar" 487 | TableName = "foobar" 488 | Endpoint = "foobar" 489 | Constraints = ["tag==api"] 490 | 491 | [ServiceFabric] 492 | Watch = true 493 | Filename = "foobar" 494 | Trace = true 495 | TemplateVersion = 42 496 | DebugLogGeneratedTemplate = true 497 | ClusterManagementURL = "foobar" 498 | APIVersion = "foobar" 499 | RefreshSeconds = 42 500 | AppInsightsClientName = "foobar" 501 | AppInsightsKey = "foobar" 502 | AppInsightsBatchSize = 42 503 | AppInsightsInterval = 42 504 | Constraints = ["tag==api"] 505 | 506 | [ServiceFabric.TLS] 507 | CA = "foobar" 508 | CAOptional = true 509 | Cert = "foobar" 510 | Key = "foobar" 511 | InsecureSkipVerify = true 512 | 513 | [Rest] 514 | EntryPoint = "foobar" 515 | 516 | [API] 517 | EntryPoint = "foobar" 518 | Dashboard = true 519 | Debug = true 520 | [API.Statistics] 521 | RecentErrors = 42 522 | 523 | [Metrics] 524 | [Metrics.Prometheus] 525 | Buckets = [42.0, 42.0] 526 | EntryPoint = "foobar" 527 | [Metrics.Datadog] 528 | Address = "foobar" 529 | PushInterval = "10s" 530 | [Metrics.StatsD] 531 | Address = "foobar" 532 | PushInterval = "10s" 533 | [Metrics.InfluxDB] 534 | Address = "foobar" 535 | Protocol = "foobar" 536 | PushInterval = "10s" 537 | Database = "foobar" 538 | RetentionPolicy = "foobar" 539 | 540 | [Ping] 541 | EntryPoint = "foobar" 542 | 543 | [HostResolver] 544 | CnameFlattening = true 545 | ResolvConfig = "foobar" 546 | ResolvDepth = 42 547 | -------------------------------------------------------------------------------- /static/logs.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import "github.com/traefik/traefik/v2/pkg/types" 4 | 5 | func migrateAccessLog(oldCfg Configuration) *types.AccessLog { 6 | if oldCfg.AccessLog == nil { 7 | return nil 8 | } 9 | 10 | return &types.AccessLog{ 11 | FilePath: oldCfg.AccessLog.File, 12 | Format: oldCfg.AccessLog.Format, 13 | Filters: migrateAccessLogFilters(oldCfg), 14 | Fields: migrateAccessLogFields(oldCfg), 15 | BufferingSize: oldCfg.AccessLog.BufferingSize, 16 | } 17 | } 18 | 19 | func migrateAccessLogFields(oldCfg Configuration) *types.AccessLogFields { 20 | if oldCfg.AccessLog.Fields == nil { 21 | return nil 22 | } 23 | 24 | return &types.AccessLogFields{ 25 | DefaultMode: oldCfg.AccessLog.Fields.DefaultMode, 26 | Names: oldCfg.AccessLog.Fields.Names, 27 | Headers: migrateFieldHeaders(oldCfg), 28 | } 29 | } 30 | 31 | func migrateFieldHeaders(oldCfg Configuration) *types.FieldHeaders { 32 | if oldCfg.AccessLog.Fields.Headers == nil { 33 | return nil 34 | } 35 | 36 | return &types.FieldHeaders{ 37 | DefaultMode: oldCfg.AccessLog.Fields.Headers.DefaultMode, 38 | Names: oldCfg.AccessLog.Fields.Headers.Names, 39 | } 40 | } 41 | 42 | func migrateAccessLogFilters(oldCfg Configuration) *types.AccessLogFilters { 43 | if oldCfg.AccessLog.Filters == nil { 44 | return nil 45 | } 46 | 47 | return &types.AccessLogFilters{ 48 | StatusCodes: oldCfg.AccessLog.Filters.StatusCodes, 49 | RetryAttempts: oldCfg.AccessLog.Filters.RetryAttempts, 50 | MinDuration: convertDuration(oldCfg.AccessLog.Filters.Duration, 0), 51 | } 52 | } 53 | 54 | func migrateTraefikLog(oldCfg Configuration) *types.TraefikLog { 55 | logCfg := &types.TraefikLog{ 56 | Level: oldCfg.LogLevel, 57 | } 58 | 59 | if oldCfg.TraefikLog != nil { 60 | logCfg.FilePath = oldCfg.TraefikLog.File 61 | logCfg.Format = oldCfg.TraefikLog.Format 62 | } 63 | return logCfg 64 | } 65 | -------------------------------------------------------------------------------- /static/metrics.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "log" 5 | "time" 6 | 7 | ptypes "github.com/traefik/paerser/types" 8 | "github.com/traefik/traefik/v2/pkg/types" 9 | ) 10 | 11 | func migrateMetrics(oldCfg Configuration) *types.Metrics { 12 | if oldCfg.Metrics == nil { 13 | return nil 14 | } 15 | 16 | return &types.Metrics{ 17 | Prometheus: migratePrometheus(oldCfg), 18 | Datadog: migrateDatadog(oldCfg), 19 | StatsD: migrateStatsD(oldCfg), 20 | InfluxDB: migrateInfluxDB(oldCfg), 21 | } 22 | } 23 | 24 | func migrateInfluxDB(oldCfg Configuration) *types.InfluxDB { 25 | if oldCfg.Metrics.InfluxDB == nil { 26 | return nil 27 | } 28 | 29 | return &types.InfluxDB{ 30 | Address: oldCfg.Metrics.InfluxDB.Address, 31 | Protocol: oldCfg.Metrics.InfluxDB.Protocol, 32 | PushInterval: parsePushInterval(oldCfg.Metrics.InfluxDB.PushInterval), 33 | Database: oldCfg.Metrics.InfluxDB.Database, 34 | RetentionPolicy: oldCfg.Metrics.InfluxDB.RetentionPolicy, 35 | Username: "", 36 | Password: "", 37 | AddEntryPointsLabels: false, // FIXME true ? 38 | AddServicesLabels: false, // FIXME true ? 39 | } 40 | } 41 | 42 | func migrateStatsD(oldCfg Configuration) *types.Statsd { 43 | if oldCfg.Metrics.StatsD == nil { 44 | return nil 45 | } 46 | 47 | return &types.Statsd{ 48 | Address: oldCfg.Metrics.StatsD.Address, 49 | PushInterval: parsePushInterval(oldCfg.Metrics.StatsD.PushInterval), 50 | AddEntryPointsLabels: false, // FIXME true ? 51 | AddServicesLabels: false, // FIXME true ? 52 | } 53 | } 54 | 55 | func migrateDatadog(oldCfg Configuration) *types.Datadog { 56 | if oldCfg.Metrics.Datadog == nil { 57 | return nil 58 | } 59 | 60 | return &types.Datadog{ 61 | Address: oldCfg.Metrics.Datadog.Address, 62 | PushInterval: parsePushInterval(oldCfg.Metrics.Datadog.PushInterval), 63 | AddEntryPointsLabels: false, // FIXME true ? 64 | AddServicesLabels: false, // FIXME true ? 65 | } 66 | } 67 | 68 | func migratePrometheus(oldCfg Configuration) *types.Prometheus { 69 | if oldCfg.Metrics.Prometheus == nil { 70 | return nil 71 | } 72 | 73 | return &types.Prometheus{ 74 | Buckets: oldCfg.Metrics.Prometheus.Buckets, 75 | AddEntryPointsLabels: false, // FIXME true ? 76 | AddServicesLabels: false, // FIXME true ? 77 | EntryPoint: oldCfg.Metrics.Prometheus.EntryPoint, 78 | } 79 | } 80 | 81 | func parsePushInterval(value string) ptypes.Duration { 82 | if value == "" { 83 | return ptypes.Duration(10 * time.Second) 84 | } 85 | 86 | pushInternal, err := time.ParseDuration(value) 87 | if err != nil { 88 | log.Fatal(err) 89 | } 90 | 91 | return ptypes.Duration(pushInternal) 92 | } 93 | -------------------------------------------------------------------------------- /static/providers.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | ptypes "github.com/traefik/paerser/types" 9 | "github.com/traefik/traefik/v2/pkg/config/static" 10 | "github.com/traefik/traefik/v2/pkg/provider/docker" 11 | "github.com/traefik/traefik/v2/pkg/provider/file" 12 | "github.com/traefik/traefik/v2/pkg/provider/kubernetes/ingress" 13 | "github.com/traefik/traefik/v2/pkg/provider/marathon" 14 | "github.com/traefik/traefik/v2/pkg/provider/rancher" 15 | "github.com/traefik/traefik/v2/pkg/provider/rest" 16 | "github.com/traefik/traefik/v2/pkg/types" 17 | ) 18 | 19 | func migrateProviders(oldCfg Configuration) *static.Providers { 20 | if oldCfg.ECS != nil { 21 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.ECS), "*static.")) 22 | } 23 | if oldCfg.Consul != nil { 24 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Consul), "*static.")) 25 | } 26 | if oldCfg.ConsulCatalog != nil { 27 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.ConsulCatalog), "*static.")) 28 | } 29 | if oldCfg.Etcd != nil { 30 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Etcd), "*static.")) 31 | } 32 | if oldCfg.Zookeeper != nil { 33 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Zookeeper), "*static.")) 34 | } 35 | if oldCfg.Boltdb != nil { 36 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Boltdb), "*static.")) 37 | } 38 | if oldCfg.Mesos != nil { 39 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Mesos), "*static.")) 40 | } 41 | if oldCfg.Eureka != nil { 42 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.Eureka), "*static.")) 43 | } 44 | if oldCfg.DynamoDB != nil { 45 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.DynamoDB), "*static.")) 46 | } 47 | if oldCfg.ServiceFabric != nil { 48 | fmt.Printf("The %s provider is currently not supported by Traefik v2.\n", strings.TrimPrefix(fmt.Sprintf("%T", oldCfg.ServiceFabric), "*static.")) 49 | } 50 | 51 | return &static.Providers{ 52 | ProvidersThrottleDuration: convertDuration(oldCfg.ProvidersThrottleDuration, 2*time.Second), 53 | Docker: migrateDocker(oldCfg), 54 | File: migrateFile(oldCfg), 55 | Marathon: migrateMarathon(oldCfg), 56 | KubernetesIngress: migrateKubernetes(oldCfg), 57 | KubernetesCRD: nil, // SKIP 58 | Rest: migrateRest(oldCfg), 59 | Rancher: migrateRancher(oldCfg), 60 | } 61 | } 62 | 63 | func migrateRancher(oldCfg Configuration) *rancher.Provider { 64 | if oldCfg.Rancher == nil { 65 | return nil 66 | } 67 | 68 | if len(oldCfg.Rancher.Constraints) != 0 { 69 | fmt.Println("The constraints on the Rancher provider must be converted manually. https://docs.traefik.io/providers/rancher/#constraints") 70 | } 71 | 72 | rancherCfg := &rancher.Provider{ 73 | Constraints: "", // SKIP 74 | Watch: oldCfg.Rancher.Watch, 75 | DefaultRule: "", // SKIP 76 | ExposedByDefault: oldCfg.Rancher.ExposedByDefault, 77 | EnableServiceHealthFilter: oldCfg.Rancher.EnableServiceHealthFilter, 78 | RefreshSeconds: oldCfg.Rancher.RefreshSeconds, 79 | } 80 | 81 | if oldCfg.Rancher.Metadata != nil { 82 | rancherCfg.IntervalPoll = oldCfg.Rancher.Metadata.IntervalPoll 83 | rancherCfg.Prefix = oldCfg.Rancher.Metadata.Prefix 84 | } 85 | 86 | return rancherCfg 87 | } 88 | 89 | func migrateKubernetes(oldCfg Configuration) *ingress.Provider { 90 | if oldCfg.Kubernetes == nil { 91 | return nil 92 | } 93 | 94 | return &ingress.Provider{ 95 | Endpoint: oldCfg.Kubernetes.Endpoint, 96 | Token: oldCfg.Kubernetes.Token, 97 | CertAuthFilePath: oldCfg.Kubernetes.CertAuthFilePath, 98 | Namespaces: oldCfg.Kubernetes.Namespaces, 99 | LabelSelector: oldCfg.Kubernetes.LabelSelector, 100 | IngressClass: oldCfg.Kubernetes.IngressClass, 101 | ThrottleDuration: convertDuration(oldCfg.Kubernetes.ThrottleDuration, 0), 102 | IngressEndpoint: migrateIngressEndpoint(oldCfg), 103 | } 104 | } 105 | 106 | func migrateIngressEndpoint(oldCfg Configuration) *ingress.EndpointIngress { 107 | if oldCfg.Kubernetes.IngressEndpoint == nil { 108 | return nil 109 | } 110 | 111 | return &ingress.EndpointIngress{ 112 | IP: oldCfg.Kubernetes.IngressEndpoint.IP, 113 | Hostname: oldCfg.Kubernetes.IngressEndpoint.Hostname, 114 | PublishedService: oldCfg.Kubernetes.IngressEndpoint.PublishedService, 115 | } 116 | } 117 | 118 | func migrateMarathon(oldCfg Configuration) *marathon.Provider { 119 | if oldCfg.Marathon == nil { 120 | return nil 121 | } 122 | 123 | if len(oldCfg.Marathon.Constraints) != 0 { 124 | fmt.Println("The constraints on the Marathon provider must be converted manually. https://docs.traefik.io/providers/marathon/#constraints") 125 | } 126 | 127 | if oldCfg.Marathon.Domain != "" { 128 | fmt.Printf("The domain (%s) defined the Marathon provider must be converted manually. See https://docs.traefik.io/providers/marathon/#defaultrule\n", oldCfg.Marathon.Domain) 129 | } 130 | 131 | return &marathon.Provider{ 132 | Constraints: "", // TODO SKIP ? 133 | Trace: oldCfg.Marathon.Trace, 134 | Watch: oldCfg.Marathon.Watch, 135 | Endpoint: oldCfg.Marathon.Endpoint, 136 | DefaultRule: "", // TODO SKIP ? 137 | ExposedByDefault: oldCfg.Marathon.ExposedByDefault, 138 | DCOSToken: oldCfg.Marathon.DCOSToken, 139 | TLS: migrateClientTLS(oldCfg.Marathon.TLS), 140 | DialerTimeout: convertDuration(oldCfg.Marathon.DialerTimeout, 5*time.Second), 141 | ResponseHeaderTimeout: convertDuration(oldCfg.Marathon.ResponseHeaderTimeout, 60*time.Second), 142 | TLSHandshakeTimeout: convertDuration(oldCfg.Marathon.TLSHandshakeTimeout, 5*time.Second), 143 | KeepAlive: convertDuration(oldCfg.Marathon.KeepAlive, 10*time.Second), 144 | ForceTaskHostname: oldCfg.Marathon.ForceTaskHostname, 145 | RespectReadinessChecks: oldCfg.Marathon.RespectReadinessChecks, 146 | Basic: migrateMarathonBasic(oldCfg), 147 | } 148 | } 149 | 150 | func migrateMarathonBasic(oldCfg Configuration) *marathon.Basic { 151 | if oldCfg.Marathon.Basic == nil { 152 | return nil 153 | } 154 | 155 | return &marathon.Basic{ 156 | HTTPBasicAuthUser: oldCfg.Marathon.Basic.HTTPBasicAuthUser, 157 | HTTPBasicPassword: oldCfg.Marathon.Basic.HTTPBasicPassword, 158 | } 159 | } 160 | 161 | func migrateFile(oldCfg Configuration) *file.Provider { 162 | if oldCfg.File == nil { 163 | return nil 164 | } 165 | 166 | if oldCfg.File.Directory == "" && oldCfg.File.Filename == "" { 167 | fmt.Println("All the elements related to dynamic configuration (backends, frontends, ...) must be converted manually. See https://docs.traefik.io/routing/overview/") 168 | } 169 | 170 | return &file.Provider{ 171 | Directory: oldCfg.File.Directory, 172 | Watch: oldCfg.File.Watch, 173 | Filename: oldCfg.File.Filename, 174 | DebugLogGeneratedTemplate: oldCfg.File.DebugLogGeneratedTemplate, 175 | } 176 | } 177 | 178 | func migrateDocker(oldCfg Configuration) *docker.Provider { 179 | if oldCfg.Docker == nil { 180 | return nil 181 | } 182 | 183 | if len(oldCfg.Docker.Constraints) != 0 { 184 | fmt.Println("The constraints defined in the Docker provider must be converted manually. See https://docs.traefik.io/providers/docker/#constraints") 185 | } 186 | 187 | if oldCfg.Docker.Domain != "" { 188 | fmt.Printf("The domain (%s) defined in the Docker provider must be converted manually. See https://docs.traefik.io/providers/docker/#defaultrule\n", oldCfg.Docker.Domain) 189 | } 190 | 191 | swarmModeRefreshSeconds := ptypes.Duration(15 * time.Second) 192 | if oldCfg.Docker.SwarmModeRefreshSeconds > 0 { 193 | swarmModeRefreshSeconds = ptypes.Duration(time.Duration(oldCfg.Docker.SwarmModeRefreshSeconds) * time.Second) 194 | } 195 | 196 | return &docker.Provider{ 197 | Constraints: "", // TODO SKIP ? 198 | Watch: oldCfg.Docker.Watch, 199 | Endpoint: oldCfg.Docker.Endpoint, 200 | DefaultRule: "", // TODO SKIP ? 201 | TLS: migrateClientTLS(oldCfg.Docker.TLS), 202 | ExposedByDefault: oldCfg.Docker.ExposedByDefault, 203 | UseBindPortIP: oldCfg.Docker.UseBindPortIP, 204 | SwarmMode: oldCfg.Docker.SwarmMode, 205 | Network: oldCfg.Docker.Network, 206 | SwarmModeRefreshSeconds: swarmModeRefreshSeconds, 207 | } 208 | } 209 | 210 | func migrateRest(oldCfg Configuration) *rest.Provider { 211 | if oldCfg.Rest == nil { 212 | return nil 213 | } 214 | 215 | if oldCfg.Rest.EntryPoint != "" { 216 | fmt.Printf("The entry point (%s) defined in the REST provider must be converted manually. See https://docs.traefik.io/operations/api/\n", oldCfg.Rest.EntryPoint) 217 | } 218 | return &rest.Provider{ 219 | Insecure: true, 220 | } 221 | } 222 | 223 | func migrateClientTLS(oldClientTLS *ClientTLS) *types.ClientTLS { 224 | if oldClientTLS == nil { 225 | return nil 226 | } 227 | 228 | return &types.ClientTLS{ 229 | CA: oldClientTLS.Ca, 230 | CAOptional: oldClientTLS.CaOptional, 231 | Cert: oldClientTLS.Cert, 232 | Key: oldClientTLS.Key, 233 | InsecureSkipVerify: oldClientTLS.InsecureSkipVerify, 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /static/tracing.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "github.com/traefik/traefik/v2/pkg/config/static" 5 | "github.com/traefik/traefik/v2/pkg/tracing/datadog" 6 | "github.com/traefik/traefik/v2/pkg/tracing/jaeger" 7 | "github.com/traefik/traefik/v2/pkg/tracing/zipkin" 8 | ) 9 | 10 | func migrateTracing(oldCfg Configuration) *static.Tracing { 11 | if oldCfg.Tracing == nil { 12 | return nil 13 | } 14 | 15 | return &static.Tracing{ 16 | ServiceName: oldCfg.Tracing.ServiceName, 17 | SpanNameLimit: oldCfg.Tracing.SpanNameLimit, 18 | Jaeger: migrateJaeger(oldCfg), 19 | Zipkin: migrateZipkin(oldCfg), 20 | Datadog: migrateDatadogTracing(oldCfg), 21 | Instana: nil, // SKIP 22 | Haystack: nil, // SKIP 23 | } 24 | } 25 | 26 | func migrateJaeger(oldCfg Configuration) *jaeger.Config { 27 | if oldCfg.Tracing.Jaeger == nil { 28 | return nil 29 | } 30 | 31 | return &jaeger.Config{ 32 | SamplingServerURL: oldCfg.Tracing.Jaeger.SamplingServerURL, 33 | SamplingType: oldCfg.Tracing.Jaeger.SamplingType, 34 | SamplingParam: oldCfg.Tracing.Jaeger.SamplingParam, 35 | LocalAgentHostPort: oldCfg.Tracing.Jaeger.LocalAgentHostPort, 36 | Gen128Bit: false, // SKIP 37 | Propagation: "", // SKIP 38 | TraceContextHeaderName: oldCfg.Tracing.Jaeger.TraceContextHeaderName, 39 | Collector: nil, // SKIP 40 | } 41 | } 42 | 43 | func migrateZipkin(oldCfg Configuration) *zipkin.Config { 44 | if oldCfg.Tracing.Zipkin == nil { 45 | return nil 46 | } 47 | 48 | return &zipkin.Config{ 49 | HTTPEndpoint: oldCfg.Tracing.Zipkin.HTTPEndpoint, 50 | SameSpan: oldCfg.Tracing.Zipkin.SameSpan, 51 | ID128Bit: oldCfg.Tracing.Zipkin.ID128Bit, 52 | SampleRate: 0, // SKIP 53 | } 54 | } 55 | 56 | func migrateDatadogTracing(oldCfg Configuration) *datadog.Config { 57 | if oldCfg.Tracing.DataDog == nil { 58 | return nil 59 | } 60 | 61 | return &datadog.Config{ 62 | LocalAgentHostPort: oldCfg.Tracing.DataDog.LocalAgentHostPort, 63 | GlobalTag: oldCfg.Tracing.DataDog.GlobalTag, 64 | Debug: oldCfg.Tracing.DataDog.Debug, 65 | PrioritySampling: oldCfg.Tracing.DataDog.PrioritySampling, 66 | TraceIDHeaderName: oldCfg.Tracing.DataDog.TraceIDHeaderName, 67 | ParentIDHeaderName: oldCfg.Tracing.DataDog.ParentIDHeaderName, 68 | SamplingPriorityHeaderName: oldCfg.Tracing.DataDog.SamplingPriorityHeaderName, 69 | BagagePrefixHeaderName: oldCfg.Tracing.DataDog.BagagePrefixHeaderName, 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /static/v1.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | import ( 4 | "crypto/tls" 5 | 6 | "github.com/containous/flaeg/parse" 7 | ) 8 | 9 | type Configuration struct { 10 | LifeCycle *LifeCycle 11 | GraceTimeOut parse.Duration 12 | Debug bool 13 | CheckNewVersion bool 14 | SendAnonymousUsage bool 15 | AccessLogsFile string 16 | AccessLog *AccessLog 17 | TraefikLogsFile string 18 | TraefikLog *TraefikLog 19 | Tracing *Tracing 20 | LogLevel string 21 | EntryPoints *map[string]EntryPoint 22 | Constraints []string 23 | ACME *ACME 24 | DefaultEntryPoints []string 25 | ProvidersThrottleDuration parse.Duration 26 | MaxIdleConnsPerHost int 27 | IdleTimeout parse.Duration 28 | InsecureSkipVerify bool 29 | RootCAs []string 30 | Retry *Retry 31 | HealthCheck *HealthCheck 32 | RespondingTimeouts *RespondingTimeouts 33 | ForwardingTimeouts *ForwardingTimeouts 34 | AllowMinWeightZero bool 35 | KeepTrailingSlash bool 36 | Web *Web 37 | Docker *Docker 38 | File *File 39 | Marathon *Marathon 40 | Consul *Consul 41 | ConsulCatalog *ConsulCatalog 42 | Etcd *Etcd 43 | Zookeeper *Zookeeper 44 | Boltdb *Boltdb 45 | Kubernetes *Kubernetes 46 | Mesos *Mesos 47 | Eureka *Eureka 48 | ECS *ECS 49 | Rancher *Rancher 50 | DynamoDB *DynamoDB 51 | ServiceFabric *ServiceFabric 52 | Rest *Rest 53 | API *API 54 | Metrics *Metrics 55 | Ping *Ping 56 | HostResolver *HostResolver 57 | } 58 | 59 | type LifeCycle struct { 60 | RequestAcceptGraceTimeout parse.Duration 61 | GraceTimeOut parse.Duration 62 | } 63 | 64 | type Filters struct { 65 | StatusCodes []string 66 | RetryAttempts bool 67 | Duration parse.Duration 68 | } 69 | 70 | type Headers struct { 71 | DefaultMode string 72 | Names map[string]string 73 | } 74 | 75 | type Fields struct { 76 | DefaultMode string 77 | Names map[string]string 78 | Headers *Headers 79 | } 80 | 81 | type AccessLog struct { 82 | File string 83 | Format string 84 | Filters *Filters 85 | Fields *Fields 86 | BufferingSize int64 87 | } 88 | 89 | type TraefikLog struct { 90 | File string 91 | Format string 92 | } 93 | 94 | type Jaeger struct { 95 | SamplingServerURL string 96 | SamplingType string 97 | SamplingParam float64 98 | LocalAgentHostPort string 99 | TraceContextHeaderName string 100 | } 101 | 102 | type Zipkin struct { 103 | HTTPEndpoint string 104 | SameSpan bool 105 | ID128Bit bool 106 | Debug bool 107 | } 108 | 109 | type DataDog struct { 110 | LocalAgentHostPort string 111 | GlobalTag string 112 | Debug bool 113 | PrioritySampling bool 114 | TraceIDHeaderName string 115 | ParentIDHeaderName string 116 | SamplingPriorityHeaderName string 117 | BagagePrefixHeaderName string 118 | } 119 | 120 | type Tracing struct { 121 | Backend string 122 | ServiceName string 123 | SpanNameLimit int 124 | Jaeger *Jaeger 125 | Zipkin *Zipkin 126 | DataDog *DataDog 127 | } 128 | 129 | type Certificates struct { 130 | CertFile string 131 | KeyFile string 132 | } 133 | 134 | type ClientCA struct { 135 | Files []string 136 | Optional bool 137 | } 138 | 139 | type DefaultCertificate struct { 140 | CertFile string 141 | KeyFile string 142 | } 143 | 144 | type TLS struct { 145 | MinVersion string 146 | CipherSuites []string 147 | Certificates []Certificates 148 | ClientCAFiles []string 149 | ClientCA *ClientCA 150 | DefaultCertificate *DefaultCertificate 151 | SniStrict bool 152 | } 153 | 154 | type Redirect struct { 155 | EntryPoint string 156 | Regex string 157 | Replacement string 158 | Permanent bool 159 | } 160 | 161 | type AuthBasic struct { 162 | UsersFile string 163 | RemoveHeader bool 164 | } 165 | 166 | type Digest struct { 167 | UsersFile string 168 | RemoveHeader bool 169 | } 170 | 171 | type ClientTLS struct { 172 | Ca string 173 | CaOptional bool 174 | Cert string 175 | Key string 176 | InsecureSkipVerify bool 177 | } 178 | 179 | type Forward struct { 180 | Address string 181 | TLS *ClientTLS 182 | TrustForwardHeader bool 183 | AuthResponseHeaders []string 184 | } 185 | 186 | type Auth struct { 187 | Basic *AuthBasic 188 | Digest *Digest 189 | Forward *Forward 190 | HeaderField string 191 | } 192 | 193 | type WhiteList struct { 194 | SourceRange []string 195 | UseXForwardedFor bool 196 | } 197 | 198 | type ProxyProtocol struct { 199 | Insecure bool 200 | TrustedIPs []string 201 | } 202 | 203 | type ForwardedHeaders struct { 204 | Insecure bool 205 | TrustedIPs []string 206 | } 207 | 208 | type EntryPoint struct { 209 | Address string 210 | TLS *TLS 211 | Redirect *Redirect 212 | Auth *Auth 213 | WhitelistSourceRange []string 214 | WhiteList *WhiteList 215 | Compress bool 216 | ProxyProtocol *ProxyProtocol 217 | ForwardedHeaders *ForwardedHeaders 218 | } 219 | 220 | type Store struct { 221 | Prefix string 222 | } 223 | 224 | type Domains struct { 225 | Main string 226 | SANs []string 227 | } 228 | 229 | type DNSChallenge struct { 230 | Provider string 231 | DelayBeforeCheck parse.Duration 232 | Resolvers []string 233 | DisablePropagationCheck bool 234 | } 235 | 236 | type HTTPChallenge struct { 237 | EntryPoint string 238 | } 239 | 240 | type TLSChallenge struct{} 241 | 242 | type ACME struct { 243 | Email string 244 | Domains []Domains 245 | Storage string 246 | StorageFile string 247 | OnDemand bool 248 | OnHostRule bool 249 | CAServer string 250 | EntryPoint string 251 | KeyType string 252 | DNSChallenge *DNSChallenge 253 | HTTPChallenge *HTTPChallenge 254 | TLSChallenge *TLSChallenge 255 | DNSProvider string 256 | DelayDontCheckDNS parse.Duration 257 | ACMELogging bool 258 | OverrideCertificates bool 259 | TLSConfig *tls.Config 260 | } 261 | 262 | type Retry struct { 263 | Attempts int 264 | } 265 | 266 | type HealthCheck struct { 267 | Interval parse.Duration 268 | } 269 | 270 | type RespondingTimeouts struct { 271 | ReadTimeout parse.Duration 272 | WriteTimeout parse.Duration 273 | IdleTimeout parse.Duration 274 | } 275 | 276 | type ForwardingTimeouts struct { 277 | DialTimeout parse.Duration 278 | ResponseHeaderTimeout parse.Duration 279 | } 280 | 281 | type Statistics struct { 282 | RecentErrors int 283 | } 284 | 285 | type Prometheus struct { 286 | Buckets []float64 287 | EntryPoint string 288 | } 289 | 290 | type Datadog struct { 291 | Address string 292 | PushInterval string 293 | } 294 | 295 | type StatsD struct { 296 | Address string 297 | PushInterval string 298 | } 299 | 300 | type InfluxDB struct { 301 | Address string 302 | Protocol string 303 | PushInterval string 304 | Database string 305 | RetentionPolicy string 306 | } 307 | 308 | type Metrics struct { 309 | Prometheus *Prometheus 310 | Datadog *Datadog 311 | StatsD *StatsD 312 | InfluxDB *InfluxDB 313 | } 314 | 315 | type Web struct { 316 | Address string 317 | CertFile string 318 | KeyFile string 319 | ReadOnly bool 320 | Statistics *Statistics 321 | Metrics *Metrics 322 | Path string 323 | Auth *Auth 324 | Debug bool 325 | } 326 | 327 | type Docker struct { 328 | Watch bool 329 | Filename string 330 | Constraints []string 331 | Trace bool 332 | TemplateVersion int 333 | DebugLogGeneratedTemplate bool 334 | Endpoint string 335 | Domain string 336 | TLS *ClientTLS 337 | ExposedByDefault bool 338 | UseBindPortIP bool 339 | SwarmMode bool 340 | Network string 341 | SwarmModeRefreshSeconds int 342 | } 343 | 344 | type File struct { 345 | Watch bool 346 | Filename string 347 | Constraints []string 348 | Trace bool 349 | TemplateVersion int 350 | DebugLogGeneratedTemplate bool 351 | Directory string 352 | TraefikFile string 353 | } 354 | 355 | type Basic struct { 356 | HTTPBasicAuthUser string 357 | HTTPBasicPassword string 358 | } 359 | 360 | type Marathon struct { 361 | Watch bool 362 | Filename string 363 | Constraints []string 364 | Trace bool 365 | TemplateVersion int 366 | DebugLogGeneratedTemplate bool 367 | Endpoint string 368 | Domain string 369 | ExposedByDefault bool 370 | GroupsAsSubDomains bool 371 | DCOSToken string 372 | MarathonLBCompatibility bool 373 | FilterMarathonConstraints bool 374 | TLS *ClientTLS 375 | DialerTimeout parse.Duration 376 | ResponseHeaderTimeout parse.Duration 377 | TLSHandshakeTimeout parse.Duration 378 | KeepAlive parse.Duration 379 | ForceTaskHostname bool 380 | Basic *Basic 381 | RespectReadinessChecks bool 382 | } 383 | 384 | type Consul struct { 385 | Watch bool 386 | Filename string 387 | Constraints []string 388 | Trace bool 389 | TemplateVersion int 390 | DebugLogGeneratedTemplate bool 391 | Endpoint string 392 | Prefix string 393 | TLS *ClientTLS 394 | Username string 395 | Password string 396 | } 397 | 398 | type ConsulCatalog struct { 399 | Watch bool 400 | Filename string 401 | Constraints []string 402 | Trace bool 403 | TemplateVersion int 404 | DebugLogGeneratedTemplate bool 405 | Endpoint string 406 | Domain string 407 | Stale bool 408 | ExposedByDefault bool 409 | Prefix string 410 | StrictChecks bool 411 | FrontEndRule string 412 | TLS *ClientTLS 413 | } 414 | 415 | type Etcd struct { 416 | Watch bool 417 | Filename string 418 | Constraints []string 419 | Trace bool 420 | TemplateVersion int 421 | DebugLogGeneratedTemplate bool 422 | Endpoint string 423 | Prefix string 424 | TLS *ClientTLS 425 | Username string 426 | Password string 427 | UseAPIV3 bool 428 | } 429 | 430 | type Zookeeper struct { 431 | Watch bool 432 | Filename string 433 | Constraints []string 434 | Trace bool 435 | TemplateVersion int 436 | DebugLogGeneratedTemplate bool 437 | Endpoint string 438 | Prefix string 439 | TLS *ClientTLS 440 | Username string 441 | Password string 442 | } 443 | 444 | type Boltdb struct { 445 | Watch bool 446 | Filename string 447 | Constraints []string 448 | Trace bool 449 | TemplateVersion int 450 | DebugLogGeneratedTemplate bool 451 | Endpoint string 452 | Prefix string 453 | TLS *ClientTLS 454 | Username string 455 | Password string 456 | } 457 | 458 | type IngressEndpoint struct { 459 | IP string 460 | Hostname string 461 | PublishedService string 462 | } 463 | 464 | type Kubernetes struct { 465 | Watch bool 466 | Filename string 467 | Constraints []string 468 | Trace bool 469 | TemplateVersion int 470 | DebugLogGeneratedTemplate bool 471 | Endpoint string 472 | Token string 473 | CertAuthFilePath string 474 | DisablePassHostHeaders bool 475 | EnablePassTLSCert bool 476 | Namespaces []string 477 | LabelSelector string 478 | IngressClass string 479 | IngressEndpoint *IngressEndpoint 480 | ThrottleDuration parse.Duration 481 | } 482 | 483 | type Mesos struct { 484 | Watch bool 485 | Filename string 486 | Constraints []string 487 | Trace bool 488 | TemplateVersion int 489 | DebugLogGeneratedTemplate bool 490 | Endpoint string 491 | Domain string 492 | ExposedByDefault bool 493 | GroupsAsSubDomains bool 494 | ZkDetectionTimeout int 495 | RefreshSeconds int 496 | IPSources string 497 | StateTimeoutSecond int 498 | Masters []string 499 | } 500 | 501 | type Eureka struct { 502 | Watch bool 503 | Filename string 504 | Constraints []string 505 | Trace bool 506 | TemplateVersion int 507 | DebugLogGeneratedTemplate bool 508 | Endpoint string 509 | Delay parse.Duration 510 | RefreshSeconds parse.Duration 511 | } 512 | 513 | type ECS struct { 514 | Watch bool 515 | Filename string 516 | Constraints []string 517 | Trace bool 518 | TemplateVersion int 519 | DebugLogGeneratedTemplate bool 520 | Domain string 521 | ExposedByDefault bool 522 | RefreshSeconds int 523 | Clusters []string 524 | Cluster string 525 | AutoDiscoverClusters bool 526 | Region string 527 | AccessKeyID string 528 | SecretAccessKey string 529 | } 530 | 531 | type RancherAPI struct { 532 | Endpoint string 533 | AccessKey string 534 | SecretKey string 535 | } 536 | 537 | type Metadata struct { 538 | IntervalPoll bool 539 | Prefix string 540 | } 541 | 542 | type Rancher struct { 543 | Watch bool 544 | Filename string 545 | Constraints []string 546 | Trace bool 547 | TemplateVersion int 548 | DebugLogGeneratedTemplate bool 549 | Endpoint string 550 | AccessKey string 551 | SecretKey string 552 | API *RancherAPI 553 | Metadata *Metadata 554 | Domain string 555 | RefreshSeconds int 556 | ExposedByDefault bool 557 | EnableServiceHealthFilter bool 558 | } 559 | 560 | type DynamoDB struct { 561 | Watch bool 562 | Filename string 563 | Constraints []string 564 | Trace bool 565 | TemplateVersion int 566 | DebugLogGeneratedTemplate bool 567 | AccessKeyID string 568 | RefreshSeconds int 569 | Region string 570 | SecretAccessKey string 571 | TableName string 572 | Endpoint string 573 | } 574 | 575 | type ServiceFabric struct { 576 | Watch bool 577 | Filename string 578 | Constraints []string 579 | Trace bool 580 | TemplateVersion int 581 | DebugLogGeneratedTemplate bool 582 | ClusterManagementURL string 583 | APIVersion string 584 | RefreshSeconds int 585 | TLS *ClientTLS 586 | AppInsightsClientName string 587 | AppInsightsKey string 588 | AppInsightsBatchSize int 589 | AppInsightsInterval int 590 | } 591 | 592 | type Rest struct { 593 | EntryPoint string 594 | } 595 | 596 | type API struct { 597 | EntryPoint string 598 | Dashboard bool 599 | Debug bool 600 | Statistics *Statistics 601 | } 602 | 603 | type Ping struct { 604 | EntryPoint string 605 | } 606 | 607 | type HostResolver struct { 608 | CnameFlattening bool 609 | ResolvConfig string 610 | ResolvDepth int 611 | } 612 | -------------------------------------------------------------------------------- /tmpl.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1-alpine as builder 2 | 3 | RUN apk --update upgrade \ 4 | && apk --no-cache --no-progress add git make gcc musl-dev ca-certificates tzdata 5 | 6 | WORKDIR /go/traefik-migration-tool 7 | 8 | ENV GO111MODULE on 9 | COPY go.mod go.sum ./ 10 | RUN go mod download 11 | 12 | COPY . . 13 | RUN GOARCH={{ .GoARCH }} GOARM={{ .GoARM }} make build 14 | 15 | FROM {{ .RuntimeImage }} 16 | 17 | # Not supported for multi-arch without Buildkit or QEMU 18 | #RUN apk --update upgrade \ 19 | # && apk --no-cache --no-progress add ca-certificates 20 | 21 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ 22 | COPY --from=builder /go/traefik-migration-tool/traefik-migration-tool . 23 | 24 | ENTRYPOINT ["/traefik-migration-tool"] 25 | --------------------------------------------------------------------------------