├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── documentation.yml
│ └── pull_request.yml
├── .gitignore
├── .golangci.toml
├── .goreleaser.yml
├── .semaphore
└── semaphore.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
├── cleanup
│ └── cleanup.go
├── configuration.go
├── context.go
├── loaders.go
├── log.go
├── mesh
│ └── mesh.go
├── prepare
│ └── prepare.go
└── version
│ └── version.go
├── docs
├── .dockerignore
├── .markdownlint.json
├── Makefile
├── check.Dockerfile
├── content
│ ├── api.md
│ ├── assets
│ │ ├── img
│ │ │ ├── after-traefik-mesh-graphic.png
│ │ │ ├── before-traefik-mesh-graphic.png
│ │ │ ├── smi.png
│ │ │ ├── traefik-mesh-logo.svg
│ │ │ └── traefik-mesh.png
│ │ └── js
│ │ │ ├── extra.js
│ │ │ └── hljs
│ │ │ ├── LICENSE
│ │ │ └── highlight.pack.js
│ ├── compatibility.md
│ ├── configuration.md
│ ├── contributing
│ │ ├── building-testing.md
│ │ ├── documentation.md
│ │ ├── maintainers.md
│ │ ├── submitting-issues.md
│ │ ├── submitting-pull-requests.md
│ │ └── thank-you.md
│ ├── examples.md
│ ├── index.md
│ ├── install.md
│ ├── migration
│ │ ├── helm-chart.md
│ │ └── traefik-mesh-v1.md
│ └── quickstart.md
├── docs.Dockerfile
├── mkdocs.yml
├── readme.md
├── requirements.txt
├── runtime.txt
└── scripts
│ ├── lint.sh
│ ├── netlify-run.sh
│ └── verify.sh
├── go.mod
├── go.sum
├── integration
├── acl_disabled_test.go
├── acl_enabled_test.go
├── coredns_test.go
├── integration_test.go
├── k3d
│ └── k3d.go
├── kubedns_test.go
├── testdata
│ ├── acl_disabled
│ │ ├── http
│ │ │ └── 1.server.yaml
│ │ ├── tcp
│ │ │ └── 1.server.yaml
│ │ ├── traffic-split
│ │ │ ├── 1.server.yaml
│ │ │ ├── 2.server-v1.yaml
│ │ │ └── 3.server-v2.yaml
│ │ └── udp
│ │ │ └── 1.server.yaml
│ ├── acl_enabled
│ │ ├── http
│ │ │ ├── 0.service-account.yaml
│ │ │ ├── 1.server.yaml
│ │ │ ├── 3.server-api.yaml
│ │ │ ├── 4.server-header.yaml
│ │ │ ├── 6.traffic-target.yaml
│ │ │ ├── 7.traffic-target-path-filter.yaml
│ │ │ └── 8.traffic-target-header-filter.yaml
│ │ └── traffic-split
│ │ │ ├── 0.service-account.yaml
│ │ │ └── 1.server-split.yaml
│ ├── coredns
│ │ └── whoami-shadow-service.yaml
│ ├── crds
│ │ ├── smi-access.yaml
│ │ ├── smi-specs.yaml
│ │ └── smi-split.yaml
│ ├── kubedns
│ │ ├── coredns.yaml
│ │ └── kubedns.yaml
│ ├── tool
│ │ ├── tool-authorized.yaml
│ │ ├── tool-forbidden.yaml
│ │ └── tool.yaml
│ └── traefik-mesh
│ │ ├── controller-acl-disabled.yaml
│ │ ├── controller-acl-enabled.yaml
│ │ ├── proxy.yaml
│ │ └── values.yaml
├── tool
│ └── tool.go
└── try
│ ├── condition.go
│ └── try.go
├── netlify.toml
├── pkg
├── annotations
│ ├── annotations.go
│ ├── annotations_test.go
│ ├── middleware.go
│ └── middleware_test.go
├── api
│ ├── api.go
│ ├── api_test.go
│ └── testdata
│ │ ├── getmeshnodeconfiguration_empty.yaml
│ │ ├── getmeshnodeconfiguration_simple.yaml
│ │ ├── getmeshnodes_empty.yaml
│ │ ├── getmeshnodes_one_mesh_pod.yaml
│ │ └── getmeshnodes_one_nonready_mesh_pod.yaml
├── cleanup
│ ├── cleanup.go
│ ├── cleanup_test.go
│ └── testdata
│ │ └── mock.yaml
├── controller
│ ├── controller.go
│ ├── controller_test.go
│ ├── handler.go
│ ├── handler_test.go
│ ├── portmapping.go
│ ├── portmapping_test.go
│ ├── service.go
│ ├── service_test.go
│ └── testdata
│ │ ├── getmeshnodeconfiguration_empty.yaml
│ │ ├── getmeshnodeconfiguration_simple.yaml
│ │ ├── getmeshnodes_empty.yaml
│ │ ├── getmeshnodes_one_mesh_pod.yaml
│ │ ├── getmeshnodes_one_nonready_mesh_pod.yaml
│ │ └── mock.yaml
├── dns
│ ├── dns.go
│ ├── dns_test.go
│ └── testdata
│ │ ├── checkdnsprovider_coredns_using_label.yaml
│ │ ├── checkdnsprovider_kubedns.yaml
│ │ ├── checkdnsprovider_no_provider.yaml
│ │ ├── checkdnsprovider_supported_min_version_suffix.yaml
│ │ ├── checkdnsprovider_supported_version.yaml
│ │ ├── checkdnsprovider_supported_version_suffix.yaml
│ │ ├── checkdnsprovider_unsupported_version.yaml
│ │ ├── configurecoredns_17.yaml
│ │ ├── configurecoredns_17_already_patched.yaml
│ │ ├── configurecoredns_17_custom_already_patched.yaml
│ │ ├── configurecoredns_17_suffix.yaml
│ │ ├── configurecoredns_already_patched.yaml
│ │ ├── configurecoredns_custom_already_patched.yaml
│ │ ├── configurecoredns_custom_not_patched.yaml
│ │ ├── configurecoredns_missing_configmap.yaml
│ │ ├── configurecoredns_missing_deployment.yaml
│ │ ├── configurecoredns_not_patched.yaml
│ │ ├── configurekubedns_already_patched.yaml
│ │ ├── configurekubedns_missing_deployment.yaml
│ │ ├── configurekubedns_not_patched.yaml
│ │ ├── configurekubedns_optional_configmap.yaml
│ │ ├── restorecoredns_custom_not_patched.yaml
│ │ ├── restorecoredns_custom_patched.yaml
│ │ ├── restorecoredns_not_patched.yaml
│ │ ├── restorecoredns_patched.yaml
│ │ ├── restorekubedns_already_patched.yaml
│ │ └── restorekubedns_not_patched.yaml
├── k8s
│ ├── client.go
│ ├── client_mock.go
│ ├── constants.go
│ ├── filter.go
│ ├── filter_test.go
│ ├── smi.go
│ └── testdata
│ │ └── mock.yaml
├── provider
│ ├── key.go
│ ├── provider.go
│ ├── provider_test.go
│ ├── rule.go
│ └── testdata
│ │ ├── acl-disabled-http-basic-config.json
│ │ ├── acl-disabled-http-basic-topology.json
│ │ ├── acl-disabled-http-traffic-split-config.json
│ │ ├── acl-disabled-http-traffic-split-topology.json
│ │ ├── acl-disabled-tcp-basic-config.json
│ │ ├── acl-disabled-tcp-basic-topology.json
│ │ ├── acl-disabled-udp-basic-config.json
│ │ ├── acl-disabled-udp-basic-topology.json
│ │ ├── acl-enabled-http-basic-config.json
│ │ ├── acl-enabled-http-basic-topology.json
│ │ ├── acl-enabled-http-route-group-config.json
│ │ ├── acl-enabled-http-route-group-topology.json
│ │ ├── acl-enabled-http-traffic-split-config.json
│ │ ├── acl-enabled-http-traffic-split-http-route-group-config.json
│ │ ├── acl-enabled-http-traffic-split-http-route-group-topology.json
│ │ ├── acl-enabled-http-traffic-split-topology.json
│ │ ├── acl-enabled-tcp-basic-config.json
│ │ ├── acl-enabled-tcp-basic-topology.json
│ │ ├── annotations-scheme-config.json
│ │ ├── annotations-scheme-topology.json
│ │ ├── annotations-traffic-type-config.json
│ │ └── annotations-traffic-type-topology.json
├── safe
│ ├── recover.go
│ ├── recover_test.go
│ ├── safe.go
│ └── safe_test.go
├── topology
│ ├── builder.go
│ ├── builder_test.go
│ ├── testdata
│ │ ├── topology-empty-destination-port.json
│ │ ├── topology-multi-sources-destinations.json
│ │ ├── topology-service-with-pod-port-mixture.json
│ │ ├── topology-spec-with-empty-match.json
│ │ ├── topology-traffic-split-specs.json
│ │ ├── topology-traffic-split-traffic-target.json
│ │ ├── topology-traffic-target-service-port-mismatch.json
│ │ └── topology-traffic-target.json
│ ├── topology.go
│ └── topology_test.go
└── version
│ └── version.go
├── spinach.yaml
└── tmpl.Dockerfile
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Create a report to help us improve Traefik Mesh.
3 | labels: ['status/0-needs-triage']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | **DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.**
9 |
10 | The issue tracker is for reporting bugs and feature requests only.
11 | For end-user related support questions, please use the [Traefik Mesh community forum](https://community.traefik.io/c/traefik-mesh).
12 |
13 | ### How to write a good bug report?
14 |
15 | - Respect the issue template as much as possible.
16 | - The title should be short and descriptive.
17 | - Explain the conditions which led you to report this issue: the context.
18 | - The context should lead to something, an idea or a problem that you’re facing.
19 | - Remain clear and concise.
20 | - Format your messages to help the reader focus on what matters and understand the structure of your message, use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown)
21 |
22 | - type: checkboxes
23 | id: terms
24 | attributes:
25 | label: Welcome!
26 | options:
27 | - label: Yes, I've searched similar issues on [GitHub](https://github.com/traefik/mesh/issues) and didn't find any.
28 | required: true
29 | - label: Yes, I've searched similar issues on the [Traefik Mesh community forum](https://community.traefik.io/c/traefik-mesh) and didn't find any.
30 | required: true
31 |
32 | - type: textarea
33 | id: expect
34 | attributes:
35 | label: What did you expect to see?
36 | description: Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
37 | placeholder: What did you expect to see?
38 | validations:
39 | required: true
40 |
41 | - type: textarea
42 | id: instead
43 | attributes:
44 | label: What did you see instead?
45 | description: Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
46 | placeholder: What did you see instead?
47 | validations:
48 | required: true
49 |
50 | - type: input
51 | id: version
52 | attributes:
53 | label: What version of Traefik Mesh are you using?
54 | description: |
55 | `latest` is not considered as a valid version.
56 | We need a release number!
57 | validations:
58 | required: true
59 |
60 | - type: textarea
61 | id: controller
62 | attributes:
63 | label: Output of controller log
64 | placeholder: paste your output here
65 | render: shell
66 | validations:
67 | required: true
68 |
69 | - type: textarea
70 | id: environment
71 | attributes:
72 | label: What is your environment & configuration?
73 | description: |
74 | arguments, YAML, TOML, provider, platform, etc.
75 |
76 | Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
77 | placeholder: Add information here.
78 | validations:
79 | required: true
80 |
81 | - type: textarea
82 | id: objects
83 | attributes:
84 | label: If applicable, please paste the yaml objects required to reproduce your issue
85 | placeholder: Paste your objects here
86 | render: shell
87 | validations:
88 | required: false
89 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Question
4 | about: Please ask and answer questions here.
5 | url: https://community.traefik.io/c/traefik-mesh
6 | - name: Documentation
7 | url: https://doc.traefik.io/traefik-mesh/
8 | about: Please take a look to our documenation.
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Propose a change to Traefik Mesh!
3 | labels: ['status/0-needs-triage']
4 | body:
5 | - type: checkboxes
6 | id: terms
7 | attributes:
8 | label: Welcome!
9 | options:
10 | - label: Yes, I've searched similar issues on [GitHub](https://github.com/traefik/mesh/issues) and didn't find any.
11 | required: true
12 | - label: Yes, I've searched similar issues on the [Traefik Mesh community forum](https://community.traefik.io/c/traefik-mesh) and didn't find any.
13 | required: true
14 |
15 | - type: textarea
16 | id: proposal
17 | attributes:
18 | label: Proposal
19 | description: |
20 | Write your feature request in the form of a proposal to be considered for implementation.
21 |
22 | Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
23 | placeholder: Write your feature request in the form of a proposal to be considered for implementation.
24 | validations:
25 | required: true
26 |
27 | - type: textarea
28 | id: background
29 | attributes:
30 | label: Background
31 | description: |
32 | Describe the background problem or need that led to this feature request.
33 |
34 | Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
35 | placeholder: Describe the background problem or need that led to this feature request.
36 | validations:
37 | required: true
38 |
39 | - type: textarea
40 | id: workarounds
41 | attributes:
42 | label: Workarounds
43 | description: |
44 | Are there any current workarounds that you're using that others in similar positions should know?
45 |
46 | Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
47 | placeholder: Are there any current workarounds that you're using that others in similar positions should know?
48 | validations:
49 | required: true
50 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## What does this PR do?
2 |
3 | This PR:
4 |
5 | -
6 |
7 | Fixes #
8 |
9 |
10 |
11 | ### How to test it
12 |
13 | * Step 1
14 | * Step 2
15 | * ...
16 |
17 | ## Additional Notes
18 |
19 |
23 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yml:
--------------------------------------------------------------------------------
1 | name: Build and Publish Documentation
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - v*
8 |
9 | jobs:
10 |
11 | docs:
12 | name: Doc Process
13 | runs-on: ubuntu-latest
14 | if: github.repository == 'traefik/mesh'
15 | env:
16 | STRUCTOR_VERSION: v1.11.2
17 | MIXTUS_VERSION: v0.4.1
18 |
19 | steps:
20 |
21 | - name: Check out code
22 | uses: actions/checkout@v2
23 | with:
24 | fetch-depth: 0
25 |
26 | - name: Login to DockerHub
27 | uses: docker/login-action@v1
28 | with:
29 | username: ${{ secrets.DOCKERHUB_USERNAME }}
30 | password: ${{ secrets.DOCKERHUB_TOKEN }}
31 |
32 | - name: Install Structor ${{ env.STRUCTOR_VERSION }}
33 | run: curl -sSfL https://raw.githubusercontent.com/traefik/structor/master/godownloader.sh | sh -s -- -b $HOME/bin ${STRUCTOR_VERSION}
34 |
35 | - name: Install Seo-doc
36 | run: curl -sSfL https://raw.githubusercontent.com/traefik/seo-doc/master/godownloader.sh | sh -s -- -b "${HOME}/bin"
37 |
38 | - name: Install Mixtus ${{ env.MIXTUS_VERSION }}
39 | run: curl -sSfL https://raw.githubusercontent.com/traefik/mixtus/master/godownloader.sh | sh -s -- -b $HOME/bin ${MIXTUS_VERSION}
40 |
41 | - name: Build documentation
42 | run: $HOME/bin/structor -o traefik -r mesh --dockerfile-url="https://raw.githubusercontent.com/traefik/mesh/master/docs/docs.Dockerfile" --menu.js-url="https://raw.githubusercontent.com/traefik/structor/master/traefik-menu.js.gotmpl" --rqts-url="https://raw.githubusercontent.com/traefik/structor/master/requirements-override.txt" --force-edit-url --exp-branch=master --debug
43 | env:
44 | STRUCTOR_LATEST_TAG: ${{ secrets.STRUCTOR_LATEST_TAG }}
45 |
46 | - name: Apply seo
47 | run: $HOME/bin/seo -path=./site -product="traefik-mesh"
48 |
49 | - name: Publish documentation
50 | run: $HOME/bin/mixtus --dst-doc-path="./traefik-mesh" --dst-owner=traefik --dst-repo-name=doc --git-user-email="30906710+traefiker@users.noreply.github.com" --git-user-name=traefiker --src-doc-path="./site" --src-owner=traefik --src-repo-name=mesh
51 | env:
52 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
53 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: Build Documentation
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 |
8 | docs:
9 | name: Doc package
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 |
14 | - name: Check out code
15 | uses: actions/checkout@v2
16 | with:
17 | fetch-depth: 0
18 |
19 | - name: Package documentation
20 | run: make docs-package
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .intellij/
3 | *.iml
4 | .DS_Store
5 | /static/
6 | /site/
7 | /docs/site/
8 | /dist
9 | *.log
10 | *.exe
11 | cover.out
12 | traefik-mesh
13 | /dist/
14 | .vscode
15 | vendor
16 | pages/
17 | mesh-gh-pages*
18 | *.zip
19 |
--------------------------------------------------------------------------------
/.golangci.toml:
--------------------------------------------------------------------------------
1 | [run]
2 | timeout = "5m"
3 |
4 | [linters-settings]
5 |
6 | [linters-settings.govet]
7 | check-shadowing = true
8 |
9 | [linters-settings.golint]
10 | min-confidence = 0.0
11 |
12 | [linters-settings.gocyclo]
13 | min-complexity = 15.0
14 |
15 | [linters-settings.gocognit]
16 | min-complexity = 15.0
17 |
18 | [linters-settings.goconst]
19 | min-len = 3.0
20 | min-occurrences = 3.0
21 |
22 | [linters-settings.misspell]
23 | locale = "US"
24 |
25 | [linters-settings.stylecheck]
26 | checks = ["all", "-ST1000"]
27 |
28 | [linters-settings.gomoddirectives]
29 | replace-allow-list = [
30 | "github.com/abbot/go-http-auth",
31 | "github.com/go-check/check",
32 | "github.com/gorilla/mux",
33 | "github.com/mailgun/minheap",
34 | ]
35 |
36 | [linters]
37 | enable-all = true
38 | disable = [
39 | "sqlclosecheck", # Not relevant (SQL)
40 | "rowserrcheck", # Not relevant (SQL)
41 | "ifshort", # Deprecated
42 | "interfacer", # Deprecated
43 | "golint", # Deprecated
44 | "maligned", # Deprecated
45 | "scopelint", # Deprecated
46 | "cyclop", # Duplicate of gocyclo
47 | "lll", # Long lines are ok.
48 | "dupl", # Not relevant
49 | "prealloc", # Not relevant
50 | "gochecknoinits", # Too strict
51 | "gochecknoglobals", # Too strict
52 | "gomnd", # Does not allow for any config or time values
53 | "gosec", # Does not allow exec.Command with variable
54 | "bodyclose", # Too many false positives
55 | "goconst", # Too many false positives
56 | "wrapcheck", # Too strict
57 | "goerr113", # Forces wrapping all errors
58 | "noctx", # Too strict
59 | "exhaustive", # Too strict
60 | "exhaustivestruct", # Too strict
61 | "exhaustruct", # Duplicate of exhaustivestruct
62 | "nlreturn", # Too strict
63 | "ireturn", # Not relevant
64 | "varnamelen", # Not relevant
65 | "nilnil", # Not relevant
66 | "testpackage", # Does not allow testing private funcs
67 | "tparallel", # Not relevant
68 | "paralleltest", # Not relevant
69 | "forcetypeassert", # Too strict
70 | "nonamedreturns", # Not relevant
71 | "structcheck", # Duplicate of unused
72 | "funlen",
73 | ]
74 |
75 | [issues]
76 | exclude-use-default = false
77 | max-per-linter = 0
78 | max-same-issues = 0
79 | exclude = [
80 | "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
81 | "should have a package comment, unless it's in another file for this package",
82 | ]
83 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | project_name: traefik-mesh
2 |
3 | builds:
4 | - binary: traefik-mesh
5 |
6 | main: ./cmd/mesh/mesh.go
7 | env:
8 | - CGO_ENABLED=0
9 | ldflags:
10 | - -s -w
11 | - -X github.com/traefik/mesh/pkg/version.Version={{.Version}}
12 | - -X github.com/traefik/mesh/pkg/version.Commit={{.Commit}}
13 | - -X github.com/traefik/mesh/pkg/version.Date={{.Date}}
14 | goos:
15 | - linux
16 | - freebsd
17 | - openbsd
18 | goarch:
19 | - amd64
20 | - 386
21 | - arm
22 | - arm64
23 | goarm:
24 | - 7
25 |
26 | ignore:
27 | - goos: freebsd
28 | goarch: arm64
29 | - goos: openbsd
30 | goarch: arm64
31 |
32 | archives:
33 | - id: traefik-mesh
34 | name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
35 | format: tar.gz
36 | files:
37 | - LICENSE
38 |
39 | checksum:
40 | name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt"
41 |
42 | changelog:
43 | sort: asc
44 | filters:
45 | exclude:
46 | - '^docs:'
47 | - '^doc:'
48 | - '^chore:'
49 | - '^test:'
50 | - '^tests:'
51 |
--------------------------------------------------------------------------------
/.semaphore/semaphore.yml:
--------------------------------------------------------------------------------
1 | version: v1.0
2 | name: Traefik Mesh Pipeline
3 |
4 | agent:
5 | machine:
6 | type: e1-standard-4
7 | os_image: ubuntu1804
8 |
9 | auto_cancel:
10 | running:
11 | when: "branch != 'master'"
12 |
13 | fail_fast:
14 | stop:
15 | when: "branch != 'master'"
16 |
17 | global_job_config:
18 | secrets:
19 | - name: dockerhub-pull-secrets
20 | prologue:
21 | commands:
22 | - curl -sSfL https://raw.githubusercontent.com/ldez/semgo/master/godownloader.sh | sudo sh -s -- -b "/usr/local/bin"
23 | - sudo semgo go1.19
24 | - echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
25 | - checkout
26 |
27 | blocks:
28 | - name: Build
29 | run:
30 | when: "branch =~ '.*' OR pull_request =~ '.*'"
31 | task:
32 | jobs:
33 | - name: Cache Go dependencies
34 | commands:
35 | - cache restore
36 | - go mod tidy
37 | - git diff --exit-code go.mod
38 | - git diff --exit-code go.sum
39 | - cache store
40 | - name: Build and check
41 | commands:
42 | - make check build
43 | - cache store traefik-mesh-dist-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_WORKFLOW_ID dist
44 | - docker save traefik/mesh:latest > traefik-mesh-img.tar
45 | - cache store traefik-mesh-img-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_WORKFLOW_ID traefik-mesh-img.tar
46 |
47 | - name: Unit Tests
48 | run:
49 | when: "branch =~ '.*' OR pull_request =~ '.*'"
50 | task:
51 | prologue:
52 | commands:
53 | - cache restore
54 | jobs:
55 | - name: Unit Tests
56 | commands:
57 | - make local-test
58 |
59 | - name: Integration Tests
60 | run:
61 | when: "branch =~ '.*' OR pull_request =~ '.*'"
62 | task:
63 | prologue:
64 | commands:
65 | - cache restore
66 | - cache restore traefik-mesh-dist-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_WORKFLOW_ID
67 | - cache restore traefik-mesh-img-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_WORKFLOW_ID
68 | - docker load < traefik-mesh-img.tar
69 | jobs:
70 | - name: ACL Enabled Suite
71 | commands:
72 | - "make test-integration-nobuild TESTFLAGS=\"-check.f ACLEnabledSuite\""
73 | - name: ACL Disabled Suite
74 | commands:
75 | - "make test-integration-nobuild TESTFLAGS=\"-check.f ACLDisabledSuite\""
76 | - name: CoreDNS Suite
77 | commands:
78 | - "make test-integration-nobuild TESTFLAGS=\"-check.f CoreDNSSuite\""
79 | - name: KubeDNS Suite
80 | commands:
81 | - "make test-integration-nobuild TESTFLAGS=\"-check.f KubeDNSSuite\""
82 |
83 | - name: Release
84 | run:
85 | when: "tag =~ '.*'"
86 | task:
87 | secrets:
88 | - name: mesh
89 |
90 | env_vars:
91 | - name: SEIHON_VERSION
92 | value: v0.9.0
93 |
94 | jobs:
95 | - name: Release
96 | commands:
97 | - curl -sL https://git.io/goreleaser | bash -s -- --timeout="60m"
98 |
99 | - name: Publish Images
100 | commands:
101 | # Install Docker image multi-arch builder
102 | - curl -sfL https://raw.githubusercontent.com/ldez/seihon/master/godownloader.sh | sudo bash -s -- -b "/usr/local/bin" ${SEIHON_VERSION}
103 | - seihon --version
104 | - docker run --rm --privileged hypriot/qemu-register
105 | - make publish-images
106 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience,nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
34 | Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
35 | Representation of a project may be further defined and clarified by project maintainers.
36 |
37 | ## Enforcement
38 |
39 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@traefik.io
40 | All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
41 | The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
42 | Further details of specific enforcement policies may be posted separately.
43 |
44 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
45 |
46 | ## Attribution
47 |
48 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
49 |
50 | [homepage]: http://contributor-covenant.org
51 | [version]: http://contributor-covenant.org/version/1/4/
52 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Traefik Mesh is an open source project, and your feedback and contributions are needed and always welcome.
4 |
5 | [Issues] and [Pull Requests] are opened at https://github.com/traefik/mesh.
6 |
7 | Non trivial changes should be discussed with the project maintainers by opening a [Feature Request] clearly explaining rationale,
8 | background and possible implementation ideas. Feel free to provide code in such discussions.
9 |
10 | Once the proposal is approved, a Pull Request can be opened. If you want to provide early visibility to reviewers, create a [Draft Pull Request].
11 |
12 | [Issues]: https://github.com/traefik/mesh/issues
13 | [Pull Requests]: https://github.com/traefik/mesh/issues
14 | [Feature Request]: https://github.com/traefik/mesh/issues/new?template=feature_request.md
15 | [Draft Pull Request]: https://github.blog/2019-02-14-introducing-draft-pull-requests/
16 |
17 | ## Release Process
18 |
19 | Traefik Mesh follows the [semver](https://semver.org/) scheme when releasing new versions.
20 |
21 | Therefore, all PR's (except fixing a bug in a specific version) should be made against the `master` branch.
22 | If you're attempting to fix a bug in an already released version, please use the correct branch of that release (e.g. `v1.1`).
23 | All bug-fixes made to a specific branch will be backported to master, prior to releasing a new (major / minor) version. Patch releases will be made out of the version branch.
24 |
25 | ### Release steps
26 |
27 | In order to release a new version of Traefik Mesh, the following steps have to be done:
28 |
29 | * Create a Prepare release PR updating the chart version and app version to upcoming release
30 | * Prepare a list of release notes for the #traefik-mesh
31 | * Merge Prepare release PR
32 | * Create and push a tag on the release commit
33 | * Create a new release branch (v1.x) on upstream to allow versioned docs to be built
34 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.19-alpine AS base-image
2 |
3 | # Package dependencies
4 | RUN apk --no-cache --no-progress add \
5 | bash \
6 | gcc \
7 | git \
8 | make \
9 | musl-dev \
10 | mercurial \
11 | curl \
12 | tar \
13 | ca-certificates \
14 | tzdata \
15 | && update-ca-certificates \
16 | && rm -rf /var/cache/apk/*
17 |
18 | WORKDIR /go/src/github.com/traefik/mesh
19 |
20 | # Download goreleaser binary to bin folder in $GOPATH
21 | RUN curl -sfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | sh
22 |
23 | # Download golangci-lint binary to bin folder in $GOPATH
24 | RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $GOPATH/bin v1.48.0
25 |
26 | ENV GO111MODULE on
27 | COPY go.mod go.sum ./
28 | RUN go mod download
29 | COPY . .
30 |
31 | FROM base-image as maker
32 |
33 | ARG MAKE_TARGET=local-build
34 |
35 | RUN make ${MAKE_TARGET}
36 |
37 | ## IMAGE
38 | FROM alpine:3.15
39 |
40 | RUN addgroup -g 1000 -S app && \
41 | adduser -u 1000 -S app -G app
42 |
43 | COPY --from=base-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
44 | COPY --from=maker /go/src/github.com/traefik/mesh/dist/traefik-mesh /app/
45 |
46 | ENTRYPOINT ["/app/traefik-mesh"]
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [](https://traefik.semaphoreci.com/projects/mesh)
7 | [](https://doc.traefik.io/traefik-mesh)
8 | [](https://goreportcard.com/report/github.com/traefik/mesh)
9 | [](https://github.com/traefik/mesh/releases)
10 | [](https://github.com/traefik/mesh/blob/master/LICENSE)
11 | [](https://community.traefik.io/c/traefik-mesh)
12 |
13 | ## Traefik Mesh: Simpler Service Mesh
14 |
15 | Traefik Mesh is a simple, yet full-featured service mesh.
16 | It is container-native and fits as your de-facto service mesh in your Kubernetes cluster.
17 | It supports the latest Service Mesh Interface specification [SMI](https://smi-spec.io) that facilitates integration with pre-existing solution.
18 | Moreover, Traefik Mesh is opt-in by default, which means that your existing services are unaffected until you decide to add them to the mesh.
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## Non-Invasive Service Mesh
26 |
27 | Traefik Mesh does not use any sidecar container but handles routing through proxy endpoints running on each node.
28 | The mesh controller runs in a dedicated pod and handles all the configuration parsing and deployment to the proxy nodes.
29 | Traefik Mesh supports multiple configuration options: annotations on user service objects, and SMI objects.
30 | Not using sidecars means that Traefik Mesh does not modify your Kubernetes objects, and does not modify your traffic without your knowledge.
31 | Using the Traefik Mesh endpoints is all that is required.
32 |
33 |
34 |
35 |
36 |
37 |
38 | ## Prerequisites
39 |
40 | To run this app, you require the following:
41 |
42 | - Kubernetes 1.11+
43 | - CoreDNS installed as [Cluster DNS Provider](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/) (versions 1.3+ supported)
44 | - Helm v3
45 |
46 | ## Install (Helm v3 only)
47 |
48 | ```shell
49 | helm repo add traefik https://traefik.github.io/charts
50 | helm repo update
51 | helm install traefik-mesh traefik/traefik-mesh
52 | ```
53 |
54 | You can find the complete documentation at https://doc.traefik.io/traefik-mesh.
55 |
56 |
57 | ## Contributing
58 |
59 | [Contributing guide](CONTRIBUTING.md).
60 |
--------------------------------------------------------------------------------
/cmd/cleanup/cleanup.go:
--------------------------------------------------------------------------------
1 | package cleanup
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os/signal"
7 | "syscall"
8 |
9 | "github.com/traefik/mesh/cmd"
10 | "github.com/traefik/mesh/pkg/cleanup"
11 | "github.com/traefik/mesh/pkg/k8s"
12 | "github.com/traefik/paerser/cli"
13 | )
14 |
15 | // NewCmd builds a new Cleanup command.
16 | func NewCmd(cConfig *cmd.CleanupConfiguration, loaders []cli.ResourceLoader) *cli.Command {
17 | return &cli.Command{
18 | Name: "cleanup",
19 | Description: `Removes Traefik Mesh shadow services from a Kubernetes cluster.`,
20 | Configuration: cConfig,
21 | Run: func(_ []string) error {
22 | return cleanupCommand(cConfig)
23 | },
24 | Resources: loaders,
25 | }
26 | }
27 |
28 | func cleanupCommand(cConfig *cmd.CleanupConfiguration) error {
29 | ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
30 | defer cancel()
31 |
32 | logger, err := cmd.NewLogger(cConfig.LogFormat, cConfig.LogLevel, false)
33 | if err != nil {
34 | return fmt.Errorf("could not create logger: %w", err)
35 | }
36 |
37 | logger.Debug("Starting cleanup...")
38 | logger.Debugf("Using masterURL: %q", cConfig.MasterURL)
39 | logger.Debugf("Using kubeconfig: %q", cConfig.KubeConfig)
40 |
41 | clients, err := k8s.NewClient(logger, cConfig.MasterURL, cConfig.KubeConfig)
42 | if err != nil {
43 | return fmt.Errorf("error building clients: %w", err)
44 | }
45 |
46 | c := cleanup.NewCleanup(logger, clients.KubernetesClient(), cConfig.Namespace)
47 |
48 | if err := c.CleanShadowServices(ctx); err != nil {
49 | return fmt.Errorf("error encountered during cluster cleanup: %w", err)
50 | }
51 |
52 | if err := c.RestoreDNSConfig(ctx); err != nil {
53 | return fmt.Errorf("error encountered during DNS restore: %w", err)
54 | }
55 |
56 | return nil
57 | }
58 |
--------------------------------------------------------------------------------
/cmd/context.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | // ContextWithStopChan creates a context canceled when the given stopCh receives a message
8 | // or get closed.
9 | func ContextWithStopChan(ctx context.Context, stopCh <-chan struct{}) context.Context {
10 | ctx, cancel := context.WithCancel(ctx)
11 |
12 | go func() {
13 | defer cancel()
14 |
15 | select {
16 | case <-ctx.Done():
17 | case <-stopCh:
18 | }
19 | }()
20 |
21 | return ctx
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/log.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/sirupsen/logrus"
8 | )
9 |
10 | // parseLogLevel parses a given log level and returns a standardized level.
11 | func parseLogLevel(level string) (logrus.Level, error) {
12 | return logrus.ParseLevel(level)
13 | }
14 |
15 | // parseLogFormat parses a log format and returns a formatter.
16 | func parseLogFormat(format string) (logrus.Formatter, error) {
17 | switch format {
18 | case "json":
19 | return &logrus.JSONFormatter{}, nil
20 | case "common":
21 | return &logrus.TextFormatter{DisableColors: false, FullTimestamp: true, DisableSorting: true}, nil
22 | default:
23 | return nil, fmt.Errorf("invalid logging format: %s", format)
24 | }
25 | }
26 |
27 | // NewLogger returns a new field logger with the provided format, level, and debug configurations.
28 | func NewLogger(format, level string, debug bool) (logrus.FieldLogger, error) {
29 | log := logrus.New()
30 | log.SetOutput(os.Stdout)
31 |
32 | logLevelStr := level
33 | if debug {
34 | logLevelStr = "debug"
35 |
36 | log.Warnf("Debug flag is deprecated, please consider using --loglevel=DEBUG instead")
37 | }
38 |
39 | logLevel, err := parseLogLevel(logLevelStr)
40 | if err != nil {
41 | return log, err
42 | }
43 |
44 | log.SetLevel(logLevel)
45 |
46 | logFormat, err := parseLogFormat(format)
47 | if err != nil {
48 | return log, err
49 | }
50 |
51 | log.SetFormatter(logFormat)
52 |
53 | return log, nil
54 | }
55 |
--------------------------------------------------------------------------------
/cmd/prepare/prepare.go:
--------------------------------------------------------------------------------
1 | package prepare
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os/signal"
7 | "syscall"
8 |
9 | "github.com/traefik/mesh/cmd"
10 | "github.com/traefik/mesh/pkg/dns"
11 | "github.com/traefik/mesh/pkg/k8s"
12 | "github.com/traefik/paerser/cli"
13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14 | )
15 |
16 | // NewCmd builds a new Prepare command.
17 | func NewCmd(pConfig *cmd.PrepareConfiguration, loaders []cli.ResourceLoader) *cli.Command {
18 | return &cli.Command{
19 | Name: "prepare",
20 | Description: `Prepare command.`,
21 | Configuration: pConfig,
22 | Run: func(_ []string) error {
23 | return prepareCommand(pConfig)
24 | },
25 | Resources: loaders,
26 | }
27 | }
28 |
29 | func prepareCommand(pConfig *cmd.PrepareConfiguration) error {
30 | ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
31 | defer cancel()
32 |
33 | log, err := cmd.NewLogger(pConfig.LogFormat, pConfig.LogLevel, pConfig.Debug)
34 | if err != nil {
35 | return fmt.Errorf("could not create logger: %w", err)
36 | }
37 |
38 | log.Debug("Starting prepare...")
39 | log.Debugf("Using masterURL: %q", pConfig.MasterURL)
40 | log.Debugf("Using kubeconfig: %q", pConfig.KubeConfig)
41 |
42 | client, err := k8s.NewClient(log, pConfig.MasterURL, pConfig.KubeConfig)
43 | if err != nil {
44 | return fmt.Errorf("unable to create kubernetes client: %w", err)
45 | }
46 |
47 | dnsClient := dns.NewClient(log, client.KubernetesClient())
48 |
49 | if pConfig.SMI {
50 | log.Warnf("SMI mode is deprecated, please consider using --acl instead")
51 | }
52 |
53 | aclEnabled := pConfig.ACL || pConfig.SMI
54 |
55 | log.Debugf("ACL mode enabled: %t", aclEnabled)
56 |
57 | if err = k8s.CheckSMIVersion(client.KubernetesClient(), aclEnabled); err != nil {
58 | return fmt.Errorf("unsupported SMI version: %w", err)
59 | }
60 |
61 | var dnsProvider dns.Provider
62 |
63 | dnsProvider, err = dnsClient.CheckDNSProvider(ctx)
64 | if err != nil {
65 | return fmt.Errorf("unable to find suitable DNS provider: %w", err)
66 | }
67 |
68 | switch dnsProvider {
69 | case dns.CoreDNS:
70 | if err := dnsClient.ConfigureCoreDNS(ctx, metav1.NamespaceSystem, pConfig.ClusterDomain, pConfig.Namespace); err != nil {
71 | return fmt.Errorf("unable to configure CoreDNS: %w", err)
72 | }
73 | case dns.KubeDNS:
74 | if err := dnsClient.ConfigureKubeDNS(ctx, pConfig.ClusterDomain, pConfig.Namespace); err != nil {
75 | return fmt.Errorf("unable to configure KubeDNS: %w", err)
76 | }
77 | }
78 |
79 | return nil
80 | }
81 |
--------------------------------------------------------------------------------
/cmd/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "runtime"
8 |
9 | "github.com/traefik/mesh/pkg/version"
10 | "github.com/traefik/paerser/cli"
11 | )
12 |
13 | const versionFormat = `
14 | version : %s
15 | commit : %s
16 | build date : %s
17 | go version : %s
18 | go compiler : %s
19 | platform : %s/%s
20 | `
21 |
22 | // NewCmd builds a new Version command.
23 | func NewCmd() *cli.Command {
24 | return &cli.Command{
25 | Name: "version",
26 | Description: `Shows the current Traefik Mesh version.`,
27 | Configuration: nil,
28 | Run: func(_ []string) error {
29 | return printVersion(os.Stdout)
30 | },
31 | }
32 | }
33 |
34 | func printVersion(w io.Writer) error {
35 | _, err := io.WriteString(w, fmt.Sprintf(
36 | versionFormat,
37 | version.Version,
38 | version.Commit,
39 | version.Date,
40 | runtime.Version(),
41 | runtime.Compiler,
42 | runtime.GOOS,
43 | runtime.GOARCH,
44 | ))
45 |
46 | return err
47 | }
48 |
--------------------------------------------------------------------------------
/docs/.dockerignore:
--------------------------------------------------------------------------------
1 | site/
2 |
--------------------------------------------------------------------------------
/docs/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "no-hard-tabs": false,
3 | "MD007": { "indent": 4 },
4 | "MD009": false,
5 | "MD013": false,
6 | "MD024": false,
7 | "MD025": false,
8 | "MD026": false,
9 | "MD033": false,
10 | "MD034": false,
11 | "MD036": false,
12 | "MD046": false
13 | }
14 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | #######
2 | # This Makefile contains all targets related to the documentation.
3 | #######
4 |
5 | DOCS_VERIFY_SKIP ?= false
6 | DOCS_LINT_SKIP ?= false
7 |
8 | TRAEFIK_MESH_DOCS_BUILD_IMAGE ?= traefik-mesh-docs
9 | TRAEFIK_MESH_DOCS_CHECK_IMAGE ?= $(TRAEFIK_MESH_DOCS_BUILD_IMAGE)-check
10 |
11 | SITE_DIR := $(CURDIR)/site
12 |
13 | DOCKER_RUN_DOC_PORT := 8000
14 | DOCKER_RUN_DOC_MOUNTS := -v $(CURDIR):/mkdocs
15 | DOCKER_RUN_DOC_OPTS := --rm $(DOCKER_RUN_DOC_MOUNTS) -p $(DOCKER_RUN_DOC_PORT):8000
16 |
17 | # Default: generates the documentation into $(SITE_DIR)
18 | docs: clean image lint build verify
19 |
20 | # Writer Mode: build and serve docs on http://localhost:8000 with livereload
21 | serve: image
22 | docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_MESH_DOCS_BUILD_IMAGE) mkdocs serve
23 |
24 | # Utilities Targets for each step
25 | image:
26 | docker build -t $(TRAEFIK_MESH_DOCS_BUILD_IMAGE) -f docs.Dockerfile ./
27 |
28 | build: image
29 | docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_MESH_DOCS_BUILD_IMAGE) sh -c "mkdocs build \
30 | && chown -R $(shell id -u):$(shell id -g) ./site"
31 |
32 | verify: build
33 | @if [ "$(DOCS_VERIFY_SKIP)" != "true" ]; then \
34 | docker build -t $(TRAEFIK_MESH_DOCS_CHECK_IMAGE) -f check.Dockerfile ./; \
35 | docker run --rm -v $(CURDIR):/app $(TRAEFIK_MESH_DOCS_CHECK_IMAGE) /verify.sh; \
36 | else \
37 | echo "DOCS_VERIFY_SKIP is true: no verification done."; \
38 | fi
39 |
40 | lint:
41 | @if [ "$(DOCS_LINT_SKIP)" != "true" ]; then \
42 | docker build -t $(TRAEFIK_MESH_DOCS_CHECK_IMAGE) -f check.Dockerfile ./ && \
43 | docker run --rm -v $(CURDIR):/app $(TRAEFIK_MESH_DOCS_CHECK_IMAGE) /lint.sh; \
44 | else \
45 | echo "DOCS_LINT_SKIP is true: no linting done."; \
46 | fi
47 |
48 | clean:
49 | rm -rf $(SITE_DIR)
50 |
51 | .PHONY: all verify docs clean build lint
52 |
--------------------------------------------------------------------------------
/docs/check.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.15
2 |
3 | # The "build-dependencies" virtual package provides build tools for html-proofer installation.
4 | # It compile ruby-nokogiri, because alpine native version is always out of date
5 | # This virtual package is cleaned at the end.
6 | RUN apk --no-cache --no-progress add \
7 | libcurl \
8 | ruby \
9 | ruby-bigdecimal \
10 | ruby-etc \
11 | ruby-ffi \
12 | ruby-json \
13 | ruby-nokogiri \
14 | ruby-dev \
15 | build-base
16 |
17 | RUN gem install --no-document html-proofer -v 3.19.0 -- --use-system-libraries
18 |
19 | # After Ruby, some NodeJS YAY!
20 | RUN apk --no-cache --no-progress add \
21 | git \
22 | nodejs \
23 | npm
24 |
25 | # To handle 'not get uid/gid'
26 | RUN npm config set unsafe-perm true
27 |
28 | RUN npm install --global \
29 | markdownlint@0.23.1 \
30 | markdownlint-cli@0.28.1
31 |
32 | # Finally the shell tools we need for later
33 | # tini helps to terminate properly all the parallelized tasks when sending CTRL-C
34 | RUN apk --no-cache --no-progress add \
35 | ca-certificates \
36 | curl \
37 | tini
38 |
39 | COPY ./scripts/verify.sh /verify.sh
40 | COPY ./scripts/lint.sh /lint.sh
41 |
42 | WORKDIR /app
43 | VOLUME ["/tmp","/app"]
44 |
45 | ENTRYPOINT ["/sbin/tini","-g","sh"]
46 |
--------------------------------------------------------------------------------
/docs/content/api.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh API"
3 | description: "Traefik Mesh includes a built-in API that can be used for debugging purposes. Read the documentation to learn more."
4 | ---
5 |
6 | # API
7 |
8 | Traefik Mesh includes a built-in API that can be used for debugging purposes.
9 | This can be useful when Traefik Mesh is not working as intended.
10 | The API is accessed via the controller pod, and for security reasons is not exposed via service.
11 | The API can be accessed by making a `GET` request to `http://:9000` combined with one of the following paths:
12 |
13 | ## `/api/configuration/current`
14 |
15 | This endpoint provides raw json of the current configuration built by the controller.
16 |
17 | !!! Note
18 | This may change on each request, as it is a live data structure.
19 |
20 | ## `/api/status/nodes`
21 |
22 | This endpoint provides a json array containing some details about the readiness of the Traefik Mesh nodes visible by the controller.
23 | This endpoint will still return a 200 if there are no visible nodes.
24 |
25 | ## `/api/status/node/{traefik-mesh-pod-name}/configuration`
26 |
27 | This endpoint provides raw json of the current configuration on the Traefik Mesh node with the pod name given in `{traefik-mesh-pod-name}`.
28 | This endpoint provides a 404 response if the pod cannot be found, or other non-200 status codes on other errors.
29 | If errors are encountered, the error will be returned in the body, and logged on the controller.
30 |
31 | ## `/api/status/readiness`
32 |
33 | This endpoint returns a 200 response if the controller has successfully started.
34 | Otherwise, it will return a 500.
35 |
--------------------------------------------------------------------------------
/docs/content/assets/img/after-traefik-mesh-graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/docs/content/assets/img/after-traefik-mesh-graphic.png
--------------------------------------------------------------------------------
/docs/content/assets/img/before-traefik-mesh-graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/docs/content/assets/img/before-traefik-mesh-graphic.png
--------------------------------------------------------------------------------
/docs/content/assets/img/smi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/docs/content/assets/img/smi.png
--------------------------------------------------------------------------------
/docs/content/assets/img/traefik-mesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/docs/content/assets/img/traefik-mesh.png
--------------------------------------------------------------------------------
/docs/content/assets/js/extra.js:
--------------------------------------------------------------------------------
1 | /* Highlight */
2 | (function(hljs) {
3 | hljs.initHighlightingOnLoad();
4 | })(hljs);
--------------------------------------------------------------------------------
/docs/content/assets/js/hljs/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2006, Ivan Sagalaev
2 | All rights reserved.
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of highlight.js nor the names of its contributors
12 | may be used to endorse or promote products derived from this software
13 | without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/docs/content/compatibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh Compatibility"
3 | description: "Traefik Mesh supports, similar to Kubernetes, at least the latest three minor versions of Kubernetes. Read the documentation to learn more."
4 | ---
5 |
6 | # Compatibility
7 |
8 | Traefik Mesh supports, [similar to Kubernetes](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions), at least the latest three minor versions of Kubernetes, therefore currently:
9 |
10 | * 1.21
11 | * 1.22
12 | * 1.23
13 |
14 | General functionality cannot be guaranted for versions older than that. However, we expect it to work with Kubernetes down to 1.11 currently.
15 |
16 | ## Compatibility by Features
17 |
18 | Some of Traefik Mesh's features are only supported on certain Kubernetes versions.
19 | Please see the table below.
20 |
21 | | Features | K8s 1.21 | K8s 1.22 | K8s 1.23 |
22 | |-----------------------|----------|----------|----------|
23 | | General functionality | ✔ | ✔ | ✔ |
24 | | Service Topology | ✔ | - | - |
25 |
26 | !!! warning "Service Topology"
27 |
28 | In Kubernetes `v1.22`, the experimental Service Topology feature was removed.
29 | Therefore, starting from Traefik Mesh `v1.4.5`, the support of this feature has been removed.
30 |
31 | ## SMI Specification support
32 |
33 | Traefik Mesh is based on the latest version of the SMI specification:
34 |
35 | | API Group | API Version |
36 | |--------------------|-------------------------------------------------------------------------------------------------------------------------|
37 | | access.smi-spec.io | [v1alpha2](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md) |
38 | | specs.smi-spec.io | [v1alpha3](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-specs/v1alpha3/traffic-specs.md) |
39 | | split.smi-spec.io | [v1alpha3](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-split/v1alpha3/traffic-split.md) |
40 |
--------------------------------------------------------------------------------
/docs/content/contributing/documentation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh Documentation"
3 | description: "You've found something unclear in the documentation and want to give a try at explaining it better? Learn how you can do so in this article."
4 | ---
5 |
6 | # Documentation
7 |
8 | You've found something unclear in the documentation and want to give a try at explaining it better?
9 | Let's see how.
10 |
11 | ## Building
12 |
13 | This [documentation](https://doc.traefik.io/traefik-mesh/) is built with [MkDocs](https://mkdocs.org/).
14 |
15 | ### With `Docker` and `make`
16 |
17 | You can build the documentation and test it locally (with live reloading), using the `serve` target:
18 |
19 | ```bash
20 | $ make serve
21 | docker build -t traefik-mesh-docs -f docs.Dockerfile ./
22 | # […]
23 | docker run --rm -v /home/user/traefik-mesh/docs:/mkdocs -p 8000:8000 traefik-mesh-docs mkdocs serve
24 | # […]
25 | INFO - Building documentation...
26 | INFO - Cleaning site directory
27 | [I 200408 14:36:33 server:296] Serving on http://0.0.0.0:8000
28 | [I 200408 14:36:33 handlers:62] Start watching changes
29 | [I 200408 14:36:33 handlers:64] Start detecting changes
30 | ```
31 |
32 | !!! Note
33 | By default, the local documentation server listens on [http://127.0.0.1:8000](http://127.0.0.1:8000).
34 | To build the documentation without serving it locally, use the `build` target.
35 |
36 | ### With `MkDocs`
37 |
38 | First, make sure you have `python` and `pip` installed. MkDocs supports `python` versions `2.7.9+`, `3.4`, `3.5`, `3.6`
39 | and `3.7`.
40 |
41 | ```bash
42 | $ python --version
43 | Python 2.7.14
44 |
45 | $ pip --version
46 | pip 19.3.1 from /usr/local/lib/python2.7/site-packages/pip (python 2.7)
47 | ```
48 |
49 | Then, install MkDocs with `pip`.
50 |
51 | ```bash
52 | pip install --user -r requirements.txt
53 | ```
54 |
55 | To build the documentation and serve it locally, run `mkdocs serve` from the root directory.
56 | This starts a local server, and exposes the documentation on `http://127.0.0.1:8000`:
57 |
58 | ```bash
59 | $ mkdocs serve
60 | INFO - Building documentation...
61 | INFO - Cleaning site directory
62 | [I 160505 22:31:24 server:281] Serving on http://127.0.0.1:8000
63 | [I 160505 22:31:24 handlers:59] Start watching changes
64 | [I 160505 22:31:24 handlers:61] Start detecting changes
65 | ```
66 |
67 | ## Checking
68 |
69 | To check that the documentation meets standard expectations (no dead links, html markup validity, ...), use the `verify` target.
70 | If you've made changes to the documentation, it's safer to clean it before verifying it.
71 |
72 | ```bash
73 | $ make clean verify
74 | docker build -t traefik-mesh-docs -f docs.Dockerfile ./
75 | # […]
76 | docker run --rm -v /home/user/traefik-mesh/docs:/mkdocs -p 8000:8000 traefik-mesh-docs sh -c "mkdocs build && chown -R 501:20 ./site"
77 | === Checking HTML content...
78 | # […]
79 | ```
80 |
81 | !!! Note "Disabling Verification"
82 | Verification can be disabled by setting the environment variable `DOCS_VERIFY_SKIP` to `true`:
83 |
84 | ```bash
85 | $ DOCS_VERIFY_SKIP=true make verify
86 | # […]
87 | DOCS_VERIFY_SKIP is true: no verification done.
88 | ```
89 |
--------------------------------------------------------------------------------
/docs/content/contributing/maintainers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh Maintainers"
3 | description: "In this article, you can find the list of Traefik Mesh maintainers."
4 | ---
5 |
6 | # Maintainers
7 |
8 | - Daniel Tomcej [@dtomcej](https://github.com/dtomcej)
9 | - Manuel Zapf [@SantoDE](https://github.com/SantoDE)
10 | - Michaël Matur [@mmatur](https://github.com/mmatur)
11 | - Landry Benguigui [@LandryBe](https://github.com/LandryBe)
12 | - Harold Ozouf [@jspdown](https://github.com/jspdown)
13 | - Julien Levesy [@jlevesy](https://github.com/jlevesy)
14 | - Brendan Le Glaunec [@Ullaakut](https://github.com/Ullaakut)
15 | - Kevin Pollet [@kevinpollet](https://github.com/kevinpollet)
16 |
--------------------------------------------------------------------------------
/docs/content/contributing/submitting-issues.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Submitting Issues in Traefik Mesh"
3 | description: "This documentation article describes the process of sorting and checking issues in Traefik Mesh."
4 | ---
5 |
6 | # Submitting Issues
7 |
8 | We use the [GitHub issue tracker](https://github.com/traefik/mesh/issues) to keep track of Traefik Mesh issues.
9 |
10 | The process of sorting and checking the issues requires a lot of work. To save us some time and get quicker feedback,
11 | be sure to follow the guidelines below.
12 |
13 | !!! Important "Getting Help"
14 | The issue tracker is not a general support forum, but a place to report bugs and asks for new features.
15 | For end-user related support questions, use the [Traefik Mesh community forum](https://community.traefik.io/c/traefik-mesh).
16 |
17 | ## Issue Title
18 |
19 | The title must be short and descriptive. (~60 characters)
20 |
21 | ## Description
22 |
23 | Follow the [issue template](https://github.com/traefik/mesh/blob/master/.github/ISSUE_TEMPLATE/) as much as possible.
24 |
25 | Explain in which context you encountered the issue.
26 |
27 | Remain clear and concise.
28 |
29 | Take time to polish the format of your message so we'll enjoy reading it and working on it. Help the readers focus on
30 | what matters, and help them understand the structure of your message (see the [GitHub Markdown Syntax](https://docs.github.com/en/get-started/writing-on-github)).
31 |
32 | ## Feature Request
33 |
34 | Remember, when asking for new features, they must be useful to the majority (and not only useful in edge case scenarios, or hack-like setups).
35 |
36 | Do your best to explain what you're looking for, and why it would improve Traefik Mesh for everyone.
37 |
38 | ## International English
39 |
40 | Traefik Mesh maintainers/users are not all native English speakers, so if you sometimes feel that some messages sound rude,
41 | remember that it's probably a language barrier problem from someone willing to help you.
42 |
--------------------------------------------------------------------------------
/docs/content/contributing/submitting-pull-requests.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Submitting Pull Requests for Traefik Mesh"
3 | description: "This documentation article describes the process of submitting a pull request for Traefik Mesh."
4 | ---
5 |
6 | # Submitting Pull Requests
7 |
8 | So you've decided to improve Traefik Mesh? Thank You! Now the last step is to submit your Pull Request in a way that makes sure
9 | it gets the attention it deserves.
10 |
11 | Let's go through the classic pitfalls to make sure everything is right.
12 |
13 | ## Title
14 |
15 | The title must be short and descriptive. (~60 characters)
16 |
17 | ## Description
18 |
19 | Follow the [pull request template](https://github.com/traefik/mesh/blob/master/.github/PULL_REQUEST_TEMPLATE.md)
20 | as much as possible.
21 |
22 | Explain the conditions which led you to write this PR: give us context. The context should lead to something, an idea or
23 | a problem that you’re facing.
24 |
25 | Remain clear and concise.
26 |
27 | Take time to polish the format of your message so we'll enjoy reading it and working on it. Help the readers focus on
28 | what matters, and help them understand the structure of your message (see the [GitHub Markdown Syntax](https://docs.github.com/en/get-started/writing-on-github)).
29 |
30 | ## Content
31 |
32 | - Make it small.
33 | - Each PR should be linked to an issue.
34 | - One feature per PR.
35 | - PRs should be standalone (they should not depend on an upcoming PR).
36 | - Write useful descriptions and titles.
37 | - Avoid re-formatting code that is not on the path of your PR.
38 | - Commits should be split properly (in order to guide reviewers through the code).
39 | - Make sure the [code builds](building-testing.md).
40 | - Make sure [all tests pass](building-testing.md).
41 | - Add tests.
42 | - Address review comments in terms of additional commits (don't amend/squash existing ones unless the PR is trivial).
43 |
--------------------------------------------------------------------------------
/docs/content/contributing/thank-you.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh Feedback and Contributions"
3 | description: "Traefik Mesh is an open-source project, your feedback and contributions are needed and always welcome! Read the docs to learn how you can contribute."
4 | ---
5 |
6 | # Thank You!
7 |
8 | Traefik Mesh is an [open-source project](https://github.com/traefik/mesh/), your feedback and contributions are needed and
9 | always welcome!
10 |
11 | !!! Question "Where to Go Next?"
12 | If you want to:
13 |
14 | - Propose and idea, request a feature a report a bug,
15 | read the page [Submitting Issues](./submitting-issues.md).
16 | - Discover how to make an efficient contribution,
17 | read the page [Submitting Pull Requests](./submitting-pull-requests.md).
18 | - Learn how to build and test Traefik Mesh,
19 | the page [Building and Testing](./building-testing.md) is for you.
20 | - Contribute to the documentation,
21 | read the related page [Documentation](./documentation.md).
22 |
--------------------------------------------------------------------------------
/docs/content/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh: Simpler Service Mesh"
3 | description: "Traefik Mesh is a lightweight and simpler service mesh designed from the ground up to be straightforward, easy to install and use. Read the docs to learn more."
4 | ---
5 |
6 | # Traefik Mesh: Simpler Service Mesh
7 |
8 |
9 |
10 |
11 |
12 | Traefik Mesh is a lightweight and simpler service mesh designed from the ground up to be straightforward, easy to install and easy to use.
13 |
14 | Built on top of Traefik, Traefik Mesh fits as your de-facto service mesh in your Kubernetes cluster supporting the latest Service Mesh Interface specification (SMI).
15 |
16 | Moreover, Traefik Mesh is opt-in by default, which means that your existing services are unaffected until you decide to add them to the mesh.
17 |
18 |
19 |
20 |
21 |
22 | ## Non-Invasive Service Mesh
23 |
24 | Traefik Mesh does not use any sidecar container but handles routing through proxy endpoints running on each node.
25 | The mesh controller runs in a dedicated pod and handles all the configuration parsing and deployment to the proxy nodes.
26 | Traefik Mesh supports multiple configuration options: annotations on user service objects, and SMI objects.
27 | Not using sidecars means that Traefik Mesh does not modify your Kubernetes objects and does not modify your traffic without your knowledge.
28 | Using the Traefik Mesh endpoints is all that is required.
29 |
30 |
31 |
32 |
33 |
34 |
35 | ## Prerequisites
36 |
37 | To run this app, you require the following:
38 |
39 | - Kubernetes 1.11+
40 | - CoreDNS/KubeDNS installed as [Cluster DNS Provider](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/) (versions 1.3+ supported)
41 | - Helm v3
42 |
--------------------------------------------------------------------------------
/docs/content/migration/helm-chart.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Helm Chart Documentation"
3 | description: "Migrate to the latest version of Traefik Mesh, a simple and lightweight service mesh, in your cluster's Helm chart. Read the technical documentation."
4 | ---
5 |
6 | # Migrations
7 |
8 | Helm Chart
9 | {: .subtitle }
10 |
11 | ## v2.1 to v3.0
12 |
13 | ### Traefik Mesh renaming
14 |
15 | All existing resources have been renamed and prefixed by `traefik-mesh`.
16 | For example, the `maesh-controller`resource has been renamed to `traefik-mesh-controller`.
17 |
18 | ### Mesh Property Name
19 |
20 | Inside the Traefik Mesh helm chart, the `mesh` property has been renamed to `proxy`.
21 |
22 | ### Image version
23 |
24 | Since version `v1.4`, Traefik Mesh uses plain [Traefik](https://github.com/traefik/traefik/) Docker image for proxies.
25 | Therefore, to change the image version used for the controller, or the proxies you should use the `controller.image` and `proxy.image` options.
26 |
27 | ### Default Mode
28 |
29 | The `mesh.defaultMode` option has been removed.
30 | You should use the new `defaultMode` option to configure the default traffic mode.
31 |
32 | ## v2.0 to v2.1
33 |
34 | ### Default Mode
35 |
36 | The `mesh.defaultMode` option has been deprecated and will be removed in a future major release.
37 | You should use the new `defaultMode` option to configure the default traffic mode.
38 |
39 | ### Prometheus and Grafana services
40 |
41 | Prior to version `v2.1`, when the Metrics chart is deployed, Prometheus and Grafana services are exposed by default through a `NodePort`.
42 | For security reasons, those services are not exposed by default anymore.
43 | To expose them you should use the new `prometheus.service` and `grafana.service` options, more details in the corresponding [values.yaml](https://github.com/traefik/mesh-helm-chart/blob/8a7a193a1718129ad6e02ff313b219029d6daffe/mesh/charts/metrics/values.yaml).
44 |
45 | ## v1.x to v2.0
46 |
47 | ### Image version
48 |
49 | Since version `v1.2`, [Traefik](https://github.com/traefik/traefik/) is used as a library.
50 | Therefore, the `controller.image` and `mesh.image` options have been removed.
51 | You should use the new `image` option as described in the [documentation](../install.md#deploy-helm-chart).
52 |
53 | ### Log Level
54 |
55 | The `controller.logging.debug` and `mesh.logging` options have been removed.
56 | You should use the new `controller.logLevel` and `mesh.logLevel` options to configure the logging level for the controller and proxies.
57 |
58 | ### SMI Mode
59 |
60 | The `smi.enable` option has been deprecated and removed.
61 | You should use the new and backward compatible ACL mode option as described in the [documentation](../install.md#access-control-list).
62 |
--------------------------------------------------------------------------------
/docs/content/migration/traefik-mesh-v1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traefik Mesh Migrations Documentation"
3 | description: "Traefik Mesh v1.4 introduced a few key changes. Learn what those changes are and what actionable steps must be taken in the technical documentation."
4 | ---
5 |
6 | # Minor Migrations
7 |
8 | Traefik Mesh v1
9 | {: .subtitle }
10 |
11 | ## Traefik Mesh v1.4
12 |
13 | Maesh has been renamed to Traefik Mesh in an effort to rename all of our products and make them look closer.
14 | Through this renaming process, a couple of things changed which might be worth mentioning for a migration process.
15 | All areas that changed are mentioned below with the appropriate actions needed to do.
16 |
17 | Everything called Maesh references to `v1.3`, while Traefik Mesh refers to `v1.4`.
18 |
19 | ### Environment Variable Prefix
20 |
21 | Prior to Traefik Mesh, environment variables were prefixed with `MAESH_`.
22 | Now they're prefixed with `TRAEFIK_MESH_` and the `MAESH_` prefix is deprecated.
23 | You need to decide on either using `MAESH_` or `TRAEFIK_MESH_` as mixing both will result in an error.
24 |
25 | ### Configuration File Name
26 |
27 | The default configuration file name is changed from `maesh` to `traefik-mesh` as well.
28 |
29 | ### DNS Name
30 |
31 | The well known internal DNS name, to opt in into the usage of Maesh was `.maesh`.
32 | Now, with the rebranding process this has been changed to `traefik.mesh` and thus, you now need to use the DNS name of `servicename.servicenamespace.traefik.maesh` to opt-in into the usage of Traefik Mesh.
33 | The old name `.maesh`, is deprecated and will be removed eventually.
34 |
35 | ### Docker Image Name
36 |
37 | As part of the process, the docker-image has been moved from `containous/maesh` to `traefik/mesh`.
38 | The old image will not be updated anymore and `traefik/mesh` starts with `v1.4.0`.
39 |
40 | ### Binary
41 |
42 | The new binary name is `traefik-mesh`, rather than `maesh` before.
43 | However, as Traefik Mesh is running inside k8s this change should not be critical as it's hidden by the docker-image name.
44 |
45 | ### Annotations
46 |
47 | As part of the rebranding process, the annotation prefix has changed.
48 | The annotation prefix `maesh.containo.us/` has been deprecated in favour of `mesh.traefik.io`.
49 |
50 | ## v1.1 to v1.2
51 |
52 | ### Debug
53 |
54 | The `--debug` CLI flag is deprecated and will be removed in a future major release.
55 | Instead, you should use the new `--logLevel` flag with `debug` as value.
56 |
57 | ### SMI Mode
58 |
59 | The `--smi` CLI flag is deprecated and will be removed in a future major release.
60 | Instead, you should use the new and backward compatible `--acl` flag.
61 |
--------------------------------------------------------------------------------
/docs/docs.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.15
2 |
3 | ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.local/bin
4 |
5 | COPY requirements.txt /mkdocs/
6 | WORKDIR /mkdocs
7 | VOLUME /mkdocs
8 |
9 | RUN apk --no-cache --no-progress add py3-pip gcc musl-dev python3-dev \
10 | && pip3 install --user -r requirements.txt
11 |
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Traefik Mesh
2 | site_description: Traefik Mesh Documentation
3 | site_author: traefik.io
4 | site_url: https://doc.traefik.io/traefik-mesh
5 | dev_addr: 0.0.0.0:8000
6 |
7 | repo_name: 'GitHub'
8 | repo_url: 'https://github.com/traefik/mesh'
9 |
10 | docs_dir: 'content'
11 | edit_uri: 'edit/master/docs/content/'
12 |
13 | product: mesh
14 |
15 | # https://squidfunk.github.io/mkdocs-material/
16 | theme:
17 | name: 'traefik-labs'
18 | language: en
19 | include_sidebar: true
20 | favicon: assets/img/traefik-mesh-logo.svg
21 | logo: assets/img/traefik-mesh-logo.svg
22 | feature:
23 | tabs: false
24 | palette:
25 | primary: 'white'
26 | accent: '#9D0EB0'
27 | i18n:
28 | prev: 'Previous'
29 | next: 'Next'
30 |
31 | copyright: "Copyright © 2020-2022 Traefik Labs"
32 |
33 | extra_javascript:
34 | - assets/js/hljs/highlight.pack.js # Download from https://highlightjs.org/download/ and enable YAML, TOML and Dockerfile
35 | - assets/js/extra.js
36 |
37 | plugins:
38 | - search
39 |
40 | # https://squidfunk.github.io/mkdocs-material/extensions/admonition/
41 | # https://facelessuser.github.io/pymdown-extensions/
42 | markdown_extensions:
43 | - meta
44 | - attr_list
45 | - admonition
46 | - footnotes
47 | - pymdownx.details
48 | - pymdownx.inlinehilite
49 | - pymdownx.highlight:
50 | use_pygments: false # hljs is used instead of pygment for TOML highlighting support
51 | - pymdownx.smartsymbols
52 | - pymdownx.superfences
53 | - pymdownx.tasklist
54 | - pymdownx.snippets:
55 | check_paths: true
56 | - markdown_include.include:
57 | base_path: content/includes/
58 | encoding: utf-8
59 | - toc:
60 | permalink: true
61 |
62 | # Page tree
63 | nav:
64 | - 'Welcome': 'index.md'
65 | - 'Quickstart': 'quickstart.md'
66 | - 'Installation': 'install.md'
67 | - 'Configuration': 'configuration.md'
68 | - 'Compatibility': 'compatibility.md'
69 | - 'Examples': 'examples.md'
70 | - 'API': 'api.md'
71 | - 'Migration':
72 | - 'Traefik Mesh v1': 'migration/traefik-mesh-v1.md'
73 | - 'Helm Chart': 'migration/helm-chart.md'
74 | - 'Contributing':
75 | - 'Thank You!': 'contributing/thank-you.md'
76 | - 'Submitting Issues': 'contributing/submitting-issues.md'
77 | - 'Submitting Pull Requests': 'contributing/submitting-pull-requests.md'
78 | - 'Building and Testing': 'contributing/building-testing.md'
79 | - 'Documentation': 'contributing/documentation.md'
80 | - 'Maintainers': 'contributing/maintainers.md'
81 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | ## Tooling
4 |
5 | | Tool | Documentation | Sources |
6 | |-------------------|-------------------------------------|-----------------------------------|
7 | | mkdocs | [documentation][mkdocs] | [Sources][mkdocs-src] |
8 | | mkdocs-material | [documentation][mkdocs-material] | [Sources][mkdocs-material-src] |
9 | | pymdown-extensions| [documentation][pymdown-extensions] | [Sources][pymdown-extensions-src] |
10 |
11 |
12 | [mkdocs]: https://www.mkdocs.org "Mkdocs"
13 | [mkdocs-src]: https://github.com/mkdocs/mkdocs "Mkdocs - Sources"
14 |
15 | [mkdocs-material]: https://squidfunk.github.io/mkdocs-material/ "Material for MkDocs"
16 | [mkdocs-material-src]: https://github.com/squidfunk/mkdocs-material "Material for MkDocs - Sources"
17 |
18 | [pymdown-extensions]: https://facelessuser.github.io/pymdown-extensions/extensions "PyMdown Extensions"
19 | [pymdown-extensions-src]: https://github.com/facelessuser/pymdown-extensions "PyMdown Extensions - Sources"
20 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | appdirs==1.4.4
2 | CacheControl==0.12.10
3 | certifi==2020.12.5
4 | charset-normalizer==2.0.7
5 | click==8.1.2
6 | colorama==0.4.4
7 | contextlib2==21.6.0
8 | distlib==0.3.3
9 | distro==1.6.0
10 | ghp-import==2.0.2
11 | html5lib==1.1
12 | idna==3.3
13 | importlib-metadata==4.11.3
14 | Jinja2==3.0.0
15 | lockfile==0.12.2
16 | Markdown==3.3.6
17 | markdown-include==0.5.1
18 | MarkupSafe==2.1.1
19 | mergedeep==1.3.4
20 | mkdocs==1.2.2
21 | mkdocs-bootswatch==1.0
22 | mkdocs-material-extensions==1.0.3
23 | mkdocs-traefiklabs==100.0.10
24 | msgpack==1.0.2
25 | ordered-set==4.0.2
26 | packaging==20.9
27 | pep517==0.12.0
28 | progress==1.6
29 | Pygments==2.11.2
30 | pymdown-extensions==7.0
31 | pyparsing==2.4.7
32 | python-dateutil==2.8.2
33 | PyYAML==6.0
34 | pyyaml-env-tag==0.1
35 | requests==2.26.0
36 | retrying==1.3.3
37 | six==1.16.0
38 | toml==0.10.2
39 | tomli==1.2.2
40 | urllib3==1.26.7
41 | watchdog==2.1.7
42 | webencodings==0.5.1
43 | zipp==3.8.0
44 |
--------------------------------------------------------------------------------
/docs/runtime.txt:
--------------------------------------------------------------------------------
1 | 3.7
2 |
--------------------------------------------------------------------------------
/docs/scripts/lint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This script will run a couple of linter on the documentation
3 |
4 | set -eu
5 |
6 | # We want to run all linters before returning success (exit 0) or failure (exit 1)
7 | # So this variable holds the global exit code
8 | EXIT_CODE=0
9 | readonly BASE_DIR=/app
10 |
11 | echo "== Linting Markdown"
12 | # Uses the file ".markdownlint.json" for setup
13 | cd "${BASE_DIR}" || exit 1
14 |
15 | LINTER_EXCLUSIONS="$(find "${BASE_DIR}/content" -type f -name '.markdownlint.json')" \
16 | GLOBAL_LINT_OPTIONS="--config ${BASE_DIR}/.markdownlint.json"
17 |
18 | # Lint the specific folders (containing linter specific rulesets)
19 | for LINTER_EXCLUSION in ${LINTER_EXCLUSIONS}
20 | do
21 | markdownlint --config "${LINTER_EXCLUSION}" "$(dirname "${LINTER_EXCLUSION}")" || EXIT_CODE=1
22 | # Add folder to the ignore list for global lint
23 | GLOBAL_LINT_OPTIONS="${GLOBAL_LINT_OPTIONS} --ignore=$(dirname "${LINTER_EXCLUSION}")"
24 | done
25 |
26 | # Lint all the content, excluding the previously done`
27 | eval markdownlint "${GLOBAL_LINT_OPTIONS}" "${BASE_DIR}/content/**/*.md" || EXIT_CODE=1
28 |
29 | exit "${EXIT_CODE}"
30 |
--------------------------------------------------------------------------------
/docs/scripts/netlify-run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This script is run in netlify environment to build and validate
4 | # the website for documentation
5 |
6 | CURRENT_DIR="$(cd "$(dirname "${0}")" && pwd -P)"
7 |
8 | #### Build website
9 | # Provide the URL for this deployment to Mkdocs
10 | echo "${DEPLOY_PRIME_URL}" > "${CURRENT_DIR}/../CNAME"
11 | sed -i "s#site_url:.*#site_url: ${DEPLOY_PRIME_URL}#" "${CURRENT_DIR}/../mkdocs.yml"
12 |
13 | # Build
14 | mkdocs build
15 |
16 | exit 0
--------------------------------------------------------------------------------
/docs/scripts/verify.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | PATH_TO_SITE="${1:-/app/site}"
4 |
5 | set -eu
6 |
7 | [ -d "${PATH_TO_SITE}" ]
8 |
9 | NUMBER_OF_CPUS="$(grep -c processor /proc/cpuinfo)"
10 |
11 | echo "=== Checking HTML content..."
12 |
13 | # Search for all HTML files except the theme's partials
14 | # and pipe this to htmlproofer with parallel threads
15 | # (one htmlproofer per vCPU)
16 | find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
17 | -name "*.html" -print0 \
18 | | xargs -0 -r -P "${NUMBER_OF_CPUS}" -I '{}' \
19 | htmlproofer \
20 | --check-html \
21 | --check_external_hash \
22 | --alt_ignore="/traefik-mesh-logo.svg/" \
23 | --http_status_ignore="0,500,501,503" \
24 | --url_ignore="/fonts.gstatic.com/,/traefik-mesh/,/github.com\/traefik\/mesh\/edit*/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/docs.github.com/" \
25 | '{}' 1>/dev/null
26 | ## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration
27 |
28 | echo "= Documentation checked successfully."
29 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/traefik/mesh
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/cenkalti/backoff/v4 v4.1.1
7 | github.com/go-check/check v0.0.0-20180628173108-788fd7840127
8 | github.com/google/uuid v1.3.0
9 | github.com/gorilla/mux v1.8.0
10 | github.com/hashicorp/go-version v1.3.0
11 | github.com/servicemeshinterface/smi-sdk-go v0.4.1
12 | github.com/sirupsen/logrus v1.8.1
13 | github.com/stretchr/testify v1.8.0
14 | github.com/traefik/paerser v0.1.8
15 | github.com/traefik/traefik/v2 v2.8.3
16 | github.com/vdemeester/shakers v0.1.0
17 | k8s.io/api v0.22.5
18 | k8s.io/apimachinery v0.22.5
19 | k8s.io/client-go v0.22.5
20 | )
21 |
22 | require (
23 | github.com/BurntSushi/toml v1.1.0 // indirect
24 | github.com/Masterminds/goutils v1.1.1 // indirect
25 | github.com/Masterminds/semver/v3 v3.1.1 // indirect
26 | github.com/Masterminds/sprig/v3 v3.2.2 // indirect
27 | github.com/davecgh/go-spew v1.1.1 // indirect
28 | github.com/evanphx/json-patch v4.11.0+incompatible // indirect
29 | github.com/go-acme/lego/v4 v4.7.0 // indirect
30 | github.com/go-logr/logr v0.4.0 // indirect
31 | github.com/gogo/protobuf v1.3.2 // indirect
32 | github.com/golang/protobuf v1.5.2 // indirect
33 | github.com/google/go-cmp v0.5.7 // indirect
34 | github.com/google/gofuzz v1.2.0 // indirect
35 | github.com/googleapis/gnostic v0.5.5 // indirect
36 | github.com/huandu/xstrings v1.3.1 // indirect
37 | github.com/imdario/mergo v0.3.12 // indirect
38 | github.com/json-iterator/go v1.1.12 // indirect
39 | github.com/mitchellh/copystructure v1.0.0 // indirect
40 | github.com/mitchellh/reflectwalk v1.0.1 // indirect
41 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
42 | github.com/modern-go/reflect2 v1.0.2 // indirect
43 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
44 | github.com/pkg/errors v0.9.1 // indirect
45 | github.com/pmezard/go-difflib v1.0.0 // indirect
46 | github.com/shopspring/decimal v1.2.0 // indirect
47 | github.com/spf13/cast v1.3.1 // indirect
48 | github.com/spf13/pflag v1.0.5 // indirect
49 | golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
50 | golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
51 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
52 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
53 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
54 | golang.org/x/text v0.3.7 // indirect
55 | golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
56 | google.golang.org/appengine v1.6.7 // indirect
57 | google.golang.org/protobuf v1.28.0 // indirect
58 | gopkg.in/inf.v0 v0.9.1 // indirect
59 | gopkg.in/square/go-jose.v2 v2.6.0 // indirect
60 | gopkg.in/yaml.v2 v2.4.0 // indirect
61 | gopkg.in/yaml.v3 v3.0.1 // indirect
62 | k8s.io/klog/v2 v2.10.0 // indirect
63 | k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c // indirect
64 | k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e // indirect
65 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
66 | sigs.k8s.io/yaml v1.2.0 // indirect
67 | )
68 |
69 | // Containous forks
70 | replace (
71 | github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e
72 | github.com/go-check/check => github.com/containous/check v0.0.0-20170915194414-ca0bf163426a
73 | github.com/gorilla/mux => github.com/containous/mux v0.0.0-20220627093034-b2dd784e613f
74 | github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
75 | )
76 |
--------------------------------------------------------------------------------
/integration/integration_test.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "log"
7 | "os"
8 | "os/exec"
9 | "testing"
10 |
11 | "github.com/go-check/check"
12 | "github.com/sirupsen/logrus"
13 | )
14 |
15 | var (
16 | integration = flag.Bool("integration", false, "run integration tests")
17 | debug = flag.Bool("debug", false, "debug log level")
18 | masterURL = "https://localhost:8443"
19 | k3dClusterName = "traefik-mesh-integration"
20 | traefikMeshNamespace = "traefik-mesh"
21 | traefikMeshBinary = "../dist/traefik-mesh"
22 | smiCRDs = "./testdata/crds/"
23 | testNamespace = "test"
24 | )
25 |
26 | func Test(t *testing.T) {
27 | if !*integration {
28 | log.Println("Integration tests disabled")
29 | return
30 | }
31 |
32 | if *debug {
33 | logrus.SetLevel(logrus.DebugLevel)
34 | }
35 |
36 | check.Suite(&ACLDisabledSuite{})
37 | check.Suite(&ACLEnabledSuite{})
38 | check.Suite(&CoreDNSSuite{})
39 | check.Suite(&KubeDNSSuite{})
40 |
41 | check.TestingT(t)
42 | }
43 |
44 | func traefikMeshPrepare() error {
45 | args := []string{
46 | "prepare",
47 | "--masterurl=" + masterURL,
48 | "--kubeconfig=" + os.Getenv("KUBECONFIG"),
49 | "--loglevel=debug",
50 | "--clusterdomain=cluster.local",
51 | "--namespace=" + traefikMeshNamespace,
52 | }
53 |
54 | cmd := exec.Command(traefikMeshBinary, args...)
55 | cmd.Env = os.Environ()
56 |
57 | output, err := cmd.CombinedOutput()
58 | if err != nil {
59 | return fmt.Errorf("traefik mesh prepare has failed - %s: %w", string(output), err)
60 | }
61 |
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/integration/kubedns_test.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/go-check/check"
7 | "github.com/sirupsen/logrus"
8 | "github.com/traefik/mesh/integration/k3d"
9 | "github.com/traefik/mesh/integration/tool"
10 | "github.com/traefik/mesh/integration/try"
11 | checker "github.com/vdemeester/shakers"
12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13 | )
14 |
15 | // KubeDNSSuite.
16 | type KubeDNSSuite struct {
17 | logger logrus.FieldLogger
18 | cluster *k3d.Cluster
19 | tool *tool.Tool
20 | }
21 |
22 | func (s *KubeDNSSuite) SetUpSuite(c *check.C) {
23 | var err error
24 |
25 | requiredImages := []k3d.DockerImage{
26 | {Name: "traefik/whoami:v1.6.0"},
27 | {Name: "coredns/coredns:1.6.3"},
28 | {Name: "giantswarm/tiny-tools:3.9"},
29 | {Name: "gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.7"},
30 | {Name: "gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.7"},
31 | {Name: "gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.7"},
32 | }
33 |
34 | s.logger = logrus.New()
35 | s.cluster, err = k3d.NewCluster(s.logger, masterURL, k3dClusterName,
36 | k3d.WithoutTraefik(),
37 | k3d.WithoutCoreDNS(),
38 | k3d.WithImages(requiredImages...),
39 | )
40 | c.Assert(err, checker.IsNil)
41 |
42 | c.Assert(s.cluster.CreateNamespace(s.logger, traefikMeshNamespace), checker.IsNil)
43 | c.Assert(s.cluster.CreateNamespace(s.logger, testNamespace), checker.IsNil)
44 |
45 | c.Assert(s.cluster.Apply(s.logger, smiCRDs), checker.IsNil)
46 | c.Assert(s.cluster.Apply(s.logger, "testdata/tool/tool.yaml"), checker.IsNil)
47 | c.Assert(s.cluster.Apply(s.logger, "testdata/kubedns/"), checker.IsNil)
48 | c.Assert(s.cluster.Apply(s.logger, "testdata/coredns/whoami-shadow-service.yaml"), checker.IsNil)
49 |
50 | c.Assert(s.cluster.WaitReadyPod("tool", testNamespace, 60*time.Second), checker.IsNil)
51 | c.Assert(s.cluster.WaitReadyDeployment("kube-dns", metav1.NamespaceSystem, 60*time.Second), checker.IsNil)
52 | c.Assert(s.cluster.WaitReadyDeployment("coredns", traefikMeshNamespace, 60*time.Second), checker.IsNil)
53 |
54 | s.tool = tool.New(s.logger, "tool", testNamespace)
55 | }
56 |
57 | func (s *KubeDNSSuite) TearDownSuite(c *check.C) {
58 | if s.cluster != nil {
59 | c.Assert(s.cluster.Stop(s.logger), checker.IsNil)
60 | }
61 | }
62 |
63 | func (s *KubeDNSSuite) TestKubeDNSDig(c *check.C) {
64 | s.logger.Info("Asserting KubeDNS has been patched successfully and can be dug")
65 |
66 | c.Assert(traefikMeshPrepare(), checker.IsNil)
67 |
68 | // Wait for kubeDNS, as the pods will be restarted by prepare.
69 | c.Assert(s.cluster.WaitReadyDeployment("kube-dns", metav1.NamespaceSystem, 60*time.Second), checker.IsNil)
70 |
71 | err := try.Retry(func() error {
72 | return s.tool.Dig("whoami.whoami.maesh")
73 | }, 60*time.Second)
74 | c.Assert(err, checker.IsNil)
75 |
76 | err = try.Retry(func() error {
77 | return s.tool.Dig("whoami.whoami.traefik.mesh")
78 | }, 60*time.Second)
79 | c.Assert(err, checker.IsNil)
80 | }
81 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/http/1.server.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-http
6 | namespace: test
7 | labels:
8 | app: server-http
9 | spec:
10 | containers:
11 | - name: server-http
12 | image: traefik/whoami:v1.6.0
13 | imagePullPolicy: IfNotPresent
14 | readinessProbe:
15 | httpGet:
16 | path: /
17 | port: 80
18 | periodSeconds: 1
19 |
20 | ---
21 | apiVersion: v1
22 | kind: Service
23 | metadata:
24 | name: server-http
25 | namespace: test
26 | labels:
27 | app: server-http
28 | spec:
29 | type: ClusterIP
30 | ports:
31 | - port: 8080
32 | name: server-http
33 | targetPort: 80
34 | selector:
35 | app: server-http
36 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/tcp/1.server.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-tcp
6 | namespace: test
7 | labels:
8 | app: server-tcp
9 | spec:
10 | containers:
11 | - name: server-tcp
12 | image: traefik/whoamitcp:v0.1.0
13 | imagePullPolicy: IfNotPresent
14 | readinessProbe:
15 | tcpSocket:
16 | port: 8080
17 | periodSeconds: 1
18 |
19 | ---
20 | apiVersion: v1
21 | kind: Service
22 | metadata:
23 | name: server-tcp
24 | namespace: test
25 | labels:
26 | app: server-tcp
27 | plop: cool
28 | annotations:
29 | mesh.traefik.io/traffic-type: tcp
30 | spec:
31 | type: ClusterIP
32 | ports:
33 | - port: 8080
34 | name: server-tcp
35 | selector:
36 | app: server-tcp
37 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/traffic-split/1.server.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: server-split
6 | namespace: test
7 | labels:
8 | app: server-split
9 | spec:
10 | type: ClusterIP
11 | ports:
12 | - port: 8080
13 | name: server-split
14 | selector:
15 | app: server-split
16 |
17 | ---
18 | apiVersion: split.smi-spec.io/v1alpha3
19 | kind: TrafficSplit
20 | metadata:
21 | name: server-traffic-split
22 | namespace: test
23 | spec:
24 | service: server-split
25 | backends:
26 | - service: server-v1
27 | weight: 50
28 | - service: server-v2
29 | weight: 50
30 |
31 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/traffic-split/2.server-v1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-v1
6 | namespace: test
7 | labels:
8 | app: server-v1
9 | spec:
10 | containers:
11 | - name: server-v1
12 | image: traefik/whoami:v1.6.0
13 | imagePullPolicy: IfNotPresent
14 | readinessProbe:
15 | httpGet:
16 | path: /
17 | port: 80
18 | periodSeconds: 1
19 |
20 | ---
21 | apiVersion: v1
22 | kind: Service
23 | metadata:
24 | name: server-v1
25 | namespace: test
26 | labels:
27 | app: server-v1
28 | spec:
29 | type: ClusterIP
30 | ports:
31 | - port: 8080
32 | name: server-v1
33 | targetPort: 80
34 | selector:
35 | app: server-v1
36 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/traffic-split/3.server-v2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-v2
6 | namespace: test
7 | labels:
8 | app: server-v2
9 | spec:
10 | containers:
11 | - name: server-v2
12 | image: traefik/whoami:v1.6.0
13 | imagePullPolicy: IfNotPresent
14 | readinessProbe:
15 | httpGet:
16 | path: /
17 | port: 80
18 | periodSeconds: 1
19 |
20 | ---
21 | apiVersion: v1
22 | kind: Service
23 | metadata:
24 | name: server-v2
25 | namespace: test
26 | labels:
27 | app: server-v2
28 | spec:
29 | type: ClusterIP
30 | ports:
31 | - port: 8080
32 | name: server-v2
33 | targetPort: 80
34 | selector:
35 | app: server-v2
36 |
--------------------------------------------------------------------------------
/integration/testdata/acl_disabled/udp/1.server.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-udp
6 | namespace: test
7 | labels:
8 | app: server-udp
9 | spec:
10 | containers:
11 | - name: server-udp
12 | image: traefik/whoamiudp:v0.1.0
13 | imagePullPolicy: IfNotPresent
14 | ports:
15 | - name: udp
16 | protocol: UDP
17 | containerPort: 8080
18 | ---
19 | apiVersion: v1
20 | kind: Service
21 | metadata:
22 | name: server-udp
23 | namespace: test
24 | labels:
25 | app: server-udp
26 | plop: cool
27 | annotations:
28 | mesh.traefik.io/traffic-type: udp
29 | spec:
30 | type: ClusterIP
31 | ports:
32 | - name: server-udp
33 | protocol: UDP
34 | port: 8080
35 | selector:
36 | app: server-udp
37 |
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/0.service-account.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: server
6 | namespace: test
7 |
8 | ---
9 | apiVersion: v1
10 | kind: ServiceAccount
11 | metadata:
12 | name: server-api
13 | namespace: test
14 |
15 | ---
16 | apiVersion: v1
17 | kind: ServiceAccount
18 | metadata:
19 | name: server-header
20 | namespace: test
21 |
22 | ---
23 | apiVersion: v1
24 | kind: ServiceAccount
25 | metadata:
26 | name: server-split
27 | namespace: test
28 |
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/1.server.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-http
6 | namespace: test
7 | labels:
8 | app: server-http
9 | spec:
10 | serviceAccountName: server
11 | containers:
12 | - name: server-http
13 | image: traefik/whoami:v1.6.0
14 | imagePullPolicy: IfNotPresent
15 | readinessProbe:
16 | httpGet:
17 | path: /
18 | port: 80
19 | periodSeconds: 1
20 |
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: server-http
26 | namespace: test
27 | labels:
28 | app: server-http
29 | spec:
30 | type: ClusterIP
31 | ports:
32 | - port: 8080
33 | name: server-http
34 | targetPort: 80
35 | selector:
36 | app: server-http
37 |
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/3.server-api.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-http-api
6 | namespace: test
7 | labels:
8 | app: server-http-api
9 | spec:
10 | serviceAccountName: server-api
11 | containers:
12 | - name: server-http-api
13 | image: traefik/whoami:v1.6.0
14 | imagePullPolicy: IfNotPresent
15 | readinessProbe:
16 | httpGet:
17 | path: /
18 | port: 80
19 | periodSeconds: 1
20 |
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: server-http-api
26 | namespace: test
27 | labels:
28 | app: server-http-api
29 | spec:
30 | type: ClusterIP
31 | ports:
32 | - port: 8080
33 | name: server-http-api
34 | targetPort: 80
35 | selector:
36 | app: server-http-api
37 |
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/4.server-header.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: server-http-header
6 | namespace: test
7 | labels:
8 | app: server-http-header
9 | spec:
10 | serviceAccountName: server-header
11 | containers:
12 | - name: server-http-header
13 | image: traefik/whoami:v1.6.0
14 | imagePullPolicy: IfNotPresent
15 | readinessProbe:
16 | httpGet:
17 | path: /
18 | port: 80
19 | periodSeconds: 1
20 |
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: server-http-header
26 | namespace: test
27 | labels:
28 | app: server-http-header
29 | spec:
30 | type: ClusterIP
31 | ports:
32 | - port: 8080
33 | name: server-http-header
34 | targetPort: 80
35 | selector:
36 | app: server-http-header
37 |
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/6.traffic-target.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: access.smi-spec.io/v1alpha2
3 | kind: TrafficTarget
4 | metadata:
5 | name: tool-authorized-to-server-http
6 | namespace: test
7 | spec:
8 | destination:
9 | kind: ServiceAccount
10 | name: server
11 | namespace: test
12 | sources:
13 | - kind: ServiceAccount
14 | name: tool-authorized
15 | namespace: test
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/7.traffic-target-path-filter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: specs.smi-spec.io/v1alpha3
3 | kind: HTTPRouteGroup
4 | metadata:
5 | name: http-route-group-api
6 | namespace: test
7 | spec:
8 | matches:
9 | - name: api
10 | pathRegex: /api
11 | methods: ["GET"]
12 |
13 | ---
14 | apiVersion: access.smi-spec.io/v1alpha2
15 | kind: TrafficTarget
16 | metadata:
17 | name: traffic-target-path-filter
18 | namespace: test
19 | spec:
20 | destination:
21 | kind: ServiceAccount
22 | name: server-api
23 | namespace: test
24 | rules:
25 | - kind: HTTPRouteGroup
26 | name: http-route-group-api
27 | sources:
28 | - kind: ServiceAccount
29 | name: tool-authorized
30 | namespace: test
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/http/8.traffic-target-header-filter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: specs.smi-spec.io/v1alpha3
3 | kind: HTTPRouteGroup
4 | metadata:
5 | name: http-route-group-header
6 | namespace: test
7 | spec:
8 | matches:
9 | - name: header
10 | headers:
11 | - Authorized: "t|True"
12 |
13 | ---
14 | apiVersion: access.smi-spec.io/v1alpha2
15 | kind: TrafficTarget
16 | metadata:
17 | name: traffic-target-header-filter
18 | namespace: test
19 | spec:
20 | destination:
21 | kind: ServiceAccount
22 | name: server-header
23 | namespace: test
24 | rules:
25 | - kind: HTTPRouteGroup
26 | name: http-route-group-header
27 | sources:
28 | - kind: ServiceAccount
29 | name: tool-authorized
30 | namespace: test
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/traffic-split/0.service-account.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: server-split
6 | namespace: test
--------------------------------------------------------------------------------
/integration/testdata/acl_enabled/traffic-split/1.server-split.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: server-http-split
6 | namespace: test
7 | labels:
8 | app: server-http-split
9 | spec:
10 | type: ClusterIP
11 | ports:
12 | - port: 8080
13 | name: server-http-split
14 | selector:
15 | app: server-http-split
16 |
17 | ---
18 | apiVersion: v1
19 | kind: Pod
20 | metadata:
21 | name: server-http-split-v1
22 | namespace: test
23 | labels:
24 | app: server-http-split-v1
25 | spec:
26 | serviceAccountName: server-split
27 | containers:
28 | - name: server-http-split-v1
29 | image: traefik/whoami:v1.6.0
30 | imagePullPolicy: IfNotPresent
31 | readinessProbe:
32 | httpGet:
33 | path: /
34 | port: 80
35 | periodSeconds: 1
36 |
37 | ---
38 | apiVersion: v1
39 | kind: Service
40 | metadata:
41 | name: server-http-split-v1
42 | namespace: test
43 | labels:
44 | app: server-http-split-v1
45 | spec:
46 | type: ClusterIP
47 | ports:
48 | - port: 8080
49 | name: server-http-split-v1
50 | targetPort: 80
51 | selector:
52 | app: server-http-split-v1
53 |
54 | ---
55 | apiVersion: v1
56 | kind: Pod
57 | metadata:
58 | name: server-http-split-v2
59 | namespace: test
60 | labels:
61 | app: server-http-split-v2
62 | spec:
63 | serviceAccountName: server-split
64 | containers:
65 | - name: server-http-split-v2
66 | image: traefik/whoami:v1.6.0
67 | imagePullPolicy: IfNotPresent
68 | readinessProbe:
69 | httpGet:
70 | path: /
71 | port: 80
72 | periodSeconds: 1
73 |
74 | ---
75 | apiVersion: v1
76 | kind: Service
77 | metadata:
78 | name: server-http-split-v2
79 | namespace: test
80 | labels:
81 | app: server-http-split-v2
82 | spec:
83 | type: ClusterIP
84 | ports:
85 | - port: 8080
86 | name: server-http-split-v2
87 | targetPort: 80
88 | selector:
89 | app: server-http-split-v2
90 |
91 | ---
92 | apiVersion: split.smi-spec.io/v1alpha3
93 | kind: TrafficSplit
94 | metadata:
95 | name: server-http-split
96 | namespace: test
97 | spec:
98 | service: server-http-split
99 | backends:
100 | - service: server-http-split-v1
101 | weight: 50
102 | - service: server-http-split-v2
103 | weight: 50
104 |
105 | ---
106 | apiVersion: access.smi-spec.io/v1alpha2
107 | kind: TrafficTarget
108 | metadata:
109 | name: tool-authorized-to-server-http-split
110 | namespace: test
111 | spec:
112 | destination:
113 | kind: ServiceAccount
114 | name: server-split
115 | namespace: test
116 | sources:
117 | - kind: ServiceAccount
118 | name: tool-authorized
119 | namespace: test
120 |
--------------------------------------------------------------------------------
/integration/testdata/coredns/whoami-shadow-service.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: traefik-mesh-whoami-6d61657368-whoami
6 | namespace: traefik-mesh
7 | labels:
8 | app: maesh
9 | type: shadow
10 | spec:
11 | type: ClusterIP
12 | ports:
13 | - port: 8080
14 | name: whoami
15 | targetPort: 80
16 | selector:
17 | app: traefik-mesh-proxy
18 |
--------------------------------------------------------------------------------
/integration/testdata/crds/smi-access.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1beta1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: traffictargets.access.smi-spec.io
6 | spec:
7 | group: access.smi-spec.io
8 | scope: Namespaced
9 | names:
10 | kind: TrafficTarget
11 | shortNames:
12 | - tt
13 | plural: traffictargets
14 | singular: traffictarget
15 | version: v1alpha2
16 | versions:
17 | - name: v1alpha2
18 | served: true
19 | storage: true
20 | - name: v1alpha1
21 | served: false
22 | storage: false
23 | validation:
24 | openAPIV3Schema:
25 | properties:
26 | spec:
27 | required:
28 | - destination
29 | properties:
30 | destination:
31 | description: The destination of this traffic target.
32 | type: object
33 | required:
34 | - name
35 | - kind
36 | properties:
37 | kind:
38 | description: Kind of the destination.
39 | type: string
40 | name:
41 | description: Name of the destination.
42 | type: string
43 | namespace:
44 | description: Namespace of the destination.
45 | type: string
46 | port:
47 | description: Port number of the destination.
48 | type: number
49 | rules:
50 | description: Specifications of this traffic target.
51 | type: array
52 | items:
53 | type: object
54 | required:
55 | - name
56 | - kind
57 | properties:
58 | kind:
59 | description: Kind of this spec.
60 | type: string
61 | enum:
62 | - HTTPRouteGroup
63 | - TCPRoute
64 | name:
65 | description: Name of this spec.
66 | type: string
67 | matches:
68 | description: Match conditions of this spec.
69 | type: array
70 | items:
71 | type: string
72 | sources:
73 | description: Sources of this traffic target.
74 | type: array
75 | items:
76 | type: object
77 | required:
78 | - name
79 | - kind
80 | properties:
81 | kind:
82 | description: Kind of this source.
83 | type: string
84 | name:
85 | description: Name of this source.
86 | type: string
87 | namespace:
88 | description: Namespace of this source.
89 | type: string
90 |
--------------------------------------------------------------------------------
/integration/testdata/crds/smi-specs.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1beta1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: httproutegroups.specs.smi-spec.io
6 | spec:
7 | group: specs.smi-spec.io
8 | scope: Namespaced
9 | names:
10 | kind: HTTPRouteGroup
11 | shortNames:
12 | - htr
13 | plural: httproutegroups
14 | singular: httproutegroup
15 | version: v1alpha3
16 | versions:
17 | - name: v1alpha3
18 | served: true
19 | storage: true
20 | - name: v1alpha2
21 | served: false
22 | storage: false
23 | - name: v1alpha1
24 | served: false
25 | storage: false
26 | validation:
27 | openAPIV3Schema:
28 | properties:
29 | spec:
30 | required:
31 | - matches
32 | properties:
33 | matches:
34 | description: Match conditions of this route group.
35 | type: array
36 | items:
37 | type: object
38 | required:
39 | - name
40 | properties:
41 | name:
42 | description: Name of the HTTP route.
43 | type: string
44 | pathRegex:
45 | description: URI path regex of the HTTP route.
46 | type: string
47 | methods:
48 | description: The HTTP methods of this HTTP route.
49 | type: array
50 | items:
51 | type: string
52 | description: The HTTP method of this HTTP route.
53 | enum:
54 | - '*'
55 | - GET
56 | - HEAD
57 | - PUT
58 | - POST
59 | - DELETE
60 | - CONNECT
61 | - OPTIONS
62 | - TRACE
63 | - PATCH
64 | headers:
65 | description: Header match conditions of this route.
66 | type: array
67 | items:
68 | description: Header match condition of this route.
69 | type: object
70 | additionalProperties:
71 | type: string
72 | ---
73 | apiVersion: apiextensions.k8s.io/v1beta1
74 | kind: CustomResourceDefinition
75 | metadata:
76 | name: tcproutes.specs.smi-spec.io
77 | spec:
78 | group: specs.smi-spec.io
79 | scope: Namespaced
80 | names:
81 | kind: TCPRoute
82 | shortNames:
83 | - tr
84 | plural: tcproutes
85 | singular: tcproute
86 | version: v1alpha3
87 | versions:
88 | - name: v1alpha3
89 | served: true
90 | storage: true
91 | - name: v1alpha2
92 | served: false
93 | storage: false
94 | - name: v1alpha1
95 | served: false
96 | storage: false
97 |
--------------------------------------------------------------------------------
/integration/testdata/crds/smi-split.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1beta1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: trafficsplits.split.smi-spec.io
6 | spec:
7 | group: split.smi-spec.io
8 | scope: Namespaced
9 | names:
10 | kind: TrafficSplit
11 | listKind: TrafficSplitList
12 | shortNames:
13 | - ts
14 | plural: trafficsplits
15 | singular: trafficsplit
16 | version: v1alpha3
17 | versions:
18 | - name: v1alpha3
19 | served: true
20 | storage: true
21 | - name: v1alpha2
22 | served: false
23 | storage: false
24 | - name: v1alpha1
25 | served: false
26 | storage: false
27 | additionalPrinterColumns:
28 | - name: Service
29 | type: string
30 | description: The apex service of this split.
31 | JSONPath: .spec.service
32 | validation:
33 | openAPIV3Schema:
34 | properties:
35 | spec:
36 | type: object
37 | required:
38 | - service
39 | - backends
40 | properties:
41 | service:
42 | description: The apex service of this split.
43 | type: string
44 | matches:
45 | description: The HTTP route groups that this traffic split should match.
46 | type: array
47 | items:
48 | type: object
49 | required: ['kind', 'name']
50 | properties:
51 | kind:
52 | description: Kind of the matching group.
53 | type: string
54 | enum:
55 | - HTTPRouteGroup
56 | name:
57 | description: Name of the matching group.
58 | type: string
59 | backends:
60 | description: The backend services of this split.
61 | type: array
62 | items:
63 | type: object
64 | required: ['service', 'weight']
65 | properties:
66 | service:
67 | description: Name of the Kubernetes service.
68 | type: string
69 | weight:
70 | description: Traffic weight value of this backend.
71 | type: number
72 |
--------------------------------------------------------------------------------
/integration/testdata/tool/tool-authorized.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: tool-authorized
6 | namespace: test
7 |
8 | ---
9 | apiVersion: v1
10 | kind: Pod
11 | metadata:
12 | name: tool-authorized
13 | namespace: test
14 | spec:
15 | serviceAccountName: tool-authorized
16 | containers:
17 | - name: tool-authorized
18 | image: giantswarm/tiny-tools:3.9
19 | command:
20 | - "sleep"
21 | - "36000"
--------------------------------------------------------------------------------
/integration/testdata/tool/tool-forbidden.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: tool-forbidden
6 | namespace: test
7 |
8 | ---
9 | apiVersion: v1
10 | kind: Pod
11 | metadata:
12 | name: tool-forbidden
13 | namespace: test
14 | spec:
15 | serviceAccountName: tool-forbidden
16 | containers:
17 | - name: tool-forbidden
18 | image: giantswarm/tiny-tools:3.9
19 | command:
20 | - "sleep"
21 | - "36000"
--------------------------------------------------------------------------------
/integration/testdata/tool/tool.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: tool
6 | namespace: test
7 |
8 | ---
9 | apiVersion: v1
10 | kind: Pod
11 | metadata:
12 | name: tool
13 | namespace: test
14 | spec:
15 | serviceAccountName: tool
16 | containers:
17 | - name: tool
18 | image: giantswarm/tiny-tools:3.9
19 | command:
20 | - "sleep"
21 | - "36000"
--------------------------------------------------------------------------------
/integration/testdata/traefik-mesh/values.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Traefik Mesh configuration.
3 | #
4 | controller:
5 | image:
6 | pullPolicy: IfNotPresent
7 | tag: latest
8 |
9 | proxy:
10 | image:
11 | pullPolicy: IfNotPresent
12 | tag: v2.3
13 |
14 | pollInterval: 100ms
15 | pollTimeout: 100ms
16 |
17 | #
18 | # Tracing configuration.
19 | #
20 | tracing:
21 | deploy: false
22 | jaeger:
23 | enabled: false
24 |
25 | #
26 | # Metrics configuration.
27 | #
28 | metrics:
29 | deploy: false
30 | prometheus:
31 | enabled: false
32 |
--------------------------------------------------------------------------------
/integration/tool/tool.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "fmt"
7 | "net"
8 | "net/http"
9 | "os"
10 | "os/exec"
11 | "strings"
12 | "time"
13 |
14 | "github.com/sirupsen/logrus"
15 | "github.com/traefik/mesh/integration/try"
16 | )
17 |
18 | // Tool is pod capable of running operations from within the cluster.
19 | type Tool struct {
20 | logger logrus.FieldLogger
21 | name string
22 | namespace string
23 | kubectlTimeout time.Duration
24 | }
25 |
26 | // New creates a new Tool.
27 | func New(logger logrus.FieldLogger, name, namespace string) *Tool {
28 | return &Tool{
29 | name: name,
30 | namespace: namespace,
31 | logger: logger,
32 | kubectlTimeout: 3 * time.Second,
33 | }
34 | }
35 |
36 | // Dig digs the given url and make sure there is an A record.
37 | func (t *Tool) Dig(url string) error {
38 | output, err := t.exec([]string{"dig", url, "+short", "+timeout=3"})
39 | if err != nil {
40 | t.logger.WithError(err).Debug("Dig command has failed")
41 | return err
42 | }
43 |
44 | IP := net.ParseIP(strings.TrimSpace(string(output)))
45 | if IP == nil {
46 | return fmt.Errorf("could not parse an IP from dig: %s", string(output))
47 | }
48 |
49 | t.logger.Debugf("Dig %q: %s", url, IP.String())
50 |
51 | return nil
52 | }
53 |
54 | // Curl curls the given url and checks if it matches the given conditions.
55 | func (t *Tool) Curl(url string, headers map[string]string, conditions ...try.ResponseCondition) error {
56 | args := []string{"curl", "-s", "-D-", "-m", "2"}
57 |
58 | for key, value := range headers {
59 | args = append(args, "-H", key+": "+value)
60 | }
61 |
62 | output, err := t.exec(append(args, url))
63 | if err != nil {
64 | t.logger.WithError(err).Debug("Curl command has failed")
65 | return err
66 | }
67 |
68 | reader := bufio.NewReader(bytes.NewReader(output))
69 |
70 | resp, err := http.ReadResponse(reader, nil)
71 | if err != nil {
72 | t.logger.WithError(err).Debug("Curl output is not an HTTP response")
73 | return err
74 | }
75 |
76 | defer resp.Body.Close()
77 |
78 | for _, condition := range conditions {
79 | if err := condition(resp); err != nil {
80 | t.logger.Debugf("Curl condition did not match: %v", err)
81 |
82 | return err
83 | }
84 | }
85 |
86 | return nil
87 | }
88 |
89 | // Netcat netcats the given url on the given port and checks if the given conditions are fulfilled.
90 | func (t *Tool) Netcat(url string, port int, udp bool, conditions ...try.StringCondition) error {
91 | var cmd string
92 |
93 | if udp {
94 | cmd = fmt.Sprintf("echo 'WHO' | nc -u -w 1 %s %d", url, port)
95 | } else {
96 | cmd = fmt.Sprintf("echo 'WHO' | nc -q 0 %s %d", url, port)
97 | }
98 |
99 | output, err := t.exec([]string{"ash", "-c", cmd})
100 | if err != nil {
101 | t.logger.WithError(err).Debug("Netcat command has failed")
102 | return err
103 | }
104 |
105 | for _, condition := range conditions {
106 | if err := condition(string(output)); err != nil {
107 | t.logger.Debugf("Netcat condition did not match: %v", err)
108 |
109 | return err
110 | }
111 | }
112 |
113 | return nil
114 | }
115 |
116 | func (t *Tool) exec(args []string) ([]byte, error) {
117 | args = append([]string{
118 | "exec", "-i", t.name,
119 | "--request-timeout=3s",
120 | "-n", t.namespace,
121 | "--",
122 | }, args...)
123 |
124 | cmd := exec.Command("kubectl", args...)
125 | cmd.Env = os.Environ()
126 |
127 | output, err := cmd.CombinedOutput()
128 | if err != nil {
129 | return []byte{}, fmt.Errorf("unable execute command 'kubectl %s' - output %s: %w", strings.Join(args, " "), output, err)
130 | }
131 |
132 | return output, nil
133 | }
134 |
--------------------------------------------------------------------------------
/integration/try/condition.go:
--------------------------------------------------------------------------------
1 | package try
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | // StringCondition is a retry condition function.
11 | // It receives a string, and returns an error
12 | // if the string failed the condition.
13 | type StringCondition func(string) error
14 |
15 | // StringContains returns a retry condition function.
16 | // The condition returns an error if the string does not contain the given values.
17 | func StringContains(values ...string) StringCondition {
18 | return func(res string) error {
19 | for _, value := range values {
20 | if !strings.Contains(res, value) {
21 | return fmt.Errorf("could not find %q in %q", value, res)
22 | }
23 | }
24 |
25 | return nil
26 | }
27 | }
28 |
29 | // ResponseCondition is a retry condition function.
30 | // It receives a response, and returns an error
31 | // if the response failed the condition.
32 | type ResponseCondition func(*http.Response) error
33 |
34 | // BodyContains returns a retry condition function.
35 | // The condition returns an error if the request body does not contain all the given
36 | // strings.
37 | func BodyContains(values ...string) ResponseCondition {
38 | return func(res *http.Response) error {
39 | body, err := io.ReadAll(res.Body)
40 | if err != nil {
41 | return fmt.Errorf("failed to read response body: %w", err)
42 | }
43 |
44 | for _, value := range values {
45 | if !strings.Contains(string(body), value) {
46 | return fmt.Errorf("could not find '%s' in body '%s'", value, string(body))
47 | }
48 | }
49 |
50 | return nil
51 | }
52 | }
53 |
54 | // StatusCodeIs returns a retry condition function.
55 | // The condition returns an error if the given response's status code is not the
56 | // given HTTP status code.
57 | func StatusCodeIs(status int) ResponseCondition {
58 | return func(res *http.Response) error {
59 | if res.StatusCode != status {
60 | return fmt.Errorf("got status code %d, wanted %d", res.StatusCode, status)
61 | }
62 |
63 | return nil
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/integration/try/try.go:
--------------------------------------------------------------------------------
1 | package try
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strconv"
7 | "time"
8 |
9 | "github.com/cenkalti/backoff/v4"
10 | "github.com/traefik/mesh/pkg/safe"
11 | )
12 |
13 | // CITimeoutMultiplier is the multiplier for all timeout in the CI.
14 | const CITimeoutMultiplier = 3
15 |
16 | // Retry runs a function over and over until it doesn't return an error or the given timeout duration is reached.
17 | func Retry(f func() error, timeout time.Duration) error {
18 | ebo := backoff.NewExponentialBackOff()
19 | ebo.MaxElapsedTime = applyCIMultiplier(timeout)
20 |
21 | if err := backoff.Retry(safe.OperationWithRecover(f), ebo); err != nil {
22 | return fmt.Errorf("unable execute function: %w", err)
23 | }
24 |
25 | return nil
26 | }
27 |
28 | func applyCIMultiplier(timeout time.Duration) time.Duration {
29 | if os.Getenv("CI") == "" {
30 | return timeout
31 | }
32 |
33 | ciTimeoutMultiplier := getCITimeoutMultiplier()
34 |
35 | return time.Duration(float64(timeout) * ciTimeoutMultiplier)
36 | }
37 |
38 | func getCITimeoutMultiplier() float64 {
39 | ciTimeoutMultiplier := os.Getenv("CI_TIMEOUT_MULTIPLIER")
40 | if ciTimeoutMultiplier == "" {
41 | return CITimeoutMultiplier
42 | }
43 |
44 | multiplier, err := strconv.ParseFloat(ciTimeoutMultiplier, 64)
45 | if err != nil {
46 | return CITimeoutMultiplier
47 | }
48 |
49 | return multiplier
50 | }
51 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | # Path relative to the root of the repository
3 | publish = "site"
4 | base = "docs"
5 |
6 | # Path relative to the "base" directory
7 | command = "sh -x scripts/netlify-run.sh"
8 |
9 | [[headers]]
10 | # Define which paths this specific [[headers]] block will cover.
11 | for = "/*"
12 | [headers.values]
13 | Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
14 |
--------------------------------------------------------------------------------
/pkg/annotations/middleware.go:
--------------------------------------------------------------------------------
1 | package annotations
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/traefik/traefik/v2/pkg/config/dynamic"
8 | )
9 |
10 | type middlewareBuilder func(annotations map[string]string) (middleware *dynamic.Middleware, name string, err error)
11 |
12 | // BuildMiddlewares builds middlewares from the given annotations.
13 | func BuildMiddlewares(annotations map[string]string) (map[string]*dynamic.Middleware, error) {
14 | builders := []middlewareBuilder{
15 | buildRetryMiddleware,
16 | buildRateLimitMiddleware,
17 | buildCircuitBreakerMiddleware,
18 | }
19 |
20 | middlewares := map[string]*dynamic.Middleware{}
21 |
22 | for _, builder := range builders {
23 | middleware, name, err := builder(annotations)
24 | if err != nil {
25 | return nil, err
26 | }
27 |
28 | if middleware != nil {
29 | middlewares[name] = middleware
30 | }
31 | }
32 |
33 | return middlewares, nil
34 | }
35 |
36 | func buildRetryMiddleware(annotations map[string]string) (middleware *dynamic.Middleware, name string, err error) {
37 | var retryAttempts int
38 |
39 | retryAttempts, err = GetRetryAttempts(annotations)
40 | if err != nil {
41 | if errors.Is(err, ErrNotFound) {
42 | return nil, "", nil
43 | }
44 |
45 | return nil, "", fmt.Errorf("unable to build retry middleware: %w", err)
46 | }
47 |
48 | name = "retry"
49 | middleware = &dynamic.Middleware{
50 | Retry: &dynamic.Retry{Attempts: retryAttempts},
51 | }
52 |
53 | return middleware, name, nil
54 | }
55 |
56 | func buildRateLimitMiddleware(annotations map[string]string) (middleware *dynamic.Middleware, name string, err error) {
57 | var (
58 | rateLimitBurst int
59 | rateLimitAverage int
60 | )
61 |
62 | rateLimitBurst, err = GetRateLimitBurst(annotations)
63 | if errors.Is(err, ErrNotFound) {
64 | return nil, "", nil
65 | } else if err != nil {
66 | return nil, "", fmt.Errorf("unable to build rate-limit middleware: %w", err)
67 | }
68 |
69 | rateLimitAverage, err = GetRateLimitAverage(annotations)
70 | if errors.Is(err, ErrNotFound) {
71 | return nil, "", nil
72 | } else if err != nil {
73 | return nil, "", fmt.Errorf("unable to build rate-limit middleware: %w", err)
74 | }
75 |
76 | if rateLimitBurst <= 0 || rateLimitAverage <= 0 {
77 | return nil, "", errors.New("unable to build rate-limit middleware: burst and average must be greater than 0")
78 | }
79 |
80 | name = "rate-limit"
81 | middleware = &dynamic.Middleware{
82 | RateLimit: &dynamic.RateLimit{
83 | Burst: int64(rateLimitBurst),
84 | Average: int64(rateLimitAverage),
85 | },
86 | }
87 |
88 | return middleware, name, nil
89 | }
90 |
91 | func buildCircuitBreakerMiddleware(annotations map[string]string) (middleware *dynamic.Middleware, name string, err error) {
92 | var circuitBreakerExpression string
93 |
94 | circuitBreakerExpression, err = GetCircuitBreakerExpression(annotations)
95 | if err != nil {
96 | if errors.Is(err, ErrNotFound) {
97 | return nil, "", nil
98 | }
99 |
100 | return nil, "", fmt.Errorf("unable to build circuit-breaker middleware: %w", err)
101 | }
102 |
103 | name = "circuit-breaker"
104 | middleware = &dynamic.Middleware{
105 | CircuitBreaker: &dynamic.CircuitBreaker{
106 | Expression: circuitBreakerExpression,
107 | },
108 | }
109 |
110 | return middleware, name, nil
111 | }
112 |
--------------------------------------------------------------------------------
/pkg/api/testdata/getmeshnodeconfiguration_empty.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/api/testdata/getmeshnodeconfiguration_empty.yaml
--------------------------------------------------------------------------------
/pkg/api/testdata/getmeshnodeconfiguration_simple.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "127.0.0.1"
14 |
--------------------------------------------------------------------------------
/pkg/api/testdata/getmeshnodes_empty.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/api/testdata/getmeshnodes_empty.yaml
--------------------------------------------------------------------------------
/pkg/api/testdata/getmeshnodes_one_mesh_pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "10.4.3.2"
14 |
--------------------------------------------------------------------------------
/pkg/api/testdata/getmeshnodes_one_nonready_mesh_pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "10.4.19.1"
14 | containerStatuses:
15 | - name: example
16 | ready: false
17 |
--------------------------------------------------------------------------------
/pkg/cleanup/cleanup.go:
--------------------------------------------------------------------------------
1 | package cleanup
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/sirupsen/logrus"
8 | "github.com/traefik/mesh/pkg/dns"
9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | "k8s.io/client-go/kubernetes"
11 | )
12 |
13 | // Cleanup holds the clients for the various resource controllers.
14 | type Cleanup struct {
15 | namespace string
16 | kubeClient kubernetes.Interface
17 | dnsClient *dns.Client
18 | logger logrus.FieldLogger
19 | }
20 |
21 | // NewCleanup returns an initialized cleanup object.
22 | func NewCleanup(logger logrus.FieldLogger, kubeClient kubernetes.Interface, namespace string) *Cleanup {
23 | dnsClient := dns.NewClient(logger, kubeClient)
24 |
25 | return &Cleanup{
26 | kubeClient: kubeClient,
27 | logger: logger,
28 | namespace: namespace,
29 | dnsClient: dnsClient,
30 | }
31 | }
32 |
33 | // CleanShadowServices deletes all shadow services from the cluster.
34 | func (c *Cleanup) CleanShadowServices(ctx context.Context) error {
35 | serviceList, err := c.kubeClient.CoreV1().Services(c.namespace).List(ctx, metav1.ListOptions{
36 | LabelSelector: "app=maesh,type=shadow",
37 | })
38 | if err != nil {
39 | return err
40 | }
41 |
42 | for _, s := range serviceList.Items {
43 | if err := c.kubeClient.CoreV1().Services(s.Namespace).Delete(ctx, s.Name, metav1.DeleteOptions{}); err != nil {
44 | return err
45 | }
46 | }
47 |
48 | return nil
49 | }
50 |
51 | // RestoreDNSConfig restores the configmap and restarts the DNS pods.
52 | func (c *Cleanup) RestoreDNSConfig(ctx context.Context) error {
53 | provider, err := c.dnsClient.CheckDNSProvider(ctx)
54 | if err != nil {
55 | return err
56 | }
57 |
58 | // Restore configmaps based on DNS provider.
59 | switch provider {
60 | case dns.CoreDNS:
61 | if err := c.dnsClient.RestoreCoreDNS(ctx); err != nil {
62 | return fmt.Errorf("unable to restore CoreDNS: %w", err)
63 | }
64 | case dns.KubeDNS:
65 | if err := c.dnsClient.RestoreKubeDNS(ctx); err != nil {
66 | return fmt.Errorf("unable to restore KubeDNS: %w", err)
67 | }
68 | }
69 |
70 | return nil
71 | }
72 |
--------------------------------------------------------------------------------
/pkg/cleanup/cleanup_test.go:
--------------------------------------------------------------------------------
1 | package cleanup
2 |
3 | import (
4 | "context"
5 | "os"
6 | "testing"
7 |
8 | "github.com/sirupsen/logrus"
9 | "github.com/stretchr/testify/assert"
10 | "github.com/stretchr/testify/require"
11 | "github.com/traefik/mesh/pkg/k8s"
12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13 | )
14 |
15 | func TestCleanup_New(t *testing.T) {
16 | clientMock := k8s.NewClientMock("mock.yaml")
17 | logger := logrus.New()
18 |
19 | logger.SetOutput(os.Stdout)
20 | logger.SetLevel(logrus.DebugLevel)
21 |
22 | cleanup := NewCleanup(logger, clientMock.KubernetesClient(), metav1.NamespaceDefault)
23 | require.NotNil(t, cleanup)
24 | }
25 |
26 | func TestCleanup_CleanShadowServices(t *testing.T) {
27 | clientMock := k8s.NewClientMock("mock.yaml")
28 | logger := logrus.New()
29 |
30 | logger.SetOutput(os.Stdout)
31 | logger.SetLevel(logrus.DebugLevel)
32 |
33 | cleanup := NewCleanup(logger, clientMock.KubernetesClient(), "traefik-mesh")
34 | require.NotNil(t, cleanup)
35 |
36 | err := cleanup.CleanShadowServices(context.Background())
37 | require.NoError(t, err)
38 |
39 | serviceList, err := clientMock.KubernetesClient().CoreV1().Services(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{
40 | LabelSelector: "app=maesh,type=shadow",
41 | })
42 | require.NoError(t, err)
43 | assert.Len(t, serviceList.Items, 0)
44 |
45 | serviceList, err = clientMock.KubernetesClient().CoreV1().Services(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{})
46 | require.NoError(t, err)
47 | assert.Len(t, serviceList.Items, 2)
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/cleanup/testdata/mock.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: test1
6 | namespace: traefik-mesh
7 | labels:
8 | app: maesh
9 | type: shadow
10 | spec:
11 | selector:
12 | app: test
13 | ports:
14 | - protocol: TCP
15 | port: 80
16 | targetPort: 8080
17 |
18 | ---
19 | apiVersion: v1
20 | kind: Service
21 | metadata:
22 | name: test2
23 | namespace: traefik-mesh
24 | labels:
25 | app: maesh
26 | type: shadow
27 | spec:
28 | selector:
29 | app: test
30 | ports:
31 | - protocol: TCP
32 | port: 80
33 | targetPort: 8080
34 |
35 | ---
36 | apiVersion: v1
37 | kind: Service
38 | metadata:
39 | name: test3
40 | namespace: traefik-mesh
41 | spec:
42 | selector:
43 | app: test
44 | ports:
45 | - protocol: TCP
46 | port: 80
47 | targetPort: 8080
48 |
49 | ---
50 | apiVersion: v1
51 | kind: Service
52 | metadata:
53 | name: test4
54 | namespace: default
55 | spec:
56 | selector:
57 | app: test
58 | ports:
59 | - protocol: TCP
60 | port: 80
61 | targetPort: 8080
62 |
--------------------------------------------------------------------------------
/pkg/controller/controller_test.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "os"
5 | "testing"
6 |
7 | "github.com/sirupsen/logrus"
8 | "github.com/stretchr/testify/assert"
9 | "github.com/traefik/mesh/pkg/k8s"
10 | "github.com/traefik/mesh/pkg/topology"
11 | "github.com/traefik/traefik/v2/pkg/config/dynamic"
12 | )
13 |
14 | const (
15 | traefikMeshNamespace string = "traefik-mesh"
16 | minHTTPPort = int32(5000)
17 | maxHTTPPort = int32(5005)
18 | minTCPPort = int32(10000)
19 | maxTCPPort = int32(10005)
20 | minUDPPort = int32(15000)
21 | maxUDPPort = int32(15005)
22 | )
23 |
24 | type storeMock struct{}
25 |
26 | func (a *storeMock) SetConfig(cfg *dynamic.Configuration) {}
27 | func (a *storeMock) SetTopology(topo *topology.Topology) {}
28 | func (a *storeMock) SetReadiness(isReady bool) {}
29 |
30 | func TestController_NewMeshController(t *testing.T) {
31 | store := &storeMock{}
32 | clientMock := k8s.NewClientMock("mock.yaml")
33 |
34 | log := logrus.New()
35 | log.SetOutput(os.Stdout)
36 | log.SetLevel(logrus.DebugLevel)
37 |
38 | // Create a new controller with base HTTP mode.
39 | controller := NewMeshController(clientMock, Config{
40 | ACLEnabled: false,
41 | DefaultMode: "http",
42 | Namespace: traefikMeshNamespace,
43 | IgnoreNamespaces: []string{},
44 | MinHTTPPort: minHTTPPort,
45 | MaxHTTPPort: maxHTTPPort,
46 | MinTCPPort: minTCPPort,
47 | MaxTCPPort: maxTCPPort,
48 | MinUDPPort: minUDPPort,
49 | MaxUDPPort: maxUDPPort,
50 | }, store, log)
51 |
52 | assert.NotNil(t, controller)
53 | }
54 |
55 | func TestController_NewMeshControllerWithSMI(t *testing.T) {
56 | store := &storeMock{}
57 | clientMock := k8s.NewClientMock("mock.yaml")
58 |
59 | log := logrus.New()
60 | log.SetOutput(os.Stdout)
61 | log.SetLevel(logrus.DebugLevel)
62 |
63 | // Create a new controller with base HTTP mode, in SMI mode.
64 | controller := NewMeshController(clientMock, Config{
65 | ACLEnabled: true,
66 | DefaultMode: "http",
67 | Namespace: traefikMeshNamespace,
68 | IgnoreNamespaces: []string{},
69 | MinHTTPPort: minHTTPPort,
70 | MaxHTTPPort: maxHTTPPort,
71 | MinTCPPort: minTCPPort,
72 | MaxTCPPort: maxTCPPort,
73 | MinUDPPort: minUDPPort,
74 | MaxUDPPort: maxUDPPort,
75 | }, store, log)
76 |
77 | assert.NotNil(t, controller)
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/controller/handler.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "github.com/sirupsen/logrus"
5 | corev1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | "k8s.io/client-go/tools/cache"
8 | "k8s.io/client-go/util/workqueue"
9 | )
10 |
11 | type enqueueWorkHandler struct {
12 | logger logrus.FieldLogger
13 | workQueue workqueue.RateLimitingInterface
14 | }
15 |
16 | // OnAdd is called when an object is added to the informers cache.
17 | func (h *enqueueWorkHandler) OnAdd(obj interface{}) {
18 | h.enqueueWork(obj)
19 | }
20 |
21 | // OnUpdate is called when an object is updated in the informers cache.
22 | func (h *enqueueWorkHandler) OnUpdate(oldObj interface{}, newObj interface{}) {
23 | oldObjMeta, okOld := oldObj.(metav1.Object)
24 | newObjMeta, okNew := newObj.(metav1.Object)
25 |
26 | // This is a resync event, no extra work is needed.
27 | if okOld && okNew && oldObjMeta.GetResourceVersion() == newObjMeta.GetResourceVersion() {
28 | return
29 | }
30 |
31 | h.enqueueWork(newObj)
32 | }
33 |
34 | // OnDelete is called when an object is removed from the informers cache.
35 | func (h *enqueueWorkHandler) OnDelete(obj interface{}) {
36 | h.enqueueWork(obj)
37 | }
38 |
39 | func (h *enqueueWorkHandler) enqueueWork(obj interface{}) {
40 | if _, isService := obj.(*corev1.Service); !isService {
41 | h.workQueue.Add(configRefreshKey)
42 | return
43 | }
44 |
45 | key, err := cache.MetaNamespaceKeyFunc(obj)
46 | if err != nil {
47 | h.logger.Errorf("Unable to create a work key for resource %#v", obj)
48 | return
49 | }
50 |
51 | h.workQueue.Add(key)
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/controller/testdata/getmeshnodeconfiguration_empty.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/controller/testdata/getmeshnodeconfiguration_empty.yaml
--------------------------------------------------------------------------------
/pkg/controller/testdata/getmeshnodeconfiguration_simple.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "127.0.0.1"
14 |
--------------------------------------------------------------------------------
/pkg/controller/testdata/getmeshnodes_empty.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/controller/testdata/getmeshnodes_empty.yaml
--------------------------------------------------------------------------------
/pkg/controller/testdata/getmeshnodes_one_mesh_pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "10.4.3.2"
14 |
--------------------------------------------------------------------------------
/pkg/controller/testdata/getmeshnodes_one_nonready_mesh_pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: mesh-pod-1
5 | namespace: foo
6 | labels:
7 | component: maesh-mesh
8 | spec:
9 | containers:
10 | - name: example
11 | image: busybox
12 | status:
13 | podIP: "10.4.19.1"
14 | containerStatuses:
15 | - name: example
16 | ready: false
17 |
--------------------------------------------------------------------------------
/pkg/controller/testdata/mock.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: foo
5 | ---
6 | apiVersion: v1
7 | kind: Service
8 | metadata:
9 | name: test
10 | namespace: foo
11 | spec:
12 | clusterIP: 10.1.0.1
13 | selector:
14 | app: test
15 | ports:
16 | - protocol: TCP
17 | port: 80
18 | targetPort: 80
19 | ---
20 | apiVersion: v1
21 | kind: Endpoints
22 | metadata:
23 | name: test
24 | namespace: foo
25 | subsets:
26 | - addresses:
27 | - ip: 10.0.0.1
28 | ports:
29 | - port: 80
30 | - addresses:
31 | - ip: 10.0.0.2
32 | ports:
33 | - port: 80
34 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_coredns_using_label.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: rke2-coredns-rke2-coredns
5 | namespace: kube-system
6 | labels:
7 | kubernetes.io/name: CoreDNS
8 | spec:
9 | template:
10 | spec:
11 | containers:
12 | - name: coredns
13 | image: image-registry.dkr.ecr.eu-west-1.amazonaws.com/eks/coredns:v1.8.4
14 | - name: titi
15 | image: titi/toto:latest
16 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_kubedns.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: titi
11 | image: titi/toto:latest
12 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_no_provider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: notaprovider
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: titi
11 | image: titi/toto:latest
12 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_supported_min_version_suffix.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: image-registry.dkr.ecr.eu-west-1.amazonaws.com/eks/coredns:v1.3.0-eksbuild.1
12 | - name: titi
13 | image: titi/toto:latest
14 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_supported_version.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: image-registry.canonical.com:5000/cdk/coredns/coredns-amd64:1.6.9
12 | - name: titi
13 | image: titi/toto:latest
14 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_supported_version_suffix.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: image-registry.dkr.ecr.eu-west-1.amazonaws.com/eks/coredns:v1.6.6-eksbuild.1
12 | - name: titi
13 | image: titi/toto:latest
14 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/checkdnsprovider_unsupported_version.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns-amd64:0.4.2
12 | - name: titi
13 | image: titi/toto:latest
14 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_17.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.7.0
12 | volumes:
13 | - configMap:
14 | name: "other-cfgmap"
15 | - configMap:
16 | name: "coredns"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: other-cfgmap
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_17_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.7.0
12 | volumes:
13 | - configMap:
14 | name: "other-cfgmap"
15 | - configMap:
16 | name: "coredns"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: other-cfgmap
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 | #### Begin Maesh Block
50 | maesh:53 {
51 | errors
52 | rewrite continue {
53 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
54 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
55 | }
56 | kubernetes titi in-addr.arpa ip6.arpa {
57 | pods insecure
58 | upstream
59 | fallthrough in-addr.arpa ip6.arpa
60 | }
61 | forward . /etc/resolv.conf
62 | cache 30
63 | loop
64 | reload
65 | loadbalance
66 | }
67 | #### End Maesh Block
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_17_custom_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.7.0
12 | volumes:
13 | - configMap:
14 | name: "coredns"
15 | - configMap:
16 | name: "coredns-custom"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: coredns-custom
22 | namespace: kube-system
23 | data:
24 | maesh.server: |
25 | #### Begin Maesh Block
26 | maesh:53 {
27 | errors
28 | rewrite continue {
29 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
30 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
31 | }
32 | kubernetes titi in-addr.arpa ip6.arpa {
33 | pods insecure
34 | upstream
35 | fallthrough in-addr.arpa ip6.arpa
36 | }
37 | forward . /etc/resolv.conf
38 | cache 30
39 | loop
40 | reload
41 | loadbalance
42 | }
43 | #### End Maesh Block
44 | ---
45 | apiVersion: v1
46 | kind: ConfigMap
47 | metadata:
48 | name: coredns
49 | namespace: kube-system
50 | data:
51 | Corefile: |
52 | .:53 {
53 | errors
54 | health {
55 | lameduck 5s
56 | }
57 | ready
58 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
59 | pods insecure
60 | fallthrough in-addr.arpa ip6.arpa
61 | ttl 30
62 | }
63 | prometheus :9153
64 | forward . /etc/resolv.conf
65 | cache 30
66 | loop
67 | reload
68 | loadbalance
69 | }
70 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_17_suffix.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: image-registry.dkr.ecr.eu-west-1.amazonaws.com/eks/coredns:v1.7.0-eksbuild.1
12 | volumes:
13 | - configMap:
14 | name: "other-cfgmap"
15 | - configMap:
16 | name: "coredns"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: other-cfgmap
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.6.0
12 | volumes:
13 | - configMap:
14 | name: "other-cfgmap"
15 | - configMap:
16 | name: "coredns"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: other-cfgmap
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 |
50 | #### Begin Maesh Block
51 | maesh:53 {
52 | errors
53 | rewrite continue {
54 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
55 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
56 | }
57 | kubernetes titi in-addr.arpa ip6.arpa {
58 | pods insecure
59 | upstream
60 | fallthrough in-addr.arpa ip6.arpa
61 | }
62 | forward . /etc/resolv.conf
63 | cache 30
64 | loop
65 | reload
66 | loadbalance
67 | }
68 | #### End Maesh Block
69 |
70 | #### Begin Traefik Mesh Block
71 | traefik.mesh:53 {
72 | errors
73 | rewrite continue {
74 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.traefik.mesh toto-{1}-6d61657368-{2}.toto.svc.titi
75 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.traefik.mesh
76 | }
77 | kubernetes titi in-addr.arpa ip6.arpa {
78 | pods insecure
79 | upstream
80 | fallthrough in-addr.arpa ip6.arpa
81 | }
82 | forward . /etc/resolv.conf
83 | cache 30
84 | loop
85 | reload
86 | loadbalance
87 | }
88 | #### End Traefik Mesh Block
89 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_custom_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.6.0
12 | volumes:
13 | - configMap:
14 | name: "coredns"
15 | - configMap:
16 | name: "coredns-custom"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: coredns-custom
22 | namespace: kube-system
23 | data:
24 | maesh.server: |
25 | #### Begin Maesh Block
26 | maesh:53 {
27 | errors
28 | rewrite continue {
29 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
30 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
31 | }
32 | kubernetes titi in-addr.arpa ip6.arpa {
33 | pods insecure
34 | upstream
35 | fallthrough in-addr.arpa ip6.arpa
36 | }
37 | forward . /etc/resolv.conf
38 | cache 30
39 | loop
40 | reload
41 | loadbalance
42 | }
43 | #### End Maesh Block
44 |
45 | traefik.mesh.server: |
46 | #### Begin Traefik Mesh Block
47 | traefik.mesh:53 {
48 | errors
49 | rewrite continue {
50 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.traefik.mesh toto-{1}-6d61657368-{2}.toto.svc.titi
51 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.traefik.mesh
52 | }
53 | kubernetes titi in-addr.arpa ip6.arpa {
54 | pods insecure
55 | upstream
56 | fallthrough in-addr.arpa ip6.arpa
57 | }
58 | forward . /etc/resolv.conf
59 | cache 30
60 | loop
61 | reload
62 | loadbalance
63 | }
64 | #### End Traefik Mesh Block
65 |
66 | ---
67 | apiVersion: v1
68 | kind: ConfigMap
69 | metadata:
70 | name: coredns
71 | namespace: kube-system
72 | data:
73 | Corefile: |
74 | .:53 {
75 | errors
76 | health {
77 | lameduck 5s
78 | }
79 | ready
80 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
81 | pods insecure
82 | fallthrough in-addr.arpa ip6.arpa
83 | ttl 30
84 | }
85 | prometheus :9153
86 | forward . /etc/resolv.conf
87 | cache 30
88 | loop
89 | reload
90 | loadbalance
91 | }
92 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_custom_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.6.0
12 | volumes:
13 | - configMap:
14 | name: "coredns"
15 | - configMap:
16 | name: "coredns-custom"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: coredns-custom
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_missing_configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_missing_deployment.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/dns/testdata/configurecoredns_missing_deployment.yaml
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurecoredns_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: coredns
11 | image: coredns:1.6.0
12 | volumes:
13 | - configMap:
14 | name: "other-cfgmap"
15 | - configMap:
16 | name: "coredns"
17 | ---
18 | apiVersion: v1
19 | kind: ConfigMap
20 | metadata:
21 | name: other-cfgmap
22 | namespace: kube-system
23 | ---
24 | apiVersion: v1
25 | kind: ConfigMap
26 | metadata:
27 | name: coredns
28 | namespace: kube-system
29 | data:
30 | Corefile: |
31 | .:53 {
32 | errors
33 | health {
34 | lameduck 5s
35 | }
36 | ready
37 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
38 | pods insecure
39 | fallthrough in-addr.arpa ip6.arpa
40 | ttl 30
41 | }
42 | prometheus :9153
43 | forward . /etc/resolv.conf
44 | cache 30
45 | loop
46 | reload
47 | loadbalance
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurekubedns_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "kube-dns"
12 | ---
13 | apiVersion: v1
14 | kind: ConfigMap
15 | metadata:
16 | name: kube-dns
17 | namespace: kube-system
18 | ---
19 | apiVersion: v1
20 | kind: Service
21 | metadata:
22 | name: coredns
23 | namespace: traefik-mesh
24 | spec:
25 | clusterIP: "1.2.3.4"
26 | ---
27 | apiVersion: apps/v1
28 | kind: Deployment
29 | metadata:
30 | name: coredns
31 | namespace: traefik-mesh
32 | spec:
33 | template:
34 | spec:
35 | containers:
36 | - name: coredns
37 | image: coredns:1.6.0
38 | volumes:
39 | - configMap:
40 | name: "other-cfgmap"
41 | - configMap:
42 | name: "coredns"
43 | ---
44 | apiVersion: v1
45 | kind: ConfigMap
46 | metadata:
47 | name: other-cfgmap
48 | namespace: traefik-mesh
49 | ---
50 | apiVersion: v1
51 | kind: ConfigMap
52 | metadata:
53 | name: coredns
54 | namespace: traefik-mesh
55 | data:
56 | Corefile: |
57 | .:53 {
58 | errors
59 | health {
60 | lameduck 5s
61 | }
62 | ready
63 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
64 | pods insecure
65 | fallthrough in-addr.arpa ip6.arpa
66 | ttl 30
67 | }
68 | prometheus :9153
69 | forward . /etc/resolv.conf
70 | cache 30
71 | loop
72 | reload
73 | loadbalance
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurekubedns_missing_deployment.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/traefik/mesh/5ee481aca18c81bd710a8c15cbdf75d3d599bea1/pkg/dns/testdata/configurekubedns_missing_deployment.yaml
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurekubedns_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "kube-dns"
12 | ---
13 | apiVersion: v1
14 | kind: ConfigMap
15 | metadata:
16 | name: kube-dns
17 | namespace: kube-system
18 | ---
19 | apiVersion: v1
20 | kind: Service
21 | metadata:
22 | name: coredns
23 | namespace: traefik-mesh
24 | spec:
25 | clusterIP: "1.2.3.4"
26 | ---
27 | apiVersion: apps/v1
28 | kind: Deployment
29 | metadata:
30 | name: coredns
31 | namespace: traefik-mesh
32 | spec:
33 | template:
34 | spec:
35 | containers:
36 | - name: coredns
37 | image: coredns:1.6.0
38 | volumes:
39 | - configMap:
40 | name: "other-cfgmap"
41 | - configMap:
42 | name: "coredns"
43 | ---
44 | apiVersion: v1
45 | kind: ConfigMap
46 | metadata:
47 | name: other-cfgmap
48 | namespace: traefik-mesh
49 | ---
50 | apiVersion: v1
51 | kind: ConfigMap
52 | metadata:
53 | name: coredns
54 | namespace: traefik-mesh
55 | data:
56 | Corefile: |
57 | .:53 {
58 | errors
59 | health {
60 | lameduck 5s
61 | }
62 | ready
63 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
64 | pods insecure
65 | fallthrough in-addr.arpa ip6.arpa
66 | ttl 30
67 | }
68 | prometheus :9153
69 | forward . /etc/resolv.conf
70 | cache 30
71 | loop
72 | reload
73 | loadbalance
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/configurekubedns_optional_configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "kube-dns"
12 | optional: true
13 | ---
14 | apiVersion: v1
15 | kind: Service
16 | metadata:
17 | name: coredns
18 | namespace: traefik-mesh
19 | spec:
20 | clusterIP: "1.2.3.4"
21 | ---
22 | apiVersion: apps/v1
23 | kind: Deployment
24 | metadata:
25 | name: coredns
26 | namespace: traefik-mesh
27 | spec:
28 | template:
29 | spec:
30 | containers:
31 | - name: coredns
32 | image: coredns:1.6.0
33 | volumes:
34 | - configMap:
35 | name: "other-cfgmap"
36 | - configMap:
37 | name: "coredns"
38 | ---
39 | apiVersion: v1
40 | kind: ConfigMap
41 | metadata:
42 | name: other-cfgmap
43 | namespace: traefik-mesh
44 | ---
45 | apiVersion: v1
46 | kind: ConfigMap
47 | metadata:
48 | name: coredns
49 | namespace: traefik-mesh
50 | data:
51 | Corefile: |
52 | .:53 {
53 | errors
54 | health {
55 | lameduck 5s
56 | }
57 | ready
58 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
59 | pods insecure
60 | fallthrough in-addr.arpa ip6.arpa
61 | ttl 30
62 | }
63 | prometheus :9153
64 | forward . /etc/resolv.conf
65 | cache 30
66 | loop
67 | reload
68 | loadbalance
69 | }
70 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorecoredns_custom_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "coredns-custom"
12 | - configMap:
13 | name: "coredns"
14 | ---
15 | apiVersion: v1
16 | kind: ConfigMap
17 | metadata:
18 | name: coredns-custom
19 | namespace: kube-system
20 | data:
21 | test.server: must be present
22 | ---
23 | apiVersion: v1
24 | kind: ConfigMap
25 | metadata:
26 | name: coredns
27 | namespace: kube-system
28 | data:
29 | Corefile: |
30 | .:53 {
31 | errors
32 | health {
33 | lameduck 5s
34 | }
35 | ready
36 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
37 | pods insecure
38 | fallthrough in-addr.arpa ip6.arpa
39 | ttl 30
40 | }
41 | prometheus :9153
42 | forward . /etc/resolv.conf
43 | cache 30
44 | loop
45 | reload
46 | loadbalance
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorecoredns_custom_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "coredns-custom"
12 | - configMap:
13 | name: "coredns"
14 | ---
15 | apiVersion: v1
16 | kind: ConfigMap
17 | metadata:
18 | name: coredns-custom
19 | namespace: kube-system
20 | data:
21 | test.server: must be present
22 | maesh.server: |
23 | #### Begin Maesh Block
24 | maesh:53 {
25 | errors
26 | rewrite continue {
27 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
28 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
29 | }
30 | kubernetes titi in-addr.arpa ip6.arpa {
31 | pods insecure
32 | upstream
33 | fallthrough in-addr.arpa ip6.arpa
34 | }
35 | forward . /etc/resolv.conf
36 | cache 30
37 | loop
38 | reload
39 | loadbalance
40 | }
41 | #### End Maesh Block
42 | ---
43 | apiVersion: v1
44 | kind: ConfigMap
45 | metadata:
46 | name: coredns
47 | namespace: kube-system
48 | data:
49 | Corefile: |
50 | .:53 {
51 | errors
52 | health {
53 | lameduck 5s
54 | }
55 | ready
56 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
57 | pods insecure
58 | fallthrough in-addr.arpa ip6.arpa
59 | ttl 30
60 | }
61 | prometheus :9153
62 | forward . /etc/resolv.conf
63 | cache 30
64 | loop
65 | reload
66 | loadbalance
67 | }
68 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorecoredns_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "other-cfgmap"
12 | - configMap:
13 | name: "coredns"
14 | ---
15 | apiVersion: v1
16 | kind: ConfigMap
17 | metadata:
18 | name: other-cfgmap
19 | namespace: kube-system
20 | ---
21 | apiVersion: v1
22 | kind: ConfigMap
23 | metadata:
24 | name: coredns
25 | namespace: kube-system
26 | data:
27 | Corefile: |
28 | .:53 {
29 | errors
30 | health {
31 | lameduck 5s
32 | }
33 | ready
34 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
35 | pods insecure
36 | fallthrough in-addr.arpa ip6.arpa
37 | ttl 30
38 | }
39 | prometheus :9153
40 | forward . /etc/resolv.conf
41 | cache 30
42 | loop
43 | reload
44 | loadbalance
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorecoredns_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: coredns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "other-cfgmap"
12 | - configMap:
13 | name: "coredns"
14 | ---
15 | apiVersion: v1
16 | kind: ConfigMap
17 | metadata:
18 | name: other-cfgmap
19 | namespace: kube-system
20 | ---
21 | apiVersion: v1
22 | kind: ConfigMap
23 | metadata:
24 | name: coredns
25 | namespace: kube-system
26 | data:
27 | Corefile: |
28 | .:53 {
29 | errors
30 | health {
31 | lameduck 5s
32 | }
33 | ready
34 | kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
35 | pods insecure
36 | fallthrough in-addr.arpa ip6.arpa
37 | ttl 30
38 | }
39 | prometheus :9153
40 | forward . /etc/resolv.conf
41 | cache 30
42 | loop
43 | reload
44 | loadbalance
45 | }
46 |
47 | #### Begin Maesh Block
48 | maesh:53 {
49 | errors
50 | rewrite continue {
51 | name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi
52 | answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.toto\.svc\.titi {1}.{2}.maesh
53 | }
54 | kubernetes titi in-addr.arpa ip6.arpa {
55 | pods insecure
56 | upstream
57 | fallthrough in-addr.arpa ip6.arpa
58 | }
59 | forward . /etc/resolv.conf
60 | cache 30
61 | loop
62 | reload
63 | loadbalance
64 | }
65 | #### End Maesh Block
66 | # This is test data that must be present
67 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorekubedns_already_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "kube-dns"
12 | ---
13 | apiVersion: v1
14 | kind: ConfigMap
15 | metadata:
16 | name: kube-dns
17 | namespace: kube-system
18 | data:
19 | stubDomains: |
20 | {"maesh":["1.2.3.4"], "traefik.mesh":["1.2.3.4"], "test":["5.6.7.8"]}
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: coredns
26 | namespace: traefik-mesh
27 | spec:
28 | clusterIP: "1.2.3.4"
29 |
--------------------------------------------------------------------------------
/pkg/dns/testdata/restorekubedns_not_patched.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: kube-dns
5 | namespace: kube-system
6 | spec:
7 | template:
8 | spec:
9 | volumes:
10 | - configMap:
11 | name: "kube-dns"
12 | ---
13 | apiVersion: v1
14 | kind: ConfigMap
15 | metadata:
16 | name: kube-dns
17 | namespace: kube-system
18 | ---
19 | apiVersion: v1
20 | kind: Service
21 | metadata:
22 | name: coredns
23 | namespace: traefik-mesh
24 | spec:
25 | clusterIP: "1.2.3.4"
26 |
--------------------------------------------------------------------------------
/pkg/k8s/constants.go:
--------------------------------------------------------------------------------
1 | package k8s
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | const (
8 | // ResyncPeriod set the resync period.
9 | ResyncPeriod = 5 * time.Minute
10 |
11 | // TrafficSplitObjectKind is the name of an SMI object of kind TrafficSplit.
12 | TrafficSplitObjectKind = "TrafficSplit"
13 | // TrafficTargetObjectKind is the name of an SMI object of kind TrafficTarget.
14 | TrafficTargetObjectKind = "TrafficTarget"
15 | // HTTPRouteGroupObjectKind is the name of an SMI object of kind HTTPRouteGroup.
16 | HTTPRouteGroupObjectKind = "HTTPRouteGroup"
17 | // TCPRouteObjectKind is the name of an SMI object of kind TCPRoute.
18 | TCPRouteObjectKind = "TCPRoute"
19 |
20 | // CoreObjectKinds is a filter for objects to process by the core client.
21 | CoreObjectKinds = "Deployment|Endpoints|Service|Ingress|Secret|Namespace|Pod|ConfigMap"
22 | // AccessObjectKinds is a filter for objects to process by the access client.
23 | AccessObjectKinds = TrafficTargetObjectKind
24 | // SpecsObjectKinds is a filter for objects to process by the specs client.
25 | SpecsObjectKinds = HTTPRouteGroupObjectKind + "|" + TCPRouteObjectKind
26 | // SplitObjectKinds is a filter for objects to process by the split client.
27 | SplitObjectKinds = TrafficSplitObjectKind
28 | )
29 |
--------------------------------------------------------------------------------
/pkg/k8s/smi.go:
--------------------------------------------------------------------------------
1 | package k8s
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "strings"
7 |
8 | access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha2"
9 | specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
10 | split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha3"
11 | "k8s.io/apimachinery/pkg/runtime/schema"
12 | "k8s.io/client-go/kubernetes"
13 | )
14 |
15 | // CheckSMIVersion checks if the SMI CRDs versions installed match the supported versions.
16 | func CheckSMIVersion(client kubernetes.Interface, aclEnabled bool) error {
17 | serverGroups, err := client.Discovery().ServerGroups()
18 | if err != nil {
19 | return fmt.Errorf("unable to list kubernetes server groups: %w", err)
20 | }
21 |
22 | requiredGroups := []schema.GroupVersion{
23 | split.SchemeGroupVersion,
24 | specs.SchemeGroupVersion,
25 | }
26 |
27 | if aclEnabled {
28 | requiredGroups = append(requiredGroups, access.SchemeGroupVersion)
29 | }
30 |
31 | var errs []string
32 |
33 | for _, requiredGroup := range requiredGroups {
34 | var version string
35 |
36 | for _, group := range serverGroups.Groups {
37 | if requiredGroup.Group == group.Name {
38 | version = group.PreferredVersion.Version
39 |
40 | break
41 | }
42 | }
43 |
44 | if version == "" {
45 | errs = append(errs, fmt.Sprintf("unable to find group %q version %q", requiredGroup.Group, requiredGroup.Version))
46 | } else if version != requiredGroup.Version {
47 | errs = append(errs, fmt.Sprintf("unable to find group %q version %q, got %q", requiredGroup.Group, requiredGroup.Version, version))
48 | }
49 | }
50 |
51 | if len(errs) > 0 {
52 | return errors.New(strings.Join(errs, "; "))
53 | }
54 |
55 | return nil
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/k8s/testdata/mock.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: test
5 | spec:
6 | selector:
7 | app: test
8 | ports:
9 | - protocol: TCP
10 | port: 80
11 | targetPort: 8080
12 |
--------------------------------------------------------------------------------
/pkg/provider/key.go:
--------------------------------------------------------------------------------
1 | package provider
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/traefik/mesh/pkg/topology"
7 | )
8 |
9 | const (
10 | blockAllMiddlewareKey = "block-all-middleware"
11 | blockAllServiceKey = "block-all-service"
12 | )
13 |
14 | func getMiddlewareKey(svc *topology.Service, name string) string {
15 | return fmt.Sprintf("%s-%s-%s", svc.Namespace, svc.Name, name)
16 | }
17 |
18 | func getServiceRouterKeyFromService(svc *topology.Service, port int32) string {
19 | return fmt.Sprintf("%s-%s-%d", svc.Namespace, svc.Name, port)
20 | }
21 |
22 | func getWhitelistMiddlewareKeyFromTrafficTargetDirect(tt *topology.ServiceTrafficTarget) string {
23 | return fmt.Sprintf("%s-%s-%s-whitelist-traffic-target-direct", tt.Service.Namespace, tt.Service.Name, tt.Name)
24 | }
25 |
26 | func getWhitelistMiddlewareKeyFromTrafficTargetIndirect(tt *topology.ServiceTrafficTarget) string {
27 | return fmt.Sprintf("%s-%s-%s-whitelist-traffic-target-indirect", tt.Service.Namespace, tt.Service.Name, tt.Name)
28 | }
29 |
30 | func getWhitelistMiddlewareKeyFromTrafficSplitDirect(ts *topology.TrafficSplit) string {
31 | return fmt.Sprintf("%s-%s-%s-whitelist-traffic-split-direct", ts.Service.Namespace, ts.Service.Name, ts.Name)
32 | }
33 |
34 | func getWhitelistMiddlewareKeyFromTrafficSplitIndirect(ts *topology.TrafficSplit) string {
35 | return fmt.Sprintf("%s-%s-%s-whitelist-traffic-split-indirect", ts.Service.Namespace, ts.Service.Name, ts.Name)
36 | }
37 |
38 | func getServiceKeyFromTrafficTarget(tt *topology.ServiceTrafficTarget, port int32) string {
39 | return fmt.Sprintf("%s-%s-%s-%d-traffic-target", tt.Service.Namespace, tt.Service.Name, tt.Name, port)
40 | }
41 |
42 | func getRouterKeyFromTrafficTargetDirect(tt *topology.ServiceTrafficTarget, port int32) string {
43 | return fmt.Sprintf("%s-%s-%s-%d-traffic-target-direct", tt.Service.Namespace, tt.Service.Name, tt.Name, port)
44 | }
45 |
46 | func getRouterKeyFromTrafficTargetIndirect(tt *topology.ServiceTrafficTarget, port int32) string {
47 | return fmt.Sprintf("%s-%s-%s-%d-traffic-target-indirect", tt.Service.Namespace, tt.Service.Name, tt.Name, port)
48 | }
49 |
50 | func getServiceKeyFromTrafficSplit(ts *topology.TrafficSplit, port int32) string {
51 | return fmt.Sprintf("%s-%s-%s-%d-traffic-split", ts.Service.Namespace, ts.Service.Name, ts.Name, port)
52 | }
53 |
54 | func getRouterKeyFromTrafficSplitDirect(ts *topology.TrafficSplit, port int32) string {
55 | return fmt.Sprintf("%s-%s-%s-%d-traffic-split-direct", ts.Service.Namespace, ts.Service.Name, ts.Name, port)
56 | }
57 |
58 | func getRouterKeyFromTrafficSplitIndirect(ts *topology.TrafficSplit, port int32) string {
59 | return fmt.Sprintf("%s-%s-%s-%d-traffic-split-indirect", ts.Service.Namespace, ts.Service.Name, ts.Name, port)
60 | }
61 |
62 | func getServiceKeyFromTrafficSplitBackend(ts *topology.TrafficSplit, port int32, backend topology.TrafficSplitBackend) string {
63 | return fmt.Sprintf("%s-%s-%s-%d-%s-traffic-split-backend", ts.Service.Namespace, ts.Service.Name, ts.Name, port, backend.Service.Name)
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-http-basic-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "my-ns-svc-a-8080": {
5 | "entryPoints": [
6 | "http-10000"
7 | ],
8 | "service": "my-ns-svc-a-8080",
9 | "rule": "Host(`svc-a.my-ns.traefik.mesh`) || Host(`svc-a.my-ns.maesh`) || Host(`10.10.14.1`)",
10 | "priority": 1002
11 | },
12 | "my-ns-svc-a-8081": {
13 | "entryPoints": [
14 | "http-10001"
15 | ],
16 | "service": "my-ns-svc-a-8081",
17 | "rule": "Host(`svc-a.my-ns.traefik.mesh`) || Host(`svc-a.my-ns.maesh`) || Host(`10.10.14.1`)",
18 | "priority": 1002
19 | },
20 | "readiness": {
21 | "entryPoints": [
22 | "readiness"
23 | ],
24 | "service": "readiness",
25 | "rule": "Path(`/ping`)"
26 | }
27 | },
28 | "services": {
29 | "block-all-service": {
30 | "loadBalancer": {
31 | "passHostHeader": false
32 | }
33 | },
34 | "my-ns-svc-a-8080": {
35 | "loadBalancer": {
36 | "servers": [
37 | {
38 | "url": "http://10.10.2.1:8080"
39 | },
40 | {
41 | "url": "http://10.10.2.2:8080"
42 | }
43 | ],
44 | "passHostHeader": true
45 | }
46 | },
47 | "my-ns-svc-a-8081": {
48 | "loadBalancer": {
49 | "servers": [
50 | {
51 | "url": "http://10.10.2.1:8080"
52 | },
53 | {
54 | "url": "http://10.10.2.2:8081"
55 | }
56 | ],
57 | "passHostHeader": true
58 | }
59 | },
60 | "readiness": {
61 | "loadBalancer": {
62 | "servers": [
63 | {
64 | "url": "http://127.0.0.1:8080"
65 | }
66 | ],
67 | "passHostHeader": true
68 | }
69 | }
70 | },
71 | "middlewares": {
72 | "block-all-middleware": {
73 | "ipWhiteList": {
74 | "sourceRange": [
75 | "255.255.255.255"
76 | ]
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-http-basic-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "TCP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | },
15 | {
16 | "name": "port-8081",
17 | "protocol": "TCP",
18 | "port": 8081,
19 | "targetPort": "web"
20 | }
21 | ],
22 | "clusterIp": "10.10.14.1",
23 | "pods": [
24 | "pod-a1@my-ns",
25 | "pod-a2@my-ns"
26 | ]
27 | }
28 | },
29 | "pods": {
30 | "pod-a1@my-ns": {
31 | "name": "pod-a1",
32 | "namespace": "my-ns",
33 | "serviceAccount": "default",
34 | "ip": "10.10.2.1",
35 | "containerPorts": [
36 | {
37 | "name": "web",
38 | "protocol": "TCP",
39 | "containerPort": 8080
40 | }
41 | ]
42 | },
43 | "pod-a2@my-ns": {
44 | "name": "pod-a2",
45 | "namespace": "my-ns",
46 | "serviceAccount": "default",
47 | "ip": "10.10.2.2",
48 | "containerPorts": [
49 | {
50 | "name": "web",
51 | "protocol": "TCP",
52 | "containerPort": 8081
53 | }
54 | ]
55 | }
56 | },
57 | "serviceTrafficTargets": {},
58 | "trafficSplits": {}
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-http-traffic-split-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "TCP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | }
15 | ],
16 | "clusterIp": "10.10.14.1",
17 | "pods": [],
18 | "trafficSplits": ["split@my-ns"]
19 | },
20 | "svc-b@my-ns": {
21 | "name": "svc-b",
22 | "namespace": "my-ns",
23 | "selector": {},
24 | "annotations": {},
25 | "ports": [
26 | {
27 | "name": "port-8080",
28 | "protocol": "TCP",
29 | "port": 8080,
30 | "targetPort": 80
31 | }
32 | ],
33 | "clusterIp": "10.10.15.1",
34 | "pods": [
35 | "pod-b@my-ns"
36 | ],
37 | "backendOf": ["split@my-ns"]
38 | },
39 | "svc-c@my-ns": {
40 | "name": "svc-c",
41 | "namespace": "my-ns",
42 | "selector": {},
43 | "annotations": {},
44 | "ports": [
45 | {
46 | "name": "port-8080",
47 | "protocol": "TCP",
48 | "port": 8080,
49 | "targetPort": 80
50 | }
51 | ],
52 | "clusterIp": "10.10.16.1",
53 | "pods": [
54 | "pod-c@my-ns"
55 | ],
56 | "backendOf": ["split@my-ns"]
57 | }
58 | },
59 | "pods": {
60 | "pod-b@my-ns": {
61 | "name": "pod-b",
62 | "namespace": "my-ns",
63 | "serviceAccount": "default",
64 | "ip": "10.10.2.1"
65 | },
66 | "pod-c@my-ns": {
67 | "name": "pod-c",
68 | "namespace": "my-ns",
69 | "serviceAccount": "default",
70 | "ip": "10.10.3.1"
71 | }
72 | },
73 | "trafficSplits": {
74 | "split@my-ns": {
75 | "name": "split",
76 | "namespace": "my-ns",
77 | "service": "svc-a@my-ns",
78 | "backends": [
79 | {
80 | "weight": 80,
81 | "service": "svc-b@my-ns"
82 | },
83 | {
84 | "weight": 20,
85 | "service": "svc-c@my-ns"
86 | }
87 | ]
88 | }
89 | },
90 | "serviceTrafficTargets": {}
91 | }
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-tcp-basic-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "readiness": {
5 | "entryPoints": [
6 | "readiness"
7 | ],
8 | "service": "readiness",
9 | "rule": "Path(`/ping`)"
10 | }
11 | },
12 | "services": {
13 | "block-all-service": {
14 | "loadBalancer": {
15 | "passHostHeader": false
16 | }
17 | },
18 | "readiness": {
19 | "loadBalancer": {
20 | "servers": [
21 | {
22 | "url": "http://127.0.0.1:8080"
23 | }
24 | ],
25 | "passHostHeader": true
26 | }
27 | }
28 | },
29 | "middlewares": {
30 | "block-all-middleware": {
31 | "ipWhiteList": {
32 | "sourceRange": [
33 | "255.255.255.255"
34 | ]
35 | }
36 | }
37 | }
38 | },
39 | "tcp": {
40 | "routers": {
41 | "my-ns-svc-a-8080": {
42 | "entryPoints": [
43 | "tcp-5000"
44 | ],
45 | "service": "my-ns-svc-a-8080",
46 | "rule": "HostSNI(`*`)"
47 | },
48 | "my-ns-svc-a-8081": {
49 | "entryPoints": [
50 | "tcp-5001"
51 | ],
52 | "service": "my-ns-svc-a-8081",
53 | "rule": "HostSNI(`*`)"
54 | }
55 | },
56 | "services": {
57 | "my-ns-svc-a-8080": {
58 | "loadBalancer": {
59 | "servers": [
60 | {
61 | "address": "10.10.2.1:8080"
62 | },
63 | {
64 | "address": "10.10.2.2:8080"
65 | }
66 | ]
67 | }
68 | },
69 | "my-ns-svc-a-8081": {
70 | "loadBalancer": {
71 | "servers": [
72 | {
73 | "address": "10.10.2.1:8080"
74 | },
75 | {
76 | "address": "10.10.2.2:8081"
77 | }
78 | ]
79 | }
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-tcp-basic-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "TCP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | },
15 | {
16 | "name": "port-8081",
17 | "protocol": "TCP",
18 | "port": 8081,
19 | "targetPort": "web"
20 | }
21 | ],
22 | "clusterIp": "10.10.14.1",
23 | "pods": [
24 | "pod-a1@my-ns",
25 | "pod-a2@my-ns"
26 | ]
27 | }
28 | },
29 | "pods": {
30 | "pod-a1@my-ns": {
31 | "name": "pod-a1",
32 | "namespace": "my-ns",
33 | "serviceAccount": "default",
34 | "ip": "10.10.2.1",
35 | "containerPorts": [
36 | {
37 | "name": "web",
38 | "protocol": "TCP",
39 | "containerPort": 8080
40 | }
41 | ]
42 | },
43 | "pod-a2@my-ns": {
44 | "name": "pod-a2",
45 | "namespace": "my-ns",
46 | "serviceAccount": "default",
47 | "ip": "10.10.2.2",
48 | "containerPorts": [
49 | {
50 | "name": "web",
51 | "protocol": "TCP",
52 | "containerPort": 8081
53 | }
54 | ]
55 | }
56 | },
57 | "serviceTrafficTargets": {},
58 | "trafficSplits": {}
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-udp-basic-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "readiness": {
5 | "entryPoints": [
6 | "readiness"
7 | ],
8 | "service": "readiness",
9 | "rule": "Path(`/ping`)"
10 | }
11 | },
12 | "services": {
13 | "block-all-service": {
14 | "loadBalancer": {
15 | "passHostHeader": false
16 | }
17 | },
18 | "readiness": {
19 | "loadBalancer": {
20 | "servers": [
21 | {
22 | "url": "http://127.0.0.1:8080"
23 | }
24 | ],
25 | "passHostHeader": true
26 | }
27 | }
28 | },
29 | "middlewares": {
30 | "block-all-middleware": {
31 | "ipWhiteList": {
32 | "sourceRange": [
33 | "255.255.255.255"
34 | ]
35 | }
36 | }
37 | }
38 | },
39 | "udp": {
40 | "routers": {
41 | "my-ns-svc-a-8080": {
42 | "entryPoints": [
43 | "udp-15000"
44 | ],
45 | "service": "my-ns-svc-a-8080"
46 | },
47 | "my-ns-svc-a-8081": {
48 | "entryPoints": [
49 | "udp-15001"
50 | ],
51 | "service": "my-ns-svc-a-8081"
52 | }
53 | },
54 | "services": {
55 | "my-ns-svc-a-8080": {
56 | "loadBalancer": {
57 | "servers": [
58 | {
59 | "address": "10.10.2.1:8080"
60 | },
61 | {
62 | "address": "10.10.2.2:8080"
63 | }
64 | ]
65 | }
66 | },
67 | "my-ns-svc-a-8081": {
68 | "loadBalancer": {
69 | "servers": [
70 | {
71 | "address": "10.10.2.1:8080"
72 | },
73 | {
74 | "address": "10.10.2.2:8081"
75 | }
76 | ]
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-disabled-udp-basic-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "UDP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | },
15 | {
16 | "name": "port-8081",
17 | "protocol": "UDP",
18 | "port": 8081,
19 | "targetPort": "ping"
20 | }
21 | ],
22 | "clusterIp": "10.10.14.1",
23 | "pods": [
24 | "pod-a1@my-ns",
25 | "pod-a2@my-ns"
26 | ]
27 | }
28 | },
29 | "pods": {
30 | "pod-a1@my-ns": {
31 | "name": "pod-a1",
32 | "namespace": "my-ns",
33 | "serviceAccount": "default",
34 | "ip": "10.10.2.1",
35 | "containerPorts": [
36 | {
37 | "name": "ping",
38 | "protocol": "UDP",
39 | "containerPort": 8080
40 | }
41 | ]
42 | },
43 | "pod-a2@my-ns": {
44 | "name": "pod-a2",
45 | "namespace": "my-ns",
46 | "serviceAccount": "default",
47 | "ip": "10.10.2.2",
48 | "containerPorts": [
49 | {
50 | "name": "ping",
51 | "protocol": "UDP",
52 | "containerPort": 8081
53 | }
54 | ]
55 | }
56 | },
57 | "serviceTrafficTargets": {},
58 | "trafficSplits": {}
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-enabled-http-basic-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "my-ns-svc-b-8080": {
5 | "entryPoints": [
6 | "http-10000"
7 | ],
8 | "middlewares": [
9 | "block-all-middleware"
10 | ],
11 | "service": "block-all-service",
12 | "rule": "Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)",
13 | "priority": 1
14 | },
15 | "my-ns-svc-b-8081": {
16 | "entryPoints": [
17 | "http-10001"
18 | ],
19 | "middlewares": [
20 | "block-all-middleware"
21 | ],
22 | "service": "block-all-service",
23 | "rule": "Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)",
24 | "priority": 1
25 | },
26 | "my-ns-svc-b-tt-8080-traffic-target-direct": {
27 | "entryPoints": [
28 | "http-10000"
29 | ],
30 | "middlewares": [
31 | "my-ns-svc-b-tt-whitelist-traffic-target-direct"
32 | ],
33 | "service": "my-ns-svc-b-tt-8080-traffic-target",
34 | "rule": "Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)",
35 | "priority": 2002
36 | },
37 | "my-ns-svc-b-tt-8081-traffic-target-direct": {
38 | "entryPoints": [
39 | "http-10001"
40 | ],
41 | "middlewares": [
42 | "my-ns-svc-b-tt-whitelist-traffic-target-direct"
43 | ],
44 | "service": "my-ns-svc-b-tt-8081-traffic-target",
45 | "rule": "Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)",
46 | "priority": 2002
47 | },
48 | "readiness": {
49 | "entryPoints": [
50 | "readiness"
51 | ],
52 | "service": "readiness",
53 | "rule": "Path(`/ping`)"
54 | }
55 | },
56 | "services": {
57 | "block-all-service": {
58 | "loadBalancer": {
59 | "passHostHeader": false
60 | }
61 | },
62 | "my-ns-svc-b-tt-8080-traffic-target": {
63 | "loadBalancer": {
64 | "servers": [
65 | {
66 | "url": "http://10.10.3.1:8080"
67 | }
68 | ],
69 | "passHostHeader": true
70 | }
71 | },
72 | "my-ns-svc-b-tt-8081-traffic-target": {
73 | "loadBalancer": {
74 | "servers": [
75 | {
76 | "url": "http://10.10.3.1:8081"
77 | }
78 | ],
79 | "passHostHeader": true
80 | }
81 | },
82 | "readiness": {
83 | "loadBalancer": {
84 | "servers": [
85 | {
86 | "url": "http://127.0.0.1:8080"
87 | }
88 | ],
89 | "passHostHeader": true
90 | }
91 | }
92 | },
93 | "middlewares": {
94 | "block-all-middleware": {
95 | "ipWhiteList": {
96 | "sourceRange": [
97 | "255.255.255.255"
98 | ]
99 | }
100 | },
101 | "my-ns-svc-b-tt-whitelist-traffic-target-direct": {
102 | "ipWhiteList": {
103 | "sourceRange": [
104 | "10.10.2.1"
105 | ]
106 | }
107 | }
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-enabled-http-basic-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b@my-ns": {
4 | "name": "svc-b",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "TCP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | },
15 | {
16 | "name": "port-8081",
17 | "protocol": "TCP",
18 | "port": 8081,
19 | "targetPort": "web"
20 | }
21 | ],
22 | "clusterIp": "10.10.14.1",
23 | "pods": [
24 | "pod-b@my-ns"
25 | ],
26 | "trafficTargets": [
27 | "svc-b@my-ns:tt@my-ns"
28 | ]
29 | }
30 | },
31 | "pods": {
32 | "pod-a@my-ns": {
33 | "name": "pod-a",
34 | "namespace": "my-ns",
35 | "serviceAccount": "client",
36 | "ip": "10.10.2.1"
37 | },
38 | "pod-b@my-ns": {
39 | "name": "pod-b",
40 | "namespace": "my-ns",
41 | "serviceAccount": "server",
42 | "ip": "10.10.3.1",
43 | "containerPorts": [
44 | {
45 | "name": "web",
46 | "protocol": "TCP",
47 | "containerPort": 8081
48 | }
49 | ]
50 | }
51 | },
52 | "serviceTrafficTargets": {
53 | "svc-b@my-ns:tt@my-ns": {
54 | "service": "svc-b@my-ns",
55 | "name": "tt",
56 | "namespace": "my-ns",
57 | "sources": [
58 | {
59 | "serviceAccount": "client",
60 | "namespace": "my-ns",
61 | "pods": [
62 | "pod-a@my-ns"
63 | ]
64 | }
65 | ],
66 | "destination": {
67 | "serviceAccount": "server",
68 | "namespace": "my-ns",
69 | "ports": [
70 | {
71 | "name": "port-8080",
72 | "protocol": "TCP",
73 | "port": 8080,
74 | "targetPort": 8080
75 | },
76 | {
77 | "name": "port-8081",
78 | "protocol": "TCP",
79 | "port": 8081,
80 | "targetPort": "web"
81 | }
82 | ],
83 | "pods": [
84 | "pod-b@my-ns"
85 | ]
86 | }
87 | }
88 | },
89 | "trafficSplits": {}
90 | }
91 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-enabled-http-route-group-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "my-ns-svc-b-8080": {
5 | "entryPoints": [
6 | "http-10000"
7 | ],
8 | "middlewares": [
9 | "block-all-middleware"
10 | ],
11 | "service": "block-all-service",
12 | "rule": "Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)",
13 | "priority": 1
14 | },
15 | "my-ns-svc-b-tt-8080-traffic-target-direct": {
16 | "entryPoints": [
17 | "http-10000"
18 | ],
19 | "middlewares": [
20 | "my-ns-svc-b-tt-whitelist-traffic-target-direct"
21 | ],
22 | "service": "my-ns-svc-b-tt-8080-traffic-target",
23 | "rule": "(Host(`svc-b.my-ns.traefik.mesh`) || Host(`svc-b.my-ns.maesh`) || Host(`10.10.14.1`)) && (PathPrefix(`/{path:app}`) || (PathPrefix(`/{path:api/notifications}`) && Method(`GET`)) || HeadersRegexp(`User-Agent`, `Mozilla/.*`))",
24 | "priority": 2006
25 | },
26 | "readiness": {
27 | "entryPoints": [
28 | "readiness"
29 | ],
30 | "service": "readiness",
31 | "rule": "Path(`/ping`)"
32 | }
33 | },
34 | "services": {
35 | "block-all-service": {
36 | "loadBalancer": {
37 | "passHostHeader": false
38 | }
39 | },
40 | "my-ns-svc-b-tt-8080-traffic-target": {
41 | "loadBalancer": {
42 | "servers": [
43 | {
44 | "url": "http://10.10.3.1:8080"
45 | }
46 | ],
47 | "passHostHeader": true
48 | }
49 | },
50 | "readiness": {
51 | "loadBalancer": {
52 | "servers": [
53 | {
54 | "url": "http://127.0.0.1:8080"
55 | }
56 | ],
57 | "passHostHeader": true
58 | }
59 | }
60 | },
61 | "middlewares": {
62 | "block-all-middleware": {
63 | "ipWhiteList": {
64 | "sourceRange": [
65 | "255.255.255.255"
66 | ]
67 | }
68 | },
69 | "my-ns-svc-b-tt-whitelist-traffic-target-direct": {
70 | "ipWhiteList": {
71 | "sourceRange": [
72 | "10.10.2.1"
73 | ]
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-enabled-tcp-basic-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "readiness": {
5 | "entryPoints": [
6 | "readiness"
7 | ],
8 | "service": "readiness",
9 | "rule": "Path(`/ping`)"
10 | }
11 | },
12 | "services": {
13 | "block-all-service": {
14 | "loadBalancer": {
15 | "passHostHeader": false
16 | }
17 | },
18 | "readiness": {
19 | "loadBalancer": {
20 | "servers": [
21 | {
22 | "url": "http://127.0.0.1:8080"
23 | }
24 | ],
25 | "passHostHeader": true
26 | }
27 | }
28 | },
29 | "middlewares": {
30 | "block-all-middleware": {
31 | "ipWhiteList": {
32 | "sourceRange": [
33 | "255.255.255.255"
34 | ]
35 | }
36 | }
37 | }
38 | },
39 | "tcp": {
40 | "routers": {
41 | "my-ns-svc-b-8080": {
42 | "entryPoints": [
43 | "tcp-5000"
44 | ],
45 | "service": "my-ns-svc-b-8080",
46 | "rule": "HostSNI(`*`)"
47 | },
48 | "my-ns-svc-b-8081": {
49 | "entryPoints": [
50 | "tcp-5001"
51 | ],
52 | "service": "my-ns-svc-b-8081",
53 | "rule": "HostSNI(`*`)"
54 | }
55 | },
56 | "services": {
57 | "my-ns-svc-b-8080": {
58 | "loadBalancer": {
59 | "servers": [
60 | {
61 | "address": "10.10.3.1:8080"
62 | }
63 | ]
64 | }
65 | },
66 | "my-ns-svc-b-8081": {
67 | "loadBalancer": {
68 | "servers": [
69 | {
70 | "address": "10.10.3.1:8081"
71 | }
72 | ]
73 | }
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/acl-enabled-tcp-basic-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b@my-ns": {
4 | "name": "svc-b",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {},
8 | "ports": [
9 | {
10 | "name": "port-8080",
11 | "protocol": "TCP",
12 | "port": 8080,
13 | "targetPort": 8080
14 | },
15 | {
16 | "name": "port-8081",
17 | "protocol": "TCP",
18 | "port": 8081,
19 | "targetPort": "web"
20 | }
21 | ],
22 | "clusterIp": "10.10.14.1",
23 | "pods": [
24 | "pod-b@my-ns"
25 | ],
26 | "trafficTargets": [
27 | "svc-b@my-ns:tt@my-ns"
28 | ]
29 | }
30 | },
31 | "pods": {
32 | "pod-a@my-ns": {
33 | "name": "pod-a",
34 | "namespace": "my-ns",
35 | "serviceAccount": "client",
36 | "ip": "10.10.2.1"
37 | },
38 | "pod-b@my-ns": {
39 | "name": "pod-b",
40 | "namespace": "my-ns",
41 | "serviceAccount": "server",
42 | "ip": "10.10.3.1",
43 | "containerPorts": [
44 | {
45 | "name": "web",
46 | "protocol": "TCP",
47 | "containerPort": 8081
48 | }
49 | ]
50 | }
51 | },
52 | "serviceTrafficTargets": {
53 | "svc-b@my-ns:tt@my-ns": {
54 | "service": "svc-b@my-ns",
55 | "name": "tt",
56 | "namespace": "my-ns",
57 | "rules": [
58 | {
59 | "tcpRoute": {
60 | "kind": "TCPRoute",
61 | "metadata": {
62 | "name": "tcp-route",
63 | "namespace": "my-ns"
64 | }
65 | }
66 | }
67 | ],
68 | "sources": [
69 | {
70 | "serviceAccount": "client",
71 | "namespace": "my-ns",
72 | "pods": [
73 | "pod-a@my-ns"
74 | ]
75 | }
76 | ],
77 | "destination": {
78 | "serviceAccount": "server",
79 | "namespace": "my-ns",
80 | "ports": [
81 | {
82 | "name": "port-8080",
83 | "protocol": "TCP",
84 | "port": 8080,
85 | "targetPort": 8080
86 | },
87 | {
88 | "name": "port-8081",
89 | "protocol": "TCP",
90 | "port": 8081,
91 | "targetPort": "web"
92 | }
93 | ],
94 | "pods": [
95 | "pod-b@my-ns"
96 | ]
97 | }
98 | }
99 | },
100 | "trafficSplits": {}
101 | }
102 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/annotations-scheme-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "my-ns-svc-a-8080": {
5 | "entryPoints": [
6 | "http-10000"
7 | ],
8 | "service": "my-ns-svc-a-8080",
9 | "rule": "Host(`svc-a.my-ns.traefik.mesh`) || Host(`svc-a.my-ns.maesh`) || Host(`10.10.14.1`)",
10 | "priority": 1002
11 | },
12 | "readiness": {
13 | "entryPoints": [
14 | "readiness"
15 | ],
16 | "service": "readiness",
17 | "rule": "Path(`/ping`)"
18 | }
19 | },
20 | "services": {
21 | "block-all-service": {
22 | "loadBalancer": {
23 | "passHostHeader": false
24 | }
25 | },
26 | "my-ns-svc-a-8080": {
27 | "loadBalancer": {
28 | "servers": [
29 | {
30 | "url": "https://10.10.2.1:8080"
31 | },
32 | {
33 | "url": "https://10.10.2.2:8080"
34 | }
35 | ],
36 | "passHostHeader": true
37 | }
38 | },
39 | "readiness": {
40 | "loadBalancer": {
41 | "servers": [
42 | {
43 | "url": "http://127.0.0.1:8080"
44 | }
45 | ],
46 | "passHostHeader": true
47 | }
48 | }
49 | },
50 | "middlewares": {
51 | "block-all-middleware": {
52 | "ipWhiteList": {
53 | "sourceRange": [
54 | "255.255.255.255"
55 | ]
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/annotations-scheme-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {
8 | "mesh.traefik.io/scheme": "https"
9 | },
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.14.1",
19 | "pods": [
20 | "pod-a1@my-ns",
21 | "pod-a2@my-ns"
22 | ]
23 | }
24 | },
25 | "pods": {
26 | "pod-a1@my-ns": {
27 | "name": "pod-a1",
28 | "namespace": "my-ns",
29 | "serviceAccount": "default",
30 | "ip": "10.10.2.1"
31 | },
32 | "pod-a2@my-ns": {
33 | "name": "pod-a2",
34 | "namespace": "my-ns",
35 | "serviceAccount": "default",
36 | "ip": "10.10.2.2"
37 | }
38 | },
39 | "serviceTrafficTargets": {},
40 | "trafficSplits": {}
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/annotations-traffic-type-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "http": {
3 | "routers": {
4 | "readiness": {
5 | "entryPoints": [
6 | "readiness"
7 | ],
8 | "service": "readiness",
9 | "rule": "Path(`/ping`)"
10 | }
11 | },
12 | "services": {
13 | "block-all-service": {
14 | "loadBalancer": {
15 | "passHostHeader": false
16 | }
17 | },
18 | "readiness": {
19 | "loadBalancer": {
20 | "servers": [
21 | {
22 | "url": "http://127.0.0.1:8080"
23 | }
24 | ],
25 | "passHostHeader": true
26 | }
27 | }
28 | },
29 | "middlewares": {
30 | "block-all-middleware": {
31 | "ipWhiteList": {
32 | "sourceRange": [
33 | "255.255.255.255"
34 | ]
35 | }
36 | }
37 | }
38 | },
39 | "tcp": {
40 | "routers": {
41 | "my-ns-svc-a-8080": {
42 | "entryPoints": [
43 | "tcp-5000"
44 | ],
45 | "service": "my-ns-svc-a-8080",
46 | "rule": "HostSNI(`*`)"
47 | }
48 | },
49 | "services": {
50 | "my-ns-svc-a-8080": {
51 | "loadBalancer": {
52 | "servers": [
53 | {
54 | "address": "10.10.2.1:8080"
55 | },
56 | {
57 | "address": "10.10.2.2:8080"
58 | }
59 | ]
60 | }
61 | }
62 | }
63 | },
64 | "udp": {
65 | "routers": {
66 | "my-ns-svc-b-8080": {
67 | "entryPoints": [
68 | "udp-15000"
69 | ],
70 | "service": "my-ns-svc-b-8080"
71 | }
72 | },
73 | "services": {
74 | "my-ns-svc-b-8080": {
75 | "loadBalancer": {
76 | "servers": [
77 | {
78 | "address": "10.10.2.1:8080"
79 | },
80 | {
81 | "address": "10.10.2.2:8080"
82 | }
83 | ]
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/pkg/provider/testdata/annotations-traffic-type-topology.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-a@my-ns": {
4 | "name": "svc-a",
5 | "namespace": "my-ns",
6 | "selector": {},
7 | "annotations": {
8 | "mesh.traefik.io/traffic-type": "tcp"
9 | },
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.14.1",
19 | "pods": [
20 | "pod-a1@my-ns",
21 | "pod-a2@my-ns"
22 | ]
23 | },
24 | "svc-b@my-ns": {
25 | "name": "svc-b",
26 | "namespace": "my-ns",
27 | "selector": {},
28 | "annotations": {
29 | "mesh.traefik.io/traffic-type": "udp"
30 | },
31 | "ports": [
32 | {
33 | "name": "port-8080",
34 | "protocol": "UDP",
35 | "port": 8080,
36 | "targetPort": 8080
37 | }
38 | ],
39 | "clusterIp": "10.10.14.1",
40 | "pods": [
41 | "pod-a1@my-ns",
42 | "pod-a2@my-ns"
43 | ]
44 | }
45 | },
46 | "pods": {
47 | "pod-a1@my-ns": {
48 | "name": "pod-a1",
49 | "namespace": "my-ns",
50 | "serviceAccount": "default",
51 | "ip": "10.10.2.1"
52 | },
53 | "pod-a2@my-ns": {
54 | "name": "pod-a2",
55 | "namespace": "my-ns",
56 | "serviceAccount": "default",
57 | "ip": "10.10.2.2"
58 | }
59 | },
60 | "serviceTrafficTargets": {},
61 | "trafficSplits": {}
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/safe/recover.go:
--------------------------------------------------------------------------------
1 | package safe
2 |
3 | import (
4 | "fmt"
5 | "runtime/debug"
6 |
7 | "github.com/cenkalti/backoff/v4"
8 | "github.com/sirupsen/logrus"
9 | )
10 |
11 | // OperationWithRecover wrap a backoff operation in a Recover.
12 | func OperationWithRecover(operation backoff.Operation) backoff.Operation {
13 | return func() (err error) {
14 | defer func() {
15 | if res := recover(); res != nil {
16 | logger := logrus.StandardLogger()
17 |
18 | logger.Errorf("Error in Go routine: %s", res)
19 | logger.Errorf("Stack: %s", debug.Stack())
20 |
21 | err = fmt.Errorf("panic in operation: %w", err)
22 | }
23 | }()
24 |
25 | return operation()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/safe/recover_test.go:
--------------------------------------------------------------------------------
1 | package safe
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/cenkalti/backoff/v4"
8 | )
9 |
10 | func TestOperationWithRecover(t *testing.T) {
11 | operation := func() error {
12 | return nil
13 | }
14 |
15 | err := backoff.Retry(OperationWithRecover(operation), &backoff.StopBackOff{})
16 | if err != nil {
17 | t.Fatalf("Error in OperationWithRecover: %s", err)
18 | }
19 | }
20 |
21 | func TestOperationWithRecoverPanic(t *testing.T) {
22 | operation := func() error {
23 | panic("BOOM")
24 | }
25 |
26 | err := backoff.Retry(OperationWithRecover(operation), &backoff.StopBackOff{})
27 | if err == nil {
28 | t.Fatalf("Error in OperationWithRecover: %s", err)
29 | }
30 | }
31 |
32 | func TestOperationWithRecoverError(t *testing.T) {
33 | operation := func() error {
34 | return fmt.Errorf("ERROR")
35 | }
36 |
37 | err := backoff.Retry(OperationWithRecover(operation), &backoff.StopBackOff{})
38 | if err == nil {
39 | t.Fatalf("Error in OperationWithRecover: %s", err)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/safe/safe.go:
--------------------------------------------------------------------------------
1 | package safe
2 |
3 | import (
4 | "sync"
5 | )
6 |
7 | // Safe contains a thread-safe value.
8 | type Safe struct {
9 | value interface{}
10 | lock sync.RWMutex
11 | }
12 |
13 | // New create a new Safe instance given a value.
14 | func New(value interface{}) *Safe {
15 | return &Safe{value: value}
16 | }
17 |
18 | // Get returns the value.
19 | func (s *Safe) Get() interface{} {
20 | s.lock.RLock()
21 | defer s.lock.RUnlock()
22 |
23 | return s.value
24 | }
25 |
26 | // Set sets a new value.
27 | func (s *Safe) Set(value interface{}) {
28 | s.lock.Lock()
29 | defer s.lock.Unlock()
30 |
31 | s.value = value
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/safe/safe_test.go:
--------------------------------------------------------------------------------
1 | package safe
2 |
3 | import "testing"
4 |
5 | func TestSafe(t *testing.T) {
6 | const ts1, ts2 = "test1", "test2"
7 |
8 | s := New(ts1)
9 |
10 | result, ok := s.Get().(string)
11 | if !ok {
12 | t.Fatalf("Safe.Get() failed, got type '%T', expected string", s.Get())
13 | }
14 |
15 | if result != ts1 {
16 | t.Errorf("Safe.Get() failed, got '%s', expected '%s'", result, ts1)
17 | }
18 |
19 | s.Set(ts2)
20 |
21 | result, ok = s.Get().(string)
22 | if !ok {
23 | t.Fatalf("Safe.Get() after Safe.Set() failed, got type '%T', expected string", s.Get())
24 | }
25 |
26 | if result != ts2 {
27 | t.Errorf("Safe.Get() after Safe.Set() failed, got '%s', expected '%s'", result, ts2)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-empty-destination-port.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b@my-ns": {
4 | "name": "svc-b",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "app-b"
8 | },
9 | "annotations": {
10 | "mesh.traefik.io/ratelimit-average": "100",
11 | "mesh.traefik.io/ratelimit-burst": "200",
12 | "mesh.traefik.io/traffic-type": "http"
13 | },
14 | "ports": [
15 | {
16 | "name": "port-8080",
17 | "protocol": "TCP",
18 | "port": 8080,
19 | "targetPort": 8080
20 | },
21 | {
22 | "name": "port-9090",
23 | "protocol": "TCP",
24 | "port": 9090,
25 | "targetPort": 9090
26 | }
27 | ],
28 | "clusterIp": "10.10.1.16",
29 | "pods": [
30 | "app-b@my-ns"
31 | ],
32 | "trafficTargets": [
33 | "svc-b@my-ns:tt@my-ns"
34 | ]
35 | }
36 | },
37 | "pods": {
38 | "app-a@my-ns": {
39 | "name": "app-a",
40 | "namespace": "my-ns",
41 | "serviceAccount": "service-account-a",
42 | "ip": "10.10.1.1",
43 | "sourceOf": [
44 | "svc-b@my-ns:tt@my-ns"
45 | ]
46 | },
47 | "app-b@my-ns": {
48 | "name": "app-b",
49 | "namespace": "my-ns",
50 | "serviceAccount": "service-account-b",
51 | "ip": "10.10.2.1",
52 | "destinationOf": [
53 | "svc-b@my-ns:tt@my-ns"
54 | ]
55 | }
56 | },
57 | "serviceTrafficTargets": {
58 | "svc-b@my-ns:tt@my-ns": {
59 | "service": "svc-b@my-ns",
60 | "name": "tt",
61 | "namespace": "my-ns",
62 | "sources": [
63 | {
64 | "serviceAccount": "service-account-a",
65 | "namespace": "my-ns",
66 | "pods": [
67 | "app-a@my-ns"
68 | ]
69 | }
70 | ],
71 | "destination": {
72 | "serviceAccount": "service-account-b",
73 | "namespace": "my-ns",
74 | "ports": [
75 | {
76 | "name": "port-8080",
77 | "protocol": "TCP",
78 | "port": 8080,
79 | "targetPort": 8080
80 | },
81 | {
82 | "name": "port-9090",
83 | "protocol": "TCP",
84 | "port": 9090,
85 | "targetPort": 9090
86 | }
87 | ],
88 | "pods": [
89 | "app-b@my-ns"
90 | ]
91 | }
92 | }
93 | },
94 | "trafficSplits": {}
95 | }
96 |
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-multi-sources-destinations.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-c@my-ns": {
4 | "name": "svc-c",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "app-c"
8 | },
9 | "annotations": {},
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.1.16",
19 | "pods": [
20 | "app-c-1@my-ns",
21 | "app-c-2@my-ns"
22 | ],
23 | "trafficTargets": [
24 | "svc-c@my-ns:tt@my-ns"
25 | ]
26 | }
27 | },
28 | "pods": {
29 | "app-a@my-ns": {
30 | "name": "app-a",
31 | "namespace": "my-ns",
32 | "serviceAccount": "service-account-a",
33 | "ip": "10.10.1.1",
34 | "sourceOf": [
35 | "svc-c@my-ns:tt@my-ns"
36 | ]
37 | },
38 | "app-b@my-ns": {
39 | "name": "app-b",
40 | "namespace": "my-ns",
41 | "serviceAccount": "service-account-b",
42 | "ip": "10.10.2.1",
43 | "sourceOf": [
44 | "svc-c@my-ns:tt@my-ns"
45 | ]
46 | },
47 | "app-c-1@my-ns": {
48 | "name": "app-c-1",
49 | "namespace": "my-ns",
50 | "serviceAccount": "service-account-c",
51 | "ip": "10.10.3.1",
52 | "destinationOf": [
53 | "svc-c@my-ns:tt@my-ns"
54 | ]
55 | },
56 | "app-c-2@my-ns": {
57 | "name": "app-c-2",
58 | "namespace": "my-ns",
59 | "serviceAccount": "service-account-c",
60 | "ip": "10.10.3.2",
61 | "destinationOf": [
62 | "svc-c@my-ns:tt@my-ns"
63 | ]
64 | }
65 | },
66 | "serviceTrafficTargets": {
67 | "svc-c@my-ns:tt@my-ns": {
68 | "service": "svc-c@my-ns",
69 | "name": "tt",
70 | "namespace": "my-ns",
71 | "sources": [
72 | {
73 | "serviceAccount": "service-account-a",
74 | "namespace": "my-ns",
75 | "pods": [
76 | "app-a@my-ns"
77 | ]
78 | },
79 | {
80 | "serviceAccount": "service-account-b",
81 | "namespace": "my-ns",
82 | "pods": [
83 | "app-b@my-ns"
84 | ]
85 | }
86 | ],
87 | "destination": {
88 | "serviceAccount": "service-account-c",
89 | "namespace": "my-ns",
90 | "ports": [
91 | {
92 | "name": "port-8080",
93 | "protocol": "TCP",
94 | "port": 8080,
95 | "targetPort": 8080
96 | }
97 | ],
98 | "pods": [
99 | "app-c-1@my-ns",
100 | "app-c-2@my-ns"
101 | ]
102 | }
103 | }
104 | },
105 | "trafficSplits": {}
106 | }
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-service-with-pod-port-mixture.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc@my-ns": {
4 | "name": "svc",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "my-app"
8 | },
9 | "ports": [
10 | {
11 | "name": "port-80",
12 | "port": 80,
13 | "targetPort": "name"
14 | },
15 | {
16 | "name": "port-8080",
17 | "port": 8080,
18 | "targetPort": 8080
19 | }
20 | ],
21 | "clusterIp": "10.10.1.3",
22 | "pods": [
23 | "pod-v1@my-ns",
24 | "pod-v2@my-ns"
25 | ],
26 | "trafficTargets": []
27 | }
28 | },
29 | "pods": {
30 | "pod-v1@my-ns": {
31 | "name": "pod-v1",
32 | "namespace": "my-ns",
33 | "serviceAccount": "service-account",
34 | "ip": "10.10.1.1",
35 | "sourceOf": []
36 | },
37 | "pod-v2@my-ns": {
38 | "name": "pod-v2",
39 | "namespace": "my-ns",
40 | "serviceAccount": "service-account",
41 | "ip": "10.10.1.2",
42 | "destinationOf": []
43 | }
44 | },
45 | "serviceTrafficTargets": {},
46 | "trafficSplits": {}
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-spec-with-empty-match.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b@my-ns": {
4 | "name": "svc-b",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "app-b"
8 | },
9 | "annotations": {},
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.1.16",
19 | "pods": [
20 | "app-b@my-ns"
21 | ],
22 | "trafficTargets": [
23 | "svc-b@my-ns:tt@my-ns"
24 | ]
25 | }
26 | },
27 | "pods": {
28 | "app-a@my-ns": {
29 | "name": "app-a",
30 | "namespace": "my-ns",
31 | "serviceAccount": "service-account-a",
32 | "ip": "10.10.1.1",
33 | "sourceOf": [
34 | "svc-b@my-ns:tt@my-ns"
35 | ]
36 | },
37 | "app-b@my-ns": {
38 | "name": "app-b",
39 | "namespace": "my-ns",
40 | "serviceAccount": "service-account-b",
41 | "ip": "10.10.2.1",
42 | "destinationOf": [
43 | "svc-b@my-ns:tt@my-ns"
44 | ]
45 | }
46 | },
47 | "trafficSplits": {},
48 | "serviceTrafficTargets": {
49 | "svc-b@my-ns:tt@my-ns": {
50 | "service": "svc-b@my-ns",
51 | "name": "tt",
52 | "namespace": "my-ns",
53 | "sources": [
54 | {
55 | "serviceAccount": "service-account-a",
56 | "namespace": "my-ns",
57 | "pods": [
58 | "app-a@my-ns"
59 | ]
60 | }
61 | ],
62 | "destination": {
63 | "serviceAccount": "service-account-b",
64 | "namespace": "my-ns",
65 | "ports": [
66 | {
67 | "name": "port-8080",
68 | "protocol": "TCP",
69 | "port": 8080,
70 | "targetPort": 8080
71 | }
72 | ],
73 | "pods": [
74 | "app-b@my-ns"
75 | ]
76 | },
77 | "rules": [
78 | {
79 | "httpRouteGroup": {
80 | "kind": "HTTPRouteGroup",
81 | "apiVersion": "specs.smi-spec.io/v1alpha3",
82 | "metadata": {
83 | "name": "http-rt-grp",
84 | "namespace": "my-ns",
85 | "creationTimestamp": null
86 | },
87 | "spec": {
88 | "matches": [
89 | {
90 | "name": "api",
91 | "methods": [
92 | "GET",
93 | "POST"
94 | ],
95 | "pathRegex": "/api"
96 | },
97 | {
98 | "name": "metric",
99 | "methods": [
100 | "GET"
101 | ],
102 | "pathRegex": "/metric"
103 | }
104 | ]
105 | }
106 | },
107 | "httpMatches": [
108 | {
109 | "name": "api",
110 | "methods": [
111 | "GET",
112 | "POST"
113 | ],
114 | "pathRegex": "/api"
115 | },
116 | {
117 | "name": "metric",
118 | "methods": [
119 | "GET"
120 | ],
121 | "pathRegex": "/metric"
122 | }
123 | ]
124 | }
125 | ]
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-traffic-target-service-port-mismatch.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b1@my-ns": {
4 | "name": "svc-b1",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "app-b1"
8 | },
9 | "annotations": {},
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.1.16",
19 | "pods": [
20 | "app-b1@my-ns"
21 | ]
22 | },
23 | "svc-b2@my-ns": {
24 | "name": "svc-b2",
25 | "namespace": "my-ns",
26 | "selector": {
27 | "app": "app-b2"
28 | },
29 | "annotations": {},
30 | "ports": [
31 | {
32 | "name": "port-80",
33 | "protocol": "TCP",
34 | "port": 80,
35 | "targetPort": 80
36 | }
37 | ],
38 | "clusterIp": "10.10.1.17",
39 | "pods": [
40 | "app-b2@my-ns"
41 | ],
42 | "trafficTargets": [
43 | "svc-b2@my-ns:tt@my-ns"
44 | ]
45 | }
46 | },
47 | "pods": {
48 | "app-a@my-ns": {
49 | "name": "app-a",
50 | "namespace": "my-ns",
51 | "serviceAccount": "service-account-a",
52 | "ip": "10.10.1.1",
53 | "sourceOf": [
54 | "svc-b2@my-ns:tt@my-ns"
55 | ]
56 | },
57 | "app-b1@my-ns": {
58 | "name": "app-b1",
59 | "namespace": "my-ns",
60 | "serviceAccount": "service-account-b",
61 | "ip": "10.10.1.2"
62 | },
63 | "app-b2@my-ns": {
64 | "name": "app-b2",
65 | "namespace": "my-ns",
66 | "serviceAccount": "service-account-b",
67 | "ip": "10.10.1.3",
68 | "destinationOf": [
69 | "svc-b2@my-ns:tt@my-ns"
70 | ]
71 | }
72 | },
73 | "serviceTrafficTargets": {
74 | "svc-b1@my-ns:tt@my-ns": {
75 | "service": "svc-b1@my-ns",
76 | "name": "tt",
77 | "namespace": "my-ns",
78 | "sources": [
79 | {
80 | "serviceAccount": "service-account-a",
81 | "namespace": "my-ns",
82 | "pods": [
83 | "app-a@my-ns"
84 | ]
85 | }
86 | ],
87 | "destination": {
88 | "serviceAccount": "service-account-b",
89 | "namespace": "my-ns",
90 | "ports": [],
91 | "pods": [
92 | "app-b1@my-ns"
93 | ]
94 | },
95 | "errors": [
96 | "unable to find destination ports on Service \"svc-b1@my-ns\": destination port 80 of TrafficTarget \"tt@my-ns\" is not exposed by the service"
97 | ]
98 | },
99 | "svc-b2@my-ns:tt@my-ns": {
100 | "service": "svc-b2@my-ns",
101 | "name": "tt",
102 | "namespace": "my-ns",
103 | "sources": [
104 | {
105 | "serviceAccount": "service-account-a",
106 | "namespace": "my-ns",
107 | "pods": [
108 | "app-a@my-ns"
109 | ]
110 | }
111 | ],
112 | "destination": {
113 | "serviceAccount": "service-account-b",
114 | "namespace": "my-ns",
115 | "ports": [
116 | {
117 | "name": "port-80",
118 | "protocol": "TCP",
119 | "port": 80,
120 | "targetPort": 80
121 | }
122 | ],
123 | "pods": [
124 | "app-b2@my-ns"
125 | ]
126 | }
127 | }
128 | },
129 | "trafficSplits": {}
130 | }
--------------------------------------------------------------------------------
/pkg/topology/testdata/topology-traffic-target.json:
--------------------------------------------------------------------------------
1 | {
2 | "services": {
3 | "svc-b@my-ns": {
4 | "name": "svc-b",
5 | "namespace": "my-ns",
6 | "selector": {
7 | "app": "app-b"
8 | },
9 | "annotations": {},
10 | "ports": [
11 | {
12 | "name": "port-8080",
13 | "protocol": "TCP",
14 | "port": 8080,
15 | "targetPort": 8080
16 | }
17 | ],
18 | "clusterIp": "10.10.1.16",
19 | "pods": [
20 | "app-b@my-ns"
21 | ],
22 | "trafficTargets": [
23 | "svc-b@my-ns:tt@my-ns"
24 | ]
25 | }
26 | },
27 | "pods": {
28 | "app-a@my-ns": {
29 | "name": "app-a",
30 | "namespace": "my-ns",
31 | "serviceAccount": "service-account-a",
32 | "ip": "10.10.1.1",
33 | "sourceOf": [
34 | "svc-b@my-ns:tt@my-ns"
35 | ]
36 | },
37 | "app-b@my-ns": {
38 | "name": "app-b",
39 | "namespace": "my-ns",
40 | "serviceAccount": "service-account-b",
41 | "ip": "10.10.2.1",
42 | "destinationOf": [
43 | "svc-b@my-ns:tt@my-ns"
44 | ]
45 | }
46 | },
47 | "serviceTrafficTargets": {
48 | "svc-b@my-ns:tt@my-ns": {
49 | "service": "svc-b@my-ns",
50 | "name": "tt",
51 | "namespace": "my-ns",
52 | "sources": [
53 | {
54 | "serviceAccount": "service-account-a",
55 | "namespace": "my-ns",
56 | "pods": [
57 | "app-a@my-ns"
58 | ]
59 | }
60 | ],
61 | "destination": {
62 | "serviceAccount": "service-account-b",
63 | "namespace": "my-ns",
64 | "ports": [
65 | {
66 | "name": "port-8080",
67 | "protocol": "TCP",
68 | "port": 8080,
69 | "targetPort": 8080
70 | }
71 | ],
72 | "pods": [
73 | "app-b@my-ns"
74 | ]
75 | },
76 | "rules": [
77 | {
78 | "httpRouteGroup": {
79 | "kind": "HTTPRouteGroup",
80 | "apiVersion": "specs.smi-spec.io/v1alpha3",
81 | "metadata": {
82 | "name": "http-rt-grp",
83 | "namespace": "my-ns",
84 | "creationTimestamp": null
85 | },
86 | "spec": {
87 | "matches": [
88 | {
89 | "name": "api",
90 | "methods": [
91 | "GET",
92 | "POST"
93 | ],
94 | "pathRegex": "/api",
95 | "headers": [
96 | {
97 | "User-Agent": "curl/.*"
98 | }
99 | ]
100 | },
101 | {
102 | "name": "metric",
103 | "methods": [
104 | "GET"
105 | ],
106 | "pathRegex": "/metric"
107 | }
108 | ]
109 | }
110 | },
111 | "httpMatches": [
112 | {
113 | "name": "api",
114 | "methods": [
115 | "GET",
116 | "POST"
117 | ],
118 | "pathRegex": "/api",
119 | "headers": [
120 | {
121 | "User-Agent": "curl/.*"
122 | }
123 | ]
124 | }
125 | ]
126 | }
127 | ]
128 | }
129 | },
130 | "trafficSplits": {}
131 | }
--------------------------------------------------------------------------------
/pkg/topology/topology_test.go:
--------------------------------------------------------------------------------
1 | package topology
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | corev1 "k8s.io/api/core/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | func TestTopology_ResolveServicePort(t *testing.T) {
12 | tests := []struct {
13 | desc string
14 | svcPort corev1.ServicePort
15 | containerPorts []corev1.ContainerPort
16 | expPort int32
17 | expResult bool
18 | }{
19 | {
20 | desc: "should return the service TargetPort if it as Int",
21 | svcPort: corev1.ServicePort{
22 | TargetPort: intstr.FromInt(3000),
23 | },
24 | expPort: 3000,
25 | expResult: true,
26 | },
27 | {
28 | desc: "should return false if the service TargetPort is a String and the container port list is empty",
29 | svcPort: corev1.ServicePort{
30 | TargetPort: intstr.FromString("foo"),
31 | },
32 | expPort: 0,
33 | expResult: false,
34 | },
35 | {
36 | desc: "should return false if the service TargetPort is a String and it cannot be resolved",
37 | svcPort: corev1.ServicePort{
38 | TargetPort: intstr.FromString("foo"),
39 | Protocol: corev1.ProtocolTCP,
40 | },
41 | containerPorts: []corev1.ContainerPort{
42 | {
43 | Name: "bar",
44 | ContainerPort: 3000,
45 | },
46 | {
47 | Name: "foo",
48 | Protocol: corev1.ProtocolUDP,
49 | ContainerPort: 3000,
50 | },
51 | },
52 | expPort: 0,
53 | expResult: false,
54 | },
55 | {
56 | desc: "should return true and the resolved service TargetPort",
57 | svcPort: corev1.ServicePort{
58 | TargetPort: intstr.FromString("foo"),
59 | Protocol: corev1.ProtocolUDP,
60 | },
61 | containerPorts: []corev1.ContainerPort{
62 | {
63 | Name: "foo",
64 | Protocol: corev1.ProtocolUDP,
65 | ContainerPort: 3000,
66 | },
67 | },
68 | expPort: 3000,
69 | expResult: true,
70 | },
71 | }
72 |
73 | for _, test := range tests {
74 | test := test
75 | t.Run(test.desc, func(t *testing.T) {
76 | t.Parallel()
77 |
78 | port, result := ResolveServicePort(test.svcPort, test.containerPorts)
79 |
80 | assert.Equal(t, test.expResult, result)
81 | assert.Equal(t, test.expPort, port)
82 | })
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/pkg/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | var (
4 | // Version holds the version name.
5 | Version = "dev"
6 | // Commit holds the version build commit.
7 | Commit = "I don't remember exactly"
8 | // Date holds the version build date.
9 | Date = "I don't remember exactly"
10 | )
11 |
--------------------------------------------------------------------------------
/spinach.yaml:
--------------------------------------------------------------------------------
1 | # Severities: Ok: 0, Info: 1, Warn: 2, Error: 3
2 | popeye:
3 | codes:
4 | 301:
5 | severity: 1 # Set severity level to Info if pod needs to connect to the API.
6 | 302:
7 | severity: 1 # Set severity level to Info if pod needs to run as root.
8 |
--------------------------------------------------------------------------------
/tmpl.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.19-alpine AS builder
2 |
3 | # Package dependencies
4 | RUN apk --no-cache --no-progress add \
5 | bash \
6 | gcc \
7 | git \
8 | make \
9 | musl-dev \
10 | mercurial \
11 | curl \
12 | tar \
13 | ca-certificates \
14 | tzdata \
15 | && update-ca-certificates \
16 | && rm -rf /var/cache/apk/*
17 |
18 | WORKDIR /go/src/github.com/traefik/mesh
19 |
20 | # Download goreleaser binary to bin folder in $GOPATH
21 | RUN curl -sfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | sh
22 |
23 | ENV GO111MODULE on
24 | COPY go.mod go.sum ./
25 | RUN go mod download
26 | COPY . .
27 |
28 | RUN GOARCH={{ .GoARCH }} GOARM={{ .GoARM }} make local-build
29 |
30 | ## IMAGE
31 | FROM {{ .RuntimeImage }}
32 |
33 | RUN addgroup -g 1000 -S app && \
34 | adduser -u 1000 -S app -G app
35 |
36 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
37 | COPY --from=builder /go/src/github.com/traefik/mesh/dist/traefik-mesh /app/
38 |
39 | ENTRYPOINT ["/app/traefik-mesh"]
40 |
--------------------------------------------------------------------------------