Compare commits

...

131 Commits

Author SHA1 Message Date
Stefan Prodan
d9fec9778d Merge pull request #430 from stefanprodan/release-6.9.3
Some checks failed
cve-scan / govulncheck (push) Successful in 11m40s
e2e / kind-helm (push) Failing after 1m13s
e2e / kind-timoni (push) Failing after 8s
test / test (push) Failing after 5m20s
Release 6.9.3
2025-11-22 14:24:39 +02:00
Stefan Prodan
7ac390bb27 Release 6.9.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-11-22 13:59:49 +02:00
Stefan Prodan
576ad0ff2f Merge pull request #429 from stefanprodan/dependabot/github_actions/actions-fa1ae25fd8
Some checks failed
cve-scan / govulncheck (push) Successful in 12m5s
e2e / kind-helm (push) Failing after 2m42s
e2e / kind-timoni (push) Failing after 9s
test / test (push) Failing after 5m19s
build(deps): bump the actions group across 1 directory with 2 updates
2025-11-22 13:55:47 +02:00
dependabot[bot]
74ac24bc86 build(deps): bump the actions group across 1 directory with 2 updates
Bumps the actions group with 2 updates in the / directory: [helm/kind-action](https://github.com/helm/kind-action) and [fluxcd/flux2](https://github.com/fluxcd/flux2).


Updates `helm/kind-action` from 1.12.0 to 1.13.0
- [Release notes](https://github.com/helm/kind-action/releases)
- [Commits](https://github.com/helm/kind-action/compare/v1.12.0...v1.13.0)

Updates `fluxcd/flux2` from 2.7.2 to 2.7.3
- [Release notes](https://github.com/fluxcd/flux2/releases)
- [Changelog](https://github.com/fluxcd/flux2/blob/main/.goreleaser.yml)
- [Commits](https://github.com/fluxcd/flux2/compare/v2.7.2...v2.7.3)

---
updated-dependencies:
- dependency-name: helm/kind-action
  dependency-version: 1.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: fluxcd/flux2
  dependency-version: 2.7.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 06:38:39 +00:00
Stefan Prodan
902e62b5f3 Merge pull request #427 from stefanprodan/chart-gateway-api
Some checks failed
test / test (push) Failing after 17s
cve-scan / govulncheck (push) Failing after 26s
e2e / kind-helm (push) Failing after 19s
e2e / kind-timoni (push) Failing after 8s
chart: Add support for Gateway API HTTPRoute
2025-10-24 12:50:27 +01:00
Stefan Prodan
6a069aed1a chart: Add support for Gateway API HTTPRoute
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-10-24 14:43:05 +03:00
Stefan Prodan
bca20328fb Merge pull request #420 from stefanprodan/dependabot/github_actions/actions-6d9da201ab
Some checks failed
cve-scan / govulncheck (push) Failing after 20s
e2e / kind-helm (push) Failing after 21s
e2e / kind-timoni (push) Failing after 11s
test / test (push) Failing after 22s
build(deps): bump fluxcd/flux2 from 2.6.4 to 2.7.0 in the actions group
2025-10-16 00:30:49 +03:00
dependabot[bot]
d81ac93a8a build(deps): bump fluxcd/flux2 from 2.6.4 to 2.7.0 in the actions group
Bumps the actions group with 1 update: [fluxcd/flux2](https://github.com/fluxcd/flux2).


Updates `fluxcd/flux2` from 2.6.4 to 2.7.0
- [Release notes](https://github.com/fluxcd/flux2/releases)
- [Changelog](https://github.com/fluxcd/flux2/blob/main/.goreleaser.yml)
- [Commits](https://github.com/fluxcd/flux2/compare/v2.6.4...v2.7.0)

---
updated-dependencies:
- dependency-name: fluxcd/flux2
  dependency-version: 2.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-15 21:23:11 +00:00
Stefan Prodan
71fc0d8096 Merge pull request #423 from stefanprodan/chart-updates
chart: Update redis image and allow pull secrets
2025-10-16 00:21:25 +03:00
Stefan Prodan
81654006ee chart: Update redis image and allow pull secrets
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-10-16 00:17:07 +03:00
Stefan Prodan
c74b0d4ccb Merge pull request #422 from stefanprodan/update-deps-chart
Update Go dependencies
2025-10-16 00:16:57 +03:00
Stefan Prodan
e335313b04 Update Go dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-10-16 00:06:37 +03:00
Stefan Prodan
ca375ee533 Merge pull request #421 from sicko583/enable-imagepullsecrets-for-deployments
enable imagepullsecrets for better image pull
2025-10-15 23:55:46 +03:00
lincheng.zhong
d8e8054876 enable imagepullsecrets for better image pull 2025-10-15 20:09:50 +08:00
Stefan Prodan
e86405a867 Merge pull request #417 from stefanprodan/release-6.9.2
Some checks failed
test / test (push) Failing after 26s
cve-scan / govulncheck (push) Failing after 38s
e2e / kind-helm (push) Failing after 25s
e2e / kind-timoni (push) Failing after 17s
Release 6.9.2
2025-09-10 23:09:01 +03:00
Stefan Prodan
a51de59edb Release 6.9.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-10 23:06:10 +03:00
Stefan Prodan
1ff6fff334 Merge pull request #416 from stefanprodan/go-1.25
Build with Go 1.25
2025-09-10 23:04:21 +03:00
Stefan Prodan
98e8cd39d4 Build with Go 1.25
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-10 22:51:09 +03:00
Stefan Prodan
65b9e92db3 Merge pull request #414 from stefanprodan/dependabot/github_actions/actions-b5ac1ad0b0
build(deps): bump the actions group across 1 directory with 3 updates
2025-09-10 22:45:04 +03:00
dependabot[bot]
c6536c75ce build(deps): bump the actions group across 1 directory with 3 updates
Bumps the actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [stefanprodan/timoni](https://github.com/stefanprodan/timoni) and [actions/setup-go](https://github.com/actions/setup-go).


Updates `actions/checkout` from 4 to 5
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

Updates `stefanprodan/timoni` from 0.25.1 to 0.25.2
- [Release notes](https://github.com/stefanprodan/timoni/releases)
- [Changelog](https://github.com/stefanprodan/timoni/blob/main/.goreleaser.yml)
- [Commits](https://github.com/stefanprodan/timoni/compare/v0.25.1...v0.25.2)

Updates `actions/setup-go` from 5 to 6
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: stefanprodan/timoni
  dependency-version: 0.25.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-10 19:29:40 +00:00
Stefan Prodan
3c4910d1c7 Merge pull request #415 from stefanprodan/fix-chart-values-prod
chart: Fix values-prod standalone use-case
2025-09-10 22:27:03 +03:00
Stefan Prodan
c831679d1e chart: Fix values-prod standalone use-case
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-10 21:18:04 +03:00
Stefan Prodan
94a9f99f79 Merge pull request #412 from stefanprodan/dependabot/go_modules/github.com/go-viper/mapstructure/v2-2.4.0
Some checks failed
cve-scan / govulncheck (push) Successful in 12m34s
e2e / kind-helm (push) Failing after 1m38s
e2e / kind-timoni (push) Failing after 10s
test / test (push) Failing after 5m32s
build(deps): bump github.com/go-viper/mapstructure/v2 from 2.3.0 to 2.4.0
2025-08-22 12:27:47 +03:00
dependabot[bot]
86ac641693 build(deps): bump github.com/go-viper/mapstructure/v2
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 15:28:33 +00:00
Stefan Prodan
cdd09cdd3d Merge pull request #408 from stefanprodan/release-6.9.1
Some checks failed
cve-scan / govulncheck (push) Successful in 13m6s
e2e / kind-helm (push) Failing after 1m46s
e2e / kind-timoni (push) Failing after 18s
test / test (push) Failing after 6m5s
Release 6.9.1
2025-07-12 14:07:13 +03:00
Stefan Prodan
0b8a7dace7 Release 6.9.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-12 14:03:55 +03:00
Stefan Prodan
e50f88a43d Merge pull request #404 from stefanprodan/dependabot/github_actions/actions-1b82273ac1
build(deps): bump fluxcd/flux2 from 2.6.1 to 2.6.4 in the actions group
2025-07-12 14:02:14 +03:00
dependabot[bot]
67e4628d95 build(deps): bump fluxcd/flux2 from 2.6.1 to 2.6.2 in the actions group
Bumps the actions group with 1 update: [fluxcd/flux2](https://github.com/fluxcd/flux2).


Updates `fluxcd/flux2` from 2.6.1 to 2.6.2
- [Release notes](https://github.com/fluxcd/flux2/releases)
- [Changelog](https://github.com/fluxcd/flux2/blob/main/.goreleaser.yml)
- [Commits](https://github.com/fluxcd/flux2/compare/v2.6.1...v2.6.2)

---
updated-dependencies:
- dependency-name: fluxcd/flux2
  dependency-version: 2.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-12 10:59:20 +00:00
Stefan Prodan
73f5e936c8 Merge pull request #407 from stefanprodan/deps-update
Update dependencies
2025-07-12 13:57:04 +03:00
Stefan Prodan
0e26c3b934 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-12 13:39:00 +03:00
Stefan Prodan
dc39bd9a08 Update Alpine to 3.22
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-12 13:06:56 +03:00
Stefan Prodan
c23d57a4e9 Merge pull request #403 from stefanprodan/dependabot/github_actions/actions-45b07363df
Some checks failed
cve-scan / govulncheck (push) Successful in 12m38s
e2e / kind-helm (push) Failing after 1m36s
e2e / kind-timoni (push) Failing after 19s
test / test (push) Failing after 5m41s
build(deps): bump stefanprodan/timoni from 0.25.0 to 0.25.1 in the actions group
2025-06-16 09:41:56 +03:00
dependabot[bot]
85d22b2172 build(deps): bump stefanprodan/timoni in the actions group
Bumps the actions group with 1 update: [stefanprodan/timoni](https://github.com/stefanprodan/timoni).


Updates `stefanprodan/timoni` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/stefanprodan/timoni/releases)
- [Changelog](https://github.com/stefanprodan/timoni/blob/main/.goreleaser.yml)
- [Commits](https://github.com/stefanprodan/timoni/compare/v0.25.0...v0.25.1)

---
updated-dependencies:
- dependency-name: stefanprodan/timoni
  dependency-version: 0.25.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 06:36:33 +00:00
Stefan Prodan
ff906f2242 Merge pull request #402 from benoittgt/prevent-warning
Some checks failed
cve-scan / govulncheck (push) Successful in 14m42s
e2e / kind-helm (push) Failing after 1m32s
e2e / kind-timoni (push) Failing after 11s
test / test (push) Failing after 5m52s
Prevent warning with `docker buildx build` command
2025-06-12 22:46:33 +03:00
Benoit Tigeot
2dbf735c46 Prevent warning with docker buildx build command
Without this patch
```
 1 warning found (use docker --debug to expand):
 - FromAsCasing: 'as' and 'FROM' keywords' casing do not match (line 1)
```
2025-06-12 21:22:51 +02:00
Stefan Prodan
1318243ec9 Merge pull request #400 from stefanprodan/dependabot/github_actions/actions-d190f23e0c
Some checks failed
cve-scan / govulncheck (push) Successful in 12m56s
e2e / kind-helm (push) Failing after 1m52s
e2e / kind-timoni (push) Failing after 19s
test / test (push) Failing after 5m44s
build(deps): bump the actions group with 2 updates
2025-06-02 10:55:18 +03:00
dependabot[bot]
12e7f14ff0 build(deps): bump the actions group with 2 updates
Bumps the actions group with 2 updates: [fluxcd/flux2](https://github.com/fluxcd/flux2) and [stefanprodan/timoni](https://github.com/stefanprodan/timoni).


Updates `fluxcd/flux2` from 2.5.1 to 2.6.1
- [Release notes](https://github.com/fluxcd/flux2/releases)
- [Changelog](https://github.com/fluxcd/flux2/blob/main/.goreleaser.yml)
- [Commits](https://github.com/fluxcd/flux2/compare/v2.5.1...v2.6.1)

Updates `stefanprodan/timoni` from 0.24.0 to 0.25.0
- [Release notes](https://github.com/stefanprodan/timoni/releases)
- [Changelog](https://github.com/stefanprodan/timoni/blob/main/.goreleaser.yml)
- [Commits](https://github.com/stefanprodan/timoni/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: fluxcd/flux2
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: stefanprodan/timoni
  dependency-version: 0.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 07:47:48 +00:00
Stefan Prodan
fb3b01be30 Merge pull request #399 from stefanprodan/release-6.9.0
Some checks failed
cve-scan / govulncheck (push) Successful in 3m56s
e2e / kind-helm (push) Failing after 3m5s
e2e / kind-timoni (push) Failing after 10s
test / test (push) Failing after 1m17s
Release 6.9.0
2025-05-15 12:33:58 +03:00
Stefan Prodan
be955e76b0 Release 6.9.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-15 12:13:20 +03:00
Stefan Prodan
3e79d79447 Merge pull request #398 from stefanprodan/govulncheck
Run CVE scan with govulncheck
2025-05-15 11:25:02 +03:00
Stefan Prodan
cd555cf439 Run CVE scan with govulncheck
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-15 09:35:42 +03:00
Stefan Prodan
2927336ecd Merge pull request #397 from stefanprodan/dependabot/github_actions/actions-7f661cc7ed
build(deps): bump the actions group with 6 updates
2025-05-15 09:25:47 +03:00
dependabot[bot]
8f5425b6d5 build(deps): bump the actions group with 6 updates
Bumps the actions group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `3` | `4` |
| [helm/kind-action](https://github.com/helm/kind-action) | `1.10.0` | `1.12.0` |
| [azure/setup-helm](https://github.com/azure/setup-helm) | `3` | `4` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `5` | `6` |
| [azure/setup-kubectl](https://github.com/azure/setup-kubectl) | `3` | `4` |
| [cue-lang/setup-cue](https://github.com/cue-lang/setup-cue) | `1.0.0` | `1.0.1` |


Updates `actions/checkout` from 3 to 4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

Updates `helm/kind-action` from 1.10.0 to 1.12.0
- [Release notes](https://github.com/helm/kind-action/releases)
- [Commits](https://github.com/helm/kind-action/compare/v1.10.0...v1.12.0)

Updates `azure/setup-helm` from 3 to 4
- [Release notes](https://github.com/azure/setup-helm/releases)
- [Changelog](https://github.com/Azure/setup-helm/blob/main/CHANGELOG.md)
- [Commits](https://github.com/azure/setup-helm/compare/v3...v4)

Updates `docker/build-push-action` from 5 to 6
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

Updates `azure/setup-kubectl` from 3 to 4
- [Release notes](https://github.com/azure/setup-kubectl/releases)
- [Changelog](https://github.com/Azure/setup-kubectl/blob/main/CHANGELOG.md)
- [Commits](https://github.com/azure/setup-kubectl/compare/v3...v4)

Updates `cue-lang/setup-cue` from 1.0.0 to 1.0.1
- [Release notes](https://github.com/cue-lang/setup-cue/releases)
- [Commits](https://github.com/cue-lang/setup-cue/compare/v1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: helm/kind-action
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: azure/setup-helm
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/build-push-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: azure/setup-kubectl
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: cue-lang/setup-cue
  dependency-version: 1.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-14 22:36:04 +00:00
Stefan Prodan
1cd88028c7 Merge pull request #396 from stefanprodan/enable-dependabot
Some checks failed
cve-scan / trivy (push) Failing after 33s
e2e / kind-helm (push) Failing after 2m55s
e2e / kind-timoni (push) Failing after 15s
test / test (push) Failing after 1m21s
Enable dependabot
2025-05-15 01:34:30 +03:00
Stefan Prodan
ca101e6728 Enable dependabot
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-15 01:28:59 +03:00
Stefan Prodan
c8419e386a Merge pull request #395 from stefanprodan/update-deps
Update dependencies
2025-05-15 01:01:54 +03:00
Stefan Prodan
9356c1c0c4 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-15 00:52:02 +03:00
Stefan Prodan
60b5e4c4fe Merge pull request #394 from mkilchhofer/feature/add_namespace_and_namespaceoverride
feat(helm): Add namespace field to all resources
2025-05-15 00:31:33 +03:00
Marco Maurer
322b71c1e5 feat(helm): Add namespace field to all resources
Signed-off-by: Marco Maurer <mkilchhofer@users.noreply.github.com>
2025-05-14 19:41:49 +02:00
Stefan Prodan
b3396adb98 Merge pull request #390 from stefanprodan/release-6.8.0
Some checks failed
cve-scan / trivy (push) Has been cancelled
e2e / kind-helm (push) Has been cancelled
e2e / kind-timoni (push) Has been cancelled
test / test (push) Has been cancelled
Release v6.8.0
2025-03-11 11:27:59 +02:00
Stefan Prodan
c6e70a7aa0 Release v6.8.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-03-11 11:23:55 +02:00
Stefan Prodan
6810566623 Merge pull request #389 from stefanprodan/go-1.24
Build with Go 1.24
2025-03-11 11:17:38 +02:00
Stefan Prodan
8efcd73510 Build with Go 1.24
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-03-11 11:13:59 +02:00
Stefan Prodan
eb81ed6ed2 Merge pull request #384 from stefanprodan/update-go-deps
Update dependencies
2025-03-11 11:08:46 +02:00
Stefan Prodan
916f1a298a Merge pull request #388 from hansbogert/master
feat(logging): add trace_id to http request debug logs
2025-03-11 11:03:16 +02:00
Hans van den Bogert
7cc399463c feat(logging): add trace_id to debug log line
... if exists in context
2025-03-10 21:48:25 +01:00
Stefan Prodan
78755636d0 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-01-14 00:09:32 +02:00
Stefan Prodan
b99bf8c252 Merge pull request #382 from cthtrifork/feature/podSecurityContext
Some checks failed
cve-scan / trivy (push) Failing after 9m22s
e2e / kind-helm (push) Failing after 1m14s
e2e / kind-timoni (push) Failing after 13s
test / test (push) Failing after 5m29s
Added support for podSecurityContext in helm chart
2024-11-14 12:19:48 +02:00
Casper Thygesen
e7928cfbc7 update chart readme 2024-11-14 10:45:13 +01:00
Stefan Prodan
dc5d3d559e Merge pull request #381 from stefanprodan/dependabot/go_modules/github.com/golang-jwt/jwt/v4-4.5.1
build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1
2024-11-14 11:40:24 +02:00
Casper Thygesen
71f618320e Added support for podSecurityContext in helm chart 2024-11-13 20:36:29 +01:00
dependabot[bot]
c4e601b4cb build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1
Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 23:45:18 +00:00
Stefan Prodan
6b7aab8a10 Merge pull request #378 from stefanprodan/release-6.7.1
Some checks failed
cve-scan / trivy (push) Successful in 6m54s
e2e / kind-helm (push) Failing after 58s
e2e / kind-timoni (push) Failing after 6s
test / test (push) Failing after 5m15s
Release 6.7.1
2024-10-08 11:58:16 +03:00
Stefan Prodan
b7d3d71d8f Release 6.7.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-10-07 16:02:31 +03:00
Stefan Prodan
abcd272293 Merge pull request #377 from stefanprodan/go-1.23
Some checks failed
cve-scan / trivy (push) Successful in 9m22s
e2e / kind-helm (push) Failing after 2m38s
e2e / kind-timoni (push) Failing after 11s
test / test (push) Failing after 6m17s
Build with Go 1.23
2024-10-07 15:59:08 +03:00
Stefan Prodan
4af7854aa2 Bump Go to 1.23
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-10-07 15:56:05 +03:00
Stefan Prodan
fc1e4a48ed Build with Go 1.23
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-10-07 15:50:27 +03:00
Stefan Prodan
08238eada7 Merge pull request #375 from stefanprodan/dependabot/go_modules/google.golang.org/grpc-1.64.1
Some checks failed
e2e / kind-timoni (push) Failing after 4s
cve-scan / trivy (push) Successful in 1m27s
e2e / kind-helm (push) Failing after 3m8s
test / test (push) Failing after 5m38s
build(deps): bump google.golang.org/grpc from 1.64.0 to 1.64.1
2024-07-12 14:59:26 +03:00
dependabot[bot]
892a66ea93 build(deps): bump google.golang.org/grpc from 1.64.0 to 1.64.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.64.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-09 21:44:38 +00:00
Stefan Prodan
0b1481aa8e Merge pull request #374 from stefanprodan/release-6.7.0
Release v6.7.0
2024-06-23 21:28:13 +03:00
Stefan Prodan
ff32a1fc4b Release v6.7.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-06-23 21:25:38 +03:00
Stefan Prodan
3de84d2360 Merge pull request #373 from stefanprodan/up-go-deps
Update dependencies
2024-06-23 21:24:35 +03:00
Stefan Prodan
ba6f4ffd7c Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-06-23 21:21:39 +03:00
Stefan Prodan
6d4405a1ef Run tidy before testing
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-06-23 21:21:25 +03:00
Stefan Prodan
752950cb4f Merge pull request #369 from Prashant-Dwivedi-08-01/grpc_APIs
GRPC Apis for Corresponding HTTP APIs
2024-06-23 21:13:19 +03:00
Prashant Dwivedi
b10c3067c8 Removed the whitespaces
Signed-off-by: Prashant Dwivedi <prashantdwivedi194@gmail.com>
2024-06-23 22:47:58 +05:30
Prashant Dwivedi
85cd1c46d4 Removed unnecessary comments and whitespaces
Signed-off-by: Prashant Dwivedi <prashantdwivedi194@gmail.com>
2024-06-23 21:59:50 +05:30
Prashant Dwivedi
2687a13c75 Merge branch 'stefanprodan:master' into grpc_APIs 2024-06-23 20:46:38 +05:30
Stefan Prodan
5fb6597929 Merge pull request #372 from stefanprodan/set-cue-version
Set CUE version in Timoni module
2024-06-23 15:09:43 +03:00
Stefan Prodan
1fbdd9420f Set CUE version in Timoni module
Adapt module to cope with breaking changes in CUE v0.9

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-06-23 15:07:18 +03:00
Prashant Dwivedi
30cd3b27d7 Added description for all the gRPC APIs in README file
Signed-off-by: Prashant Dwivedi <prashantdwivedi194@gmail.com>
2024-06-23 11:13:01 +05:30
Stefan Prodan
1d7de0bb82 Merge pull request #370 from maxbrunet/fix/deploy/cache-server-url
fix(deploy): add protocol to Redis URL
2024-06-15 00:28:42 +03:00
Maxime Brunet
c52654c59e fix(deploy): add protocol to Redis URL 2024-06-14 12:10:17 -07:00
Prashant Dwivedi
1a6838a4a2 Merge branch 'master' of github.com:Prashant-Dwivedi-08-01/podinfo into grpc_APIs 2024-06-07 20:27:13 +05:30
Stefan Prodan
b0c487c6b2 Merge pull request #367 from stefanprodan/release-6.6.3
Release v6.6.3
2024-05-23 11:34:11 +03:00
Stefan Prodan
b28069ac51 Release v6.6.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-05-23 11:30:18 +03:00
Stefan Prodan
d8a136cf74 Merge pull request #366 from stefanprodan/up-deps-otel
Update opentelemetry dependencies
2024-05-23 11:28:58 +03:00
Stefan Prodan
614f74f6df Update opentelemetry dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-05-23 11:25:26 +03:00
Stefan Prodan
0c4f327390 Merge pull request #365 from stefanprodan/alpine-3.20
Update Alpine to 3.20
2024-05-23 11:22:24 +03:00
Stefan Prodan
d791dedb24 Update Alpine to 3.20
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-05-23 11:19:15 +03:00
Stefan Prodan
220d4e909c Merge pull request #364 from rodrigorfk/fix-ws-panic
fix: panic when the WebSocket endpoint is under load
2024-05-23 11:17:11 +03:00
Rodrigo Fior Kuntzer
eba7fe186e fix: panic when the WebSocket endpoint is under load 2024-05-23 10:01:01 +02:00
Prashant Dwivedi
9108833214 Added the token Validate api and updated the test for it 2024-05-09 12:56:54 +05:30
Prashant Dwivedi
386ceb09be Added the grpc APIs for the remaining HTTP apis 2024-05-08 00:25:37 +05:30
Stefan Prodan
f350624047 Merge pull request #356 from needsure/master
chore: fix some typos in comments
2024-04-28 14:07:49 +03:00
Stefan Prodan
37ba3e854f Merge pull request #361 from stefanprodan/dependabot/go_modules/golang.org/x/net-0.23.0
build(deps): bump golang.org/x/net from 0.22.0 to 0.23.0
2024-04-19 17:17:36 +03:00
dependabot[bot]
70335812c6 build(deps): bump golang.org/x/net from 0.22.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 13:23:50 +00:00
Stefan Prodan
8d010c498e Merge pull request #357 from stefanprodan/release-6.6.2
Release v6.6.2
2024-04-10 14:04:54 +03:00
Stefan Prodan
8b3079a417 Release v6.6.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-04-10 14:01:43 +03:00
needsure
37fa020bcd chore: fix some typos in conments
Signed-off-by: needsure <qinzhipeng@outlook.com>
2024-04-09 16:45:31 +08:00
Stefan Prodan
d879d0f4fb Merge pull request #336 from michaelkebe/remove-localhost
Removed reference to localhost from swagger
2024-04-09 10:14:32 +03:00
Michael Kebe
16191504d1 Removed reference to localhost from swagger
Now it is possible to use the swagger webinterface
running on a host other than localhost e.g. in docker
or kubernetes.

Removed the @host line from pkg/api/server.go and
ran make swagger.

Fixes probably #179
2024-04-09 08:54:38 +02:00
Stefan Prodan
d042732a44 Merge pull request #353 from stefanprodan/release-6.6.1
Release v6.6.1
2024-03-27 15:56:20 +02:00
Stefan Prodan
649864583b Release v6.6.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-03-27 15:36:51 +02:00
Stefan Prodan
c07eb64558 Merge pull request #352 from stefanprodan/go-1.22
Update dependencies to Go 1.22
2024-03-26 14:23:19 +02:00
Stefan Prodan
44942884c3 Update dependencies to Go 1.22
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-03-26 14:19:26 +02:00
Stefan Prodan
d562a2a82a Merge pull request #344 from toyamagu-2021/feat-allow-input-config-and-extraArgs
feat(chart): allow input config and extraArgs
2024-03-26 09:00:43 +02:00
toyamagu2021
d7c1bf015c feat(chart): allow input config and extraArgs
Signed-off-by: toyamagu2021 <toyamagu2021@gmail.com>
2024-03-26 09:28:44 +09:00
Stefan Prodan
cdec0786ef Merge pull request #347 from eltociear/patch-1
Update README.md
2024-03-25 10:14:24 +02:00
Stefan Prodan
e6d611e1e2 Merge pull request #349 from mustafakarci/feature/extraEnv
feature(chart): allow extraEnvs to be parst
2024-03-25 10:14:01 +02:00
Mustafa Karci
36bea810ef feature(chart): allow extraEnvs to be parst 2024-03-20 12:28:40 +01:00
Stefan Prodan
50047dab3a Merge pull request #348 from stefanprodan/dependabot/go_modules/google.golang.org/protobuf-1.33.0
build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0
2024-03-14 10:36:40 +02:00
dependabot[bot]
2b936e6700 build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 23:03:41 +00:00
Ikko Eltociear Ashimine
55e4e51eba Update README.md
Github -> GitHub
2024-03-06 00:27:17 +09:00
Stefan Prodan
47090ad9e1 Merge pull request #331 from the-technat/master
feat(helm): add topologySpreadConstraints and PDB
2024-02-28 08:58:04 +00:00
Nathanael Liechti
6a0bbda8a5 feat(helm): add topologySpreadConstraints and PDB 2024-02-26 20:54:29 +00:00
Stefan Prodan
357009a863 Sign only GHCR artifacts with Notation
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-02-26 14:00:22 +02:00
Stefan Prodan
0f98770296 Split signature actions
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-02-26 13:27:46 +02:00
Stefan Prodan
f9032836a6 Merge pull request #343 from stefanprodan/release-6.6.0
Release v6.6.0
2024-02-26 12:17:54 +02:00
Stefan Prodan
5368c3fe10 Release v6.6.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-02-26 12:15:05 +02:00
Stefan Prodan
b1207aa9b1 Merge pull request #341 from JasonTheDeveloper/feat/notation
feat(notation): sign artifacts using notation
2024-02-26 11:58:49 +02:00
Jason
c7f9b521fa ci(notation): install 1.1.0
Signed-off-by: Jason <jagoodse@microsoft.com>
2024-02-26 20:40:03 +11:00
Stefan Prodan
24405a5a5d Setup notation signing keys
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2024-02-25 12:12:22 +02:00
Stefan Prodan
5195b158fc Merge pull request #334 from michaelkebe/patch-1
Fixes /store endpoint with the kustomize deployment
2024-02-25 11:31:44 +02:00
Stefan Prodan
532db405f8 Merge pull request #322 from JayKaku/feature/grpc-version-echo-apis
Implement gRPC for `echo` and `version` APIs
2024-02-25 11:30:59 +02:00
JayKaku
2251bee699 Fixed parsing logger in echo_test.go service registeration 2024-02-24 23:44:12 +05:30
JayKaku
8535efccb7 Implemented zap logger in place of log | gprc echo 2024-02-24 23:44:12 +05:30
JayKaku
e008d1f261 Added config, logger for grpc echo api 2024-02-24 23:44:12 +05:30
Jay Kaku
22097353d2 Feature grpc version echo api (#3)
added grpc verion and echo apis

---------

Co-authored-by: Prashant Dwivedi <prashantdwivedi194@gmail.com>
2024-02-24 23:44:12 +05:30
JayKaku
c305843105 restructured api to api/http, api/grpc, pkg http 2024-02-24 23:44:12 +05:30
Michael Kebe
2d80c7a22d added /data to kustomize deployment
Added an emptyDir to the kustomzie deployment, otherwise the /store endpoint does not work for storing files.
2024-01-10 09:44:12 +01:00
141 changed files with 4957 additions and 638 deletions

View File

@@ -1,6 +0,0 @@
FROM stefanprodan/alpine-base:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -1,9 +0,0 @@
name: 'github-release-notes'
description: 'A GitHub Action to run github-release-notes commands'
author: 'Stefan Prodan'
branding:
icon: 'command'
color: 'blue'
runs:
using: 'docker'
image: 'Dockerfile'

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
VERSION=0.2.0
BIN_DIR="$GITHUB_WORKSPACE/bin"
main() {
mkdir -p ${BIN_DIR}
tmpDir=$(mktemp -d)
pushd $tmpDir >& /dev/null
curl -sSL https://github.com/buchanae/github-release-notes/releases/download/${VERSION}/github-release-notes-linux-amd64-${VERSION}.tar.gz | tar xz
cp github-release-notes ${BIN_DIR}/github-release-notes
popd >& /dev/null
rm -rf $tmpDir
}
main
echo "$BIN_DIR" >> $GITHUB_PATH
echo "$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin" >> $GITHUB_PATH

11
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
groups:
actions:
patterns:
- "*"
schedule:
interval: "weekly"

View File

@@ -1,31 +1,23 @@
name: cve-scan name: cve-scan
on: on:
workflow_dispatch:
push: push:
branches: branches:
- "master" - "master"
pull_request:
branches:
- "master"
permissions: permissions:
contents: read contents: read
jobs: jobs:
trivy: govulncheck:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v5
- name: Build image - name: Vulnerability scan
id: build id: govulncheck
run: | uses: golang/govulncheck-action@v1
IMAGE=test/podinfo:${GITHUB_SHA}
docker build -t ${IMAGE} .
echo "image=$IMAGE" >> $GITHUB_OUTPUT
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.build.outputs.image }}
format: table
exit-code: "1"
ignore-unfixed: true
vuln-type: os,library
severity: CRITICAL,HIGH

View File

@@ -14,20 +14,19 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@v1.8.0 uses: helm/kind-action@v1.13.0
with: with:
version: v0.20.0
cluster_name: kind cluster_name: kind
- name: Build container image - name: Build container image
run: | run: |
./test/build.sh ./test/build.sh
kind load docker-image test/podinfo:latest kind load docker-image test/podinfo:latest
- name: Setup Helm - name: Setup Helm
uses: azure/setup-helm@v3 uses: azure/setup-helm@v4
with: with:
version: v3.12.3 version: v3.17.3
- name: Deploy - name: Deploy
run: ./test/deploy.sh run: ./test/deploy.sh
- name: Run integration tests - name: Run integration tests
@@ -49,13 +48,12 @@ jobs:
PODINFO_VERSION: "0.0.0-devel" PODINFO_VERSION: "0.0.0-devel"
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Setup Timoni - name: Setup Timoni
uses: stefanprodan/timoni/actions/setup@main uses: stefanprodan/timoni/actions/setup@main
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@v1.8.0 uses: helm/kind-action@v1.13.0
with: with:
version: v0.20.0
cluster_name: kind cluster_name: kind
- name: Build container - name: Build container
run: | run: |

View File

@@ -16,14 +16,14 @@ jobs:
id-token: write # needed for keyless signing id-token: write # needed for keyless signing
packages: write # needed for ghcr access packages: write # needed for ghcr access
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: sigstore/cosign-installer@v3 - uses: sigstore/cosign-installer@v3
- uses: fluxcd/flux2/action@main - uses: fluxcd/flux2/action@v2.7.3
- uses: stefanprodan/timoni/actions/setup@main - uses: stefanprodan/timoni/actions/setup@v0.25.2
- name: Setup Notation CLI - name: Setup Notation CLI
uses: notaryproject/notation-action/setup@v1 uses: notaryproject/notation-action/setup@v1
with: with:
version: "1.0.0" version: "1.1.0"
- name: Setup Notation signing keys - name: Setup Notation signing keys
run: | run: |
mkdir -p ~/.config/notation/localkeys/ mkdir -p ~/.config/notation/localkeys/
@@ -33,13 +33,13 @@ jobs:
env: env:
NOTATION_KEY: ${{ secrets.NOTATION_SIGNING_KEY }} NOTATION_KEY: ${{ secrets.NOTATION_SIGNING_KEY }}
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v4 uses: actions/setup-go@v6
with: with:
go-version: 1.21.x go-version: 1.25.x
- name: Setup Helm - name: Setup Helm
uses: azure/setup-helm@v3 uses: azure/setup-helm@v4
with: with:
version: v3.12.3 version: v3.17.3
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3
with: with:
@@ -79,7 +79,7 @@ jobs:
type=raw,value=${{ steps.prep.outputs.VERSION }} type=raw,value=${{ steps.prep.outputs.VERSION }}
type=raw,value=latest type=raw,value=latest
- name: Publish multi-arch image - name: Publish multi-arch image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v6
with: with:
sbom: true sbom: true
provenance: true provenance: true
@@ -113,7 +113,7 @@ jobs:
--source="${{ github.event.repository.html_url }}" \ --source="${{ github.event.repository.html_url }}" \
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}" --revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
flux tag artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --tag latest flux tag artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --tag latest
- name: Sign OCI artifacts - name: Sign artifacts with Cosign
env: env:
COSIGN_EXPERIMENTAL: 1 COSIGN_EXPERIMENTAL: 1
run: | run: |
@@ -121,12 +121,8 @@ jobs:
cosign sign ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }} --yes cosign sign ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }} --yes
cosign sign ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }} --yes cosign sign ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }} --yes
cosign sign ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --yes cosign sign ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --yes
notation sign --signature-format cose docker.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }}
- name: Publish base image - name: Publish base image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v6
with: with:
push: true push: true
builder: ${{ steps.buildx.outputs.name }} builder: ${{ steps.buildx.outputs.name }}
@@ -145,25 +141,25 @@ jobs:
--source="${{ github.event.repository.html_url }}" \ --source="${{ github.event.repository.html_url }}" \
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}" --revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
flux tag artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --tag latest flux tag artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --tag latest
- name: Sign config artifact - name: Sign config artifact with cso
run: | run: |
echo "$COSIGN_KEY" > /tmp/cosign.key echo "$COSIGN_KEY" > /tmp/cosign.key
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --yes cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --yes
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:latest --yes cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:latest --yes
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:latest
env: env:
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
COSIGN_KEY: ${{secrets.COSIGN_KEY}} COSIGN_KEY: ${{secrets.COSIGN_KEY}}
- uses: ./.github/actions/release-notes - name: Sign artifacts with Notation
- name: Generate release notes
run: | run: |
echo 'CHANGELOG' > /tmp/release.txt notation sign --signature-format cose ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
github-release-notes -org stefanprodan -repo podinfo -since-latest-release >> /tmp/release.txt notation sign --signature-format cose ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }}
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:latest
- name: Publish release - name: Publish release
uses: goreleaser/goreleaser-action@v5 uses: goreleaser/goreleaser-action@v6
with: with:
version: latest version: latest
args: release --release-notes=/tmp/release.txt --skip-validate args: release --skip=validate
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -10,35 +10,36 @@ permissions:
contents: read contents: read
env: env:
KUBERNETES_VERSION: 1.26.0 KUBERNETES_VERSION: 1.31.0
HELM_VERSION: 3.17.3
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v4 uses: actions/setup-go@v6
with: with:
go-version: 1.21.x go-version: 1.25.x
cache-dependency-path: | cache-dependency-path: |
**/go.sum **/go.sum
**/go.mod **/go.mod
- name: Setup kubectl - name: Setup kubectl
uses: azure/setup-kubectl@v3 uses: azure/setup-kubectl@v4
with: with:
version: v${{ env.KUBERNETES_VERSION }} version: v${{ env.KUBERNETES_VERSION }}
- name: Setup kubeconform - name: Setup kubeconform
uses: ./.github/actions/kubeconform uses: ./.github/actions/kubeconform
- name: Setup Helm - name: Setup Helm
uses: azure/setup-helm@v3 uses: azure/setup-helm@v4
with: with:
version: v3.10.3 version: v${{ env.HELM_VERSION }}
- name: Setup CUE - name: Setup CUE
uses: cue-lang/setup-cue@v1.0.0 uses: cue-lang/setup-cue@v1.0.1
- name: Setup Timoni - name: Setup Timoni
uses: stefanprodan/timoni/actions/setup@main uses: stefanprodan/timoni/actions/setup@v0.25.2
- name: Run unit tests - name: Run unit tests
run: make test run: make test
- name: Validate Helm chart - name: Validate Helm chart
@@ -51,7 +52,7 @@ jobs:
- name: Verify CUE formatting - name: Verify CUE formatting
working-directory: ./timoni/podinfo working-directory: ./timoni/podinfo
run: | run: |
cue fmt ./.. cue fmt ./...
status=$(git status . --porcelain) status=$(git status . --porcelain)
[[ -z "$status" ]] || { [[ -z "$status" ]] || {
echo "CUE files are not correctly formatted" echo "CUE files are not correctly formatted"

3
.gitignore vendored
View File

@@ -23,3 +23,6 @@ bin/
cue/cue.mod/gen/ cue/cue.mod/gen/
cue/go.mod cue/go.mod
cue/go.sum cue/go.sum
.notation/podinfo.csr
.notation/podinfo.key

View File

@@ -1,3 +1,18 @@
version: 2
# xref: https://goreleaser.com/customization/project/
project_name: podinfo
# xref: https://goreleaser.com/customization/hooks/
before:
hooks:
- go mod download
# xref: https://goreleaser.com/customization/env/
env:
- CGO_ENABLED=0
# xref: https://goreleaser.com/customization/build/
builds: builds:
- main: ./cmd/podcli - main: ./cmd/podcli
binary: podcli binary: podcli
@@ -8,9 +23,13 @@ builds:
- linux - linux
goarch: goarch:
- amd64 - amd64
env:
- CGO_ENABLED=0 # xref: https://goreleaser.com/customization/archive/
archives: archives:
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files: files:
- none* - LICENSE
# xref: https://goreleaser.com/customization/changelog/
changelog:
use: github-native

15
.notation/README.md Normal file
View File

@@ -0,0 +1,15 @@
# Podinfo signed releases
Podinfo release assets such as the Helm chart and the Flux artifact
are published to GitHub Container Registry and are signed with
[Notation](https://github.com/notaryproject/notation).
## Generate signing keys
Generate a new signing key pair:
```sh
openssl genrsa -out podinfo.key 2048
openssl req -new -key podinfo.key -out podinfo.csr -config codesign.cnf
openssl x509 -req -days 1826 -in podinfo.csr -signkey podinfo.key -out notation.crt -extensions v3_req -extfile codesign.cnf
```

18
.notation/codesign.cnf Normal file
View File

@@ -0,0 +1,18 @@
[ req ]
default_bits = 2048
default_keyfile = privatekey.pem
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
C = RO
ST = BU
L = Bucharest
O = Notary
CN = stefanprodan.com
[ v3_req ]
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
#subjectKeyIdentifier = hash

View File

@@ -1,20 +1,21 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIUBk/7TYVIUsiCeUm5c11abfwMrZUwDQYJKoZIhvcNAQEL MIIDbDCCAlSgAwIBAgIUP7zhmTw5XTWLcgBGkBEsErMOkz4wDQYJKoZIhvcNAQEL
BQAwUTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0dGxl BQAwWjELMAkGA1UEBhMCUk8xCzAJBgNVBAgMAkJVMRIwEAYDVQQHDAlCdWNoYXJl
MQ8wDQYDVQQKDAZOb3RhcnkxEjAQBgNVBAMMCWZsdXhjZC5pbzAeFw0yMzEyMDcw c3QxDzANBgNVBAoMBk5vdGFyeTEZMBcGA1UEAwwQc3RlZmFucHJvZGFuLmNvbTAe
NDIwNDhaFw0yNDEyMDYwNDIwNDhaMFExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJX Fw0yNDAyMjUxMDAyMzZaFw0yOTAyMjQxMDAyMzZaMFoxCzAJBgNVBAYTAlJPMQsw
QTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwGTm90YXJ5MRIwEAYDVQQDDAlm CQYDVQQIDAJCVTESMBAGA1UEBwwJQnVjaGFyZXN0MQ8wDQYDVQQKDAZOb3Rhcnkx
bHV4Y2QuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx1hpkMmSD GTAXBgNVBAMMEHN0ZWZhbnByb2Rhbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
rlyjjL8UYaciLBmMtwbpFUcejDgKSSKAqHGtTPrzSHrza1oFybyjwkG7SlbR6k23 DwAwggEKAoIBAQDtH4oPi3SyX/DGv6NdjIvmApvD9eeSgsmHdwpAly8T9D2me+fx
fuWTIz7gVjx+rEmbnJuAnzhGCES4TY+dPO/svhuAT9iGVlJ4TKuPXFO53c+GKY+t Z+wRNJmq4aq/A1anX+Sg28iwHzV+1WKpsHnjYzDAJSEYP2S8A5H1nGRKUoibdijw
AJoWO04uzVbZsCNPlYmKoq3XvaMc3bnn2APr9xb7aHqF7LggqWe7GeKQEJvEdBYZ C3QBh5C75rjF/tmZVSX/Vgbf3HJJEsF4WUxWabLxoV2QLo7UlEsQd9+bSeKNMncx
m1KLKym6+pqnEDSPENUVGMYKQwQHNmpVz6y+HdvuR4AQxHrHGvDxo+G7GIjrDe8l 1+E6FdbRCrYo90iobvZJ8K/S2zCWq/JTeHfTnmSEDhx6nMJcaSjvMPn3zyauWcQw
cW4PurFAbv3yLLvpC4ZkppPLuVv7p0kUwy1sSeWVu7uxZ/MPGqI2HSMctDbAvGLj dDpkcaGiJ64fEJRT2OFxXv9u+vDmIMKzo/Wjbd+IzFj6YY4VisK88aU7tmDelnk5
bPY+rkVf3+4ZAgMBAAGjKjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAK gQB9eu62PFoaVsYJp4VOhblFKvGJpQwbWB9BAgMBAAGjKjAoMA4GA1UdDwEB/wQE
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAO2TSX5ewQXidW14UzhjNKTXt AwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEA
Yc8O6qMGNlv2PuCWT9k0ce6qC7s2XYAbvEWYNAS/fwdFC6cJMT/6/Y3s/zbFNrAH 6x+C6hAIbLwMvkNx4K5p7Qe/pLQR0VwQFAw10yr/5KSN+YKFpon6pQ0TebL7qll+
TMJTmGKZvtJnWywcCOg+HcRrLIpExJB1bAaTUW+oea9ABiitMeUEY6oiBGqacPeA uBGZvtQhN6v+DlnVqB7lvJKd+89isgirkkews5KwuXg7Gv5UPIugH0dXISZU8DMJ
4eVoDQ8wVS8oNHx71fmC9G6iNHaBTip3x81j0koz3JhHf1Mc3gKN56ww1RF/LMEa 7J4oKREv5HzdFmfsUfNlQcfyVTjKL6UINXfKGdqNNxXxR9b4a1TY2JcmEhzBTHaq
NW473dG/8pkuFOp6kuz775/EKBNuYfR6bEYx9zPNIpYAzVsveTnXTHsec3xkUoCQ ZqX6HK784a0dB7aHgeFrFwPCCP4M684Hs7CFbk3jo2Ef4ljnB5AyWpe8pwCLMdRt
xtfR15R8dfbvNFB1iFiew6oiBQ5Wz9abB0PU7b/pE21SjT1+lBKJ9xmMOzFwag== UjSjL5xJWVQvRU+STQsPr6SvpokPCG4rLQyjgeYYk4CCj5piSxbSUZFavq8v1y7Y
m91USVqfeUX7ZzjDxPHE2A==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@@ -1,8 +1,8 @@
{ {
"default": "fluxcd.io", "default": "stefanprodan.com",
"keys": [ "keys": [
{ {
"name": "fluxcd.io", "name": "stefanprodan.com",
"keyPath": "/home/runner/.config/notation/localkeys/notation.key", "keyPath": "/home/runner/.config/notation/localkeys/notation.key",
"certPath": "/home/runner/.config/notation/localkeys/notation.crt" "certPath": "/home/runner/.config/notation/localkeys/notation.crt"
} }

View File

@@ -2,7 +2,7 @@
"version": "1.0", "version": "1.0",
"trustPolicies": [ "trustPolicies": [
{ {
"name": "fluxcd.io", "name": "stefanprodan.com",
"registryScopes": [ "registryScopes": [
"ghcr.io/stefanprodan/podinfo-deploy", "ghcr.io/stefanprodan/podinfo-deploy",
"ghcr.io/stefanprodan/charts/podinfo" "ghcr.io/stefanprodan/charts/podinfo"
@@ -10,9 +10,9 @@
"signatureVerification": { "signatureVerification": {
"level" : "strict" "level" : "strict"
}, },
"trustStores": [ "ca:fluxcd.io" ], "trustStores": [ "ca:stefanprodan.com" ],
"trustedIdentities": [ "trustedIdentities": [
"x509.subject: C=US, ST=WA, L=Seattle, O=Notary, CN=fluxcd.io" "x509.subject: C=RO, ST=BU, L=Bucharest, O=Notary, CN=stefanprodan.com"
] ]
} }
] ]

View File

@@ -1,4 +1,4 @@
FROM golang:1.21-alpine as builder FROM golang:1.25-alpine AS builder
ARG REVISION ARG REVISION
@@ -18,7 +18,7 @@ RUN CGO_ENABLED=0 go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \ -X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-a -o bin/podcli cmd/podcli/* -a -o bin/podcli cmd/podcli/*
FROM alpine:3.19 FROM alpine:3.22
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION ARG VERSION

View File

@@ -1,4 +1,4 @@
FROM golang:1.21 FROM golang:1.25
WORKDIR /workspace WORKDIR /workspace

View File

@@ -1,5 +1,5 @@
ARG GO_VERSION=1.21 ARG GO_VERSION=1.25
ARG XX_VERSION=1.3.0 ARG XX_VERSION=1.6.1
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
@@ -28,7 +28,7 @@ RUN xx-go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \ -X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-a -o bin/podcli cmd/podcli/* -a -o bin/podcli cmd/podcli/*
FROM alpine:3.19 FROM alpine:3.22
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION ARG VERSION

View File

@@ -16,7 +16,7 @@ run:
--ui-logo=https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif $(EXTRA_RUN_ARGS) --ui-logo=https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif $(EXTRA_RUN_ARGS)
.PHONY: test .PHONY: test
test: test: tidy fmt vet
go test ./... -coverprofile cover.out go test ./... -coverprofile cover.out
build: build:
@@ -24,14 +24,13 @@ build:
GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podcli ./cmd/podcli/* GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podcli ./cmd/podcli/*
tidy: tidy:
rm -f go.sum; go mod tidy -compat=1.21 rm -f go.sum; go mod tidy -compat=1.25
vet: vet:
go vet ./... go vet ./...
fmt: fmt:
gofmt -l -s -w ./ go fmt ./...
goimports -l -w ./
build-charts: build-charts:
helm lint charts/* helm lint charts/*
@@ -93,7 +92,7 @@ swagger:
go install github.com/swaggo/swag/cmd/swag@latest go install github.com/swaggo/swag/cmd/swag@latest
go get github.com/swaggo/swag/gen@latest go get github.com/swaggo/swag/gen@latest
go get github.com/swaggo/swag/cmd/swag@latest go get github.com/swaggo/swag/cmd/swag@latest
cd pkg/api && $$(go env GOPATH)/bin/swag init -g server.go cd pkg/api/http && $$(go env GOPATH)/bin/swag init -g server.go
.PHONY: timoni-build .PHONY: timoni-build
timoni-build: timoni-build:

View File

@@ -22,10 +22,10 @@ Specifications:
* Swagger docs * Swagger docs
* Timoni, Helm and Kustomize installers * Timoni, Helm and Kustomize installers
* End-to-End testing with Kubernetes Kind and Helm * End-to-End testing with Kubernetes Kind and Helm
* Multi-arch container image with Docker buildx and Github Actions * Multi-arch container image with Docker buildx and GitHub Actions
* Container image signing with Sigstore cosign * Container image signing with Sigstore cosign
* SBOMs and SLSA Provenance embedded in the container image * SBOMs and SLSA Provenance embedded in the container image
* CVE scanning with Trivy * CVE scanning with govulncheck
Web API: Web API:
@@ -57,6 +57,16 @@ Web API:
gRPC API: gRPC API:
* `/grpc.health.v1.Health/Check` health checking * `/grpc.health.v1.Health/Check` health checking
* `/grpc.EchoService/Echo` echos the received content
* `/grpc.VersionService/Version` returns podinfo version and Git commit hash
* `/grpc.DelayService/Delay` returns a successful response after the given seconds in the body of gRPC request
* `/grpc.EnvService/Env` returns environment variables as a JSON array
* `/grpc.HeaderService/Header` returns the headers present in the gRPC request. Any custom header can also be given as a part of request and that can be returned using this API
* `/grpc.InfoService/Info` returns the runtime information
* `/grpc.PanicService/Panic` crashes the process with gRPC status code as '1 CANCELLED'
* `/grpc.StatusService/Status` returns the gRPC Status code given in the request body
* `/grpc.TokenService/TokenGenerate` issues a JWT token valid for one minute
* `/grpc.TokenService/TokenValidate` validates the JWT token
Web UI: Web UI:

View File

@@ -1,6 +1,6 @@
apiVersion: v1 apiVersion: v1
version: 6.5.4 version: 6.9.3
appVersion: 6.5.4 appVersion: 6.9.3
name: podinfo name: podinfo
engine: gotpl engine: gotpl
description: Podinfo Helm chart for Kubernetes description: Podinfo Helm chart for Kubernetes

View File

@@ -13,24 +13,26 @@ The Podinfo charts are published to
[GitHub Container Registry](https://github.com/stefanprodan/podinfo/pkgs/container/charts%2Fpodinfo) [GitHub Container Registry](https://github.com/stefanprodan/podinfo/pkgs/container/charts%2Fpodinfo)
and signed with [Cosign](https://github.com/sigstore/cosign) & GitHub Actions OIDC. and signed with [Cosign](https://github.com/sigstore/cosign) & GitHub Actions OIDC.
To install the chart with the release name `my-release` from GHCR: To install the chart with the release name `podinfo` from GHCR:
```console ```console
$ helm upgrade -i my-release oci://ghcr.io/stefanprodan/charts/podinfo $ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo
``` ```
To verify a chart with Cosign: To verify a chart version with Cosign:
```console ```console
$ cosign verify ghcr.io/stefanprodan/charts/podinfo:<VERSION> $ cosign verify ghcr.io/stefanprodan/charts/podinfo:<VERSION> \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity-regexp=^https://github\\.com/stefanprodan/podinfo/.*$
``` ```
Alternatively, you can install the chart from GitHub pages: Alternatively, you can install the chart from GitHub pages:
```console ```console
$ helm repo add podinfo https://stefanprodan.github.io/podinfo $ helm repo add stefanprodan https://stefanprodan.github.io/podinfo
$ helm upgrade -i my-release podinfo/podinfo $ helm upgrade -i podinfo stefanprodan/podinfo
``` ```
The command deploys podinfo on the Kubernetes cluster in the default namespace. The command deploys podinfo on the Kubernetes cluster in the default namespace.
@@ -38,10 +40,10 @@ The [configuration](#configuration) section lists the parameters that can be con
## Uninstalling the Chart ## Uninstalling the Chart
To uninstall/delete the `my-release` deployment: To uninstall the `podinfo` release:
```console ```console
$ helm delete my-release $ helm uninstall podinfo
``` ```
The command removes all the Kubernetes components associated with the chart and deletes the release. The command removes all the Kubernetes components associated with the chart and deletes the release.
@@ -50,81 +52,94 @@ The command removes all the Kubernetes components associated with the chart and
The following tables lists the configurable parameters of the podinfo chart and their default values. The following tables lists the configurable parameters of the podinfo chart and their default values.
| Parameter | Default | Description | | Parameter | Default | Description |
| --------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | |-----------------------------------|--------------------------------|------------------------------------------------------------------------------------------------------------------------|
| `replicaCount` | `1` | Desired number of pods | | `replicaCount` | `1` | Desired number of pods |
| `logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error` | | `logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `backend` | `None` | Echo backend URL | | `backend` | `None` | Echo backend URL |
| `backends` | `[]` | Array of echo backend URLs | | `backends` | `[]` | Array of echo backend URLs |
| `cache` | `None` | Redis address in the format `tcp://<host>:<port>` | | `cache` | `None` | Redis address in the format `tcp://<host>:<port>` |
| `redis.enabled` | `false` | Create Redis deployment for caching purposes | | `redis.enabled` | `false` | Create Redis deployment for caching purposes |
| `ui.color` | `#34577c` | UI color | | `redis.repository` | `docker.io/redis` | Redis image repository |
| `ui.message` | `None` | UI greetings message | | `redis.tag` | `<VERSION>` | Redis image tag |
| `ui.logo` | `None` | UI logo | | `redis.imagePullSecrets` | `[]` | Redis image pull secrets |
| `faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds | | `ui.color` | `#34577c` | UI color |
| `faults.error` | `false` | 1/3 chances of a random HTTP response error | | `ui.message` | `None` | UI greetings message |
| `faults.unhealthy` | `false` | When set, the healthy state is never reached | | `ui.logo` | `None` | UI logo |
| `faults.unready` | `false` | When set, the ready state is never reached | | `faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds |
| `faults.testFail` | `false` | When set, a helm test is included which always fails | | `faults.error` | `false` | 1/3 chances of a random HTTP response error |
| `faults.testTimeout` | `false` | When set, a helm test is included which always times out | | `faults.unhealthy` | `false` | When set, the healthy state is never reached |
| `image.repository` | `stefanprodan/podinfo` | Image repository | | `faults.unready` | `false` | When set, the ready state is never reached |
| `image.tag` | `<VERSION>` | Image tag | | `faults.testFail` | `false` | When set, a helm test is included which always fails |
| `image.pullPolicy` | `IfNotPresent` | Image pull policy | | `faults.testTimeout` | `false` | When set, a helm test is included which always times out |
| `service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app) | | `image.repository` | `ghcr.io/stefanprodan/podinfo` | Image repository |
| `service.type` | `ClusterIP` | Type of the Kubernetes Service | | `image.tag` | `<VERSION>` | Image tag |
| `service.metricsPort` | `9797` | Prometheus metrics endpoint port | | `image.pullPolicy` | `IfNotPresent` | Image pull policy |
| `service.httpPort` | `9898` | Container HTTP port | | `image.pullSecrets` | `[]` | Image pull secrets |
| `service.externalPort` | `9898` | ClusterIP HTTP port | | `service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app) |
| `service.grpcPort` | `9999` | ClusterIP gPRC port | | `service.type` | `ClusterIP` | Type of the Kubernetes Service |
| `service.grpcService` | `podinfo` | gPRC service name | | `service.metricsPort` | `9797` | Prometheus metrics endpoint port |
| `service.nodePort` | `31198` | NodePort for the HTTP endpoint | | `service.httpPort` | `9898` | Container HTTP port |
| `h2c.enabled` | `false` | Allow upgrading to h2c (non-TLS version of HTTP/2) | | `service.externalPort` | `9898` | ClusterIP HTTP port |
| `hpa.enabled` | `false` | Enables the Kubernetes HPA | | `service.grpcPort` | `9999` | ClusterIP gPRC port |
| `hpa.maxReplicas` | `10` | Maximum amount of pods | | `service.grpcService` | `podinfo` | gPRC service name |
| `hpa.cpu` | `None` | Target CPU usage per pod | | `service.nodePort` | `31198` | NodePort for the HTTP endpoint |
| `hpa.memory` | `None` | Target memory usage per pod | | `h2c.enabled` | `false` | Allow upgrading to h2c (non-TLS version of HTTP/2) |
| `hpa.requests` | `None` | Target HTTP requests per second per pod | | `extraArgs` | `[]` | Additional command line arguments to pass to podinfo container |
| `serviceAccount.enabled` | `false` | Whether a service account should be created | | `extraEnvs` | `[]` | Extra environment variables for the podinfo container |
| `serviceAccount.name` | `None` | The name of the service account to use, if not set and create is true, a name is generated using the fullname template | | `config.path` | `""` | config file path |
| `serviceAccount.imagePullSecrets` | `[]` | List of image pull secrets if pulling from private registries. | | `config.name` | `""` | config file name |
| `securityContext` | `{}` | The security context to be set on the podinfo container | | `hpa.enabled` | `false` | Enables the Kubernetes HPA |
| `linkerd.profile.enabled` | `false` | Create Linkerd service profile | | `hpa.maxReplicas` | `10` | Maximum amount of pods |
| `serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created | | `hpa.cpu` | `None` | Target CPU usage per pod |
| `serviceMonitor.interval` | `15s` | Prometheus scraping interval | | `hpa.memory` | `None` | Target memory usage per pod |
| `serviceMonitor.additionalLabels` | `{}` | Add additional labels to the service monitor | | `hpa.requests` | `None` | Target HTTP requests per second per pod |
| `ingress.enabled` | `false` | Enables Ingress | | `serviceAccount.enabled` | `false` | Whether a service account should be created |
| `ingress.className ` | `""` | Use ingressClassName | | `serviceAccount.name` | `None` | The name of the service account to use, if not set and create is true, a name is generated using the fullname template |
| `ingress.additionalLabels` | `{}` | Add additional labels to the ingress | | `serviceAccount.imagePullSecrets` | `[]` | List of image pull secrets if pulling from private registries. |
| `ingress.annotations` | `{}` | Ingress annotations | | `securityContext` | `{}` | The security context to be set on the podinfo container |
| `ingress.hosts` | `[]` | Ingress accepted hosts | | `podSecurityContext` | `{}` | The security context to be set on the pod |
| `ingress.tls` | `[]` | Ingress TLS configuration | | `podAnnotations` | `{}` | Pod annotations |
| `resources.requests.cpu` | `1m` | Pod CPU request | | `serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created |
| `resources.requests.memory` | `16Mi` | Pod memory request | | `serviceMonitor.interval` | `15s` | Prometheus scraping interval |
| `resources.limits.cpu` | `None` | Pod CPU limit | | `serviceMonitor.additionalLabels` | `{}` | Add additional labels to the service monitor |
| `resources.limits.memory` | `None` | Pod memory limit | | `ingress.enabled` | `false` | Enables Ingress |
| `nodeSelector` | `{}` | Node labels for pod assignment | | `ingress.className` | `""` | Use ingressClassName |
| `tolerations` | `[]` | List of node taints to tolerate | | `ingress.additionalLabels` | `{}` | Add additional labels to the ingress |
| `affinity` | `None` | Node/pod affinities | | `ingress.annotations` | `{}` | Ingress annotations |
| `podAnnotations` | `{}` | Pod annotations | | `ingress.hosts` | `[]` | Ingress accepted hosts |
| `ingress.tls` | `[]` | Ingress TLS configuration |
| `httpRoute.enabled` | `false` | Enables Gateway API HTTPRoute |
| `httpRoute.additionalLabels` | `{}` | Add additional labels to the HTTPRoute |
| `httpRoute.annotations` | `{}` | HTTPRoute annotations |
| `httpRoute.parentRefs` | `[]` | Gateways that this route is attached to |
| `httpRoute.hostnames` | `["podinfo.local"]` | Hostnames matching HTTP header |
| `httpRoute.rules` | `[]` | List of rules and filters applied |
| `linkerd.profile.enabled` | `false` | Create Linkerd service profile |
| `resources.requests.cpu` | `1m` | Pod CPU request |
| `resources.requests.memory` | `16Mi` | Pod memory request |
| `resources.limits.cpu` | `None` | Pod CPU limit |
| `resources.limits.memory` | `None` | Pod memory limit |
| `nodeSelector` | `{}` | Node labels for pod assignment |
| `tolerations` | `[]` | List of node taints to tolerate |
| `affinity` | `None` | Node/pod affinities |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, Specify each parameter using the `--set key=value[,key=value]` argument:
```console ```console
$ helm install my-release podinfo/podinfo \ $ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo \
--set=serviceMonitor.enabled=true,serviceMonitor.interval=5s --set=serviceMonitor.enabled=true,serviceMonitor.interval=5s
``` ```
To add custom annotations you need to escape the annotation key string: To add custom annotations you need to escape the annotation key string:
```console ```console
$ helm upgrade -i my-release podinfo/podinfo \ $ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo \
--set podAnnotations."appmesh\.k8s\.aws\/preview"=enabled --set podAnnotations."toolkit\.fluxcd\.io\/tenant"=dev-team
``` ```
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart:
```console ```console
$ helm install my-release podinfo/podinfo -f values.yaml $ helm upgrade -i my-release oci://ghcr.io/stefanprodan/charts/podinfo -f values.yaml
``` ```
> **Tip**: You can use the default [values.yaml](values.yaml)

View File

@@ -6,15 +6,15 @@
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- else if contains "NodePort" .Values.service.type }} {{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "podinfo.fullname" . }}) export NODE_PORT=$(kubectl get --namespace {{ include "podinfo.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "podinfo.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") export NODE_IP=$(kubectl get nodes --namespace {{ include "podinfo.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }} {{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available. NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "podinfo.fullname" . }}' You can watch the status of by running 'kubectl get svc -w {{ template "podinfo.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "podinfo.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') export SERVICE_IP=$(kubectl get svc --namespace {{ include "podinfo.namespace" . }} {{ template "podinfo.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.externalPort }} echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
{{- else if contains "ClusterIP" .Values.service.type }} {{- else if contains "ClusterIP" .Values.service.type }}
echo "Visit http://127.0.0.1:8080 to use your application" echo "Visit http://127.0.0.1:8080 to use your application"
kubectl -n {{ .Release.Namespace }} port-forward deploy/{{ template "podinfo.fullname" . }} 8080:{{ .Values.service.externalPort }} kubectl -n {{ include "podinfo.namespace" . }} port-forward deploy/{{ template "podinfo.fullname" . }} 8080:{{ .Values.service.externalPort }}
{{- end }} {{- end }}

View File

@@ -23,6 +23,13 @@ If release name contains chart name it will be used as a full name.
{{- end }} {{- end }}
{{- end }} {{- end }}
{{/*
Allow the release namespace to be overridden for multi-namespace deployments in combined charts.
*/}}
{{- define "podinfo.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/* {{/*
Create chart name and version as used by the chart label. Create chart name and version as used by the chart label.
*/}} */}}

View File

@@ -3,6 +3,7 @@ apiVersion: cert-manager.io/v1
kind: Certificate kind: Certificate
metadata: metadata:
name: {{ template "podinfo.fullname" . }} name: {{ template "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
spec: spec:

View File

@@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: {{ template "podinfo.fullname" . }} name: {{ template "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
spec: spec:
@@ -30,6 +31,9 @@ spec:
{{- if .Values.serviceAccount.enabled }} {{- if .Values.serviceAccount.enabled }}
serviceAccountName: {{ template "podinfo.serviceAccountName" . }} serviceAccountName: {{ template "podinfo.serviceAccountName" . }}
{{- end }} {{- end }}
{{- if .Values.image.pullSecrets }}
imagePullSecrets: {{ toYaml .Values.image.pullSecrets | nindent 8 }}
{{- end }}
containers: containers:
- name: {{ .Chart.Name }} - name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
@@ -87,6 +91,15 @@ spec:
{{- if .Values.h2c.enabled }} {{- if .Values.h2c.enabled }}
- --h2c - --h2c
{{- end }} {{- end }}
{{- with .Values.config.path }}
- --config-path={{ . }}
{{- end }}
{{- with .Values.config.name }}
- --config={{ . }}
{{- end }}
{{- with .Values.extraArgs }}
{{- toYaml . | nindent 12 }}
{{- end }}
env: env:
{{- if .Values.ui.message }} {{- if .Values.ui.message }}
- name: PODINFO_UI_MESSAGE - name: PODINFO_UI_MESSAGE
@@ -104,6 +117,9 @@ spec:
- name: PODINFO_BACKEND_URL - name: PODINFO_BACKEND_URL
value: {{ .Values.backend }} value: {{ .Values.backend }}
{{- end }} {{- end }}
{{- if .Values.extraEnvs }}
{{ toYaml .Values.extraEnvs | indent 10 }}
{{- end }}
ports: ports:
- name: http - name: http
containerPort: {{ .Values.service.httpPort | default 9898 }} containerPort: {{ .Values.service.httpPort | default 9898 }}
@@ -183,6 +199,10 @@ spec:
{{- end }} {{- end }}
resources: resources:
{{ toYaml .Values.resources | indent 12 }} {{ toYaml .Values.resources | indent 12 }}
{{- with .Values.podSecurityContext }}
securityContext:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: nodeSelector:
{{ toYaml . | indent 8 }} {{ toYaml . | indent 8 }}
@@ -203,3 +223,7 @@ spec:
secret: secret:
secretName: {{ template "podinfo.tlsSecretName" . }} secretName: {{ template "podinfo.tlsSecretName" . }}
{{- end }} {{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -3,6 +3,7 @@ apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler kind: HorizontalPodAutoscaler
metadata: metadata:
name: {{ template "podinfo.fullname" . }} name: {{ template "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
spec: spec:

View File

@@ -0,0 +1,41 @@
{{- if .Values.httpRoute.enabled -}}
{{- $fullName := include "podinfo.fullname" . -}}
{{- $svcPort := .Values.service.externalPort -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ $fullName }}
labels:
{{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.httpRoute.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- with .Values.httpRoute.parentRefs }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httpRoute.rules }}
{{- with .matches }}
- matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ $fullName }}
port: {{ $svcPort }}
weight: 1
{{- end }}
{{- end }}

View File

@@ -5,6 +5,7 @@ apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ $fullName }} name: {{ $fullName }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.ingress.additionalLabels }} {{- with .Values.ingress.additionalLabels }}

View File

@@ -2,7 +2,8 @@
apiVersion: linkerd.io/v1alpha2 apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile kind: ServiceProfile
metadata: metadata:
name: {{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local name: {{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}.svc.cluster.local
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
spec: spec:

View File

@@ -0,0 +1,14 @@
{{- if and .Values.podDisruptionBudget (gt (int .Values.replicaCount) 1) }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels:
{{- include "podinfo.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "podinfo.selectorLabels" . | nindent 6 }}
{{- toYaml .Values.podDisruptionBudget | nindent 2 }}
{{- end }}

View File

@@ -21,6 +21,9 @@ spec:
{{- if .Values.serviceAccount.enabled }} {{- if .Values.serviceAccount.enabled }}
serviceAccountName: {{ template "podinfo.serviceAccountName" . }} serviceAccountName: {{ template "podinfo.serviceAccountName" . }}
{{- end }} {{- end }}
{{- if .Values.redis.imagePullSecrets }}
imagePullSecrets: {{ toYaml .Values.redis.imagePullSecrets | nindent 8 }}
{{- end }}
containers: containers:
- name: redis - name: redis
image: "{{ .Values.redis.repository }}:{{ .Values.redis.tag }}" image: "{{ .Values.redis.repository }}:{{ .Values.redis.tag }}"

View File

@@ -14,4 +14,5 @@ spec:
port: 6379 port: 6379
protocol: TCP protocol: TCP
targetPort: redis targetPort: redis
appProtocol: redis
{{- end }} {{- end }}

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: {{ template "podinfo.fullname" . }} name: {{ template "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.service.annotations }} {{- with .Values.service.annotations }}

View File

@@ -3,6 +3,7 @@ apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor kind: ServiceMonitor
metadata: metadata:
name: {{ template "podinfo.fullname" . }} name: {{ template "podinfo.fullname" . }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.serviceMonitor.additionalLabels }} {{- with .Values.serviceMonitor.additionalLabels }}
@@ -15,7 +16,7 @@ spec:
interval: {{ .Values.serviceMonitor.interval }} interval: {{ .Values.serviceMonitor.interval }}
namespaceSelector: namespaceSelector:
matchNames: matchNames:
- {{ .Release.Namespace }} - {{ include "podinfo.namespace" . }}
selector: selector:
matchLabels: matchLabels:
{{- include "podinfo.selectorLabels" . | nindent 6 }} {{- include "podinfo.selectorLabels" . | nindent 6 }}

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-cache-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-cache-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:
@@ -24,6 +25,6 @@ spec:
curl -s -XDELETE ${PODINFO_SVC}/cache/test curl -s -XDELETE ${PODINFO_SVC}/cache/test
env: env:
- name: PODINFO_SVC - name: PODINFO_SVC
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}" value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
restartPolicy: Never restartPolicy: Never
{{- end }} {{- end }}

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:

View File

@@ -2,6 +2,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-grpc-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-grpc-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:
@@ -15,5 +16,5 @@ spec:
- name: grpc-health-probe - name: grpc-health-probe
image: stefanprodan/grpc_health_probe:v0.3.0 image: stefanprodan/grpc_health_probe:v0.3.0
command: ['grpc_health_probe'] command: ['grpc_health_probe']
args: ['-addr={{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.grpcPort }}'] args: ['-addr={{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.grpcPort }}']
restartPolicy: Never restartPolicy: Never

View File

@@ -2,6 +2,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-jwt-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-jwt-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:
@@ -22,5 +23,5 @@ spec:
curl -sH "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test curl -sH "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test
env: env:
- name: PODINFO_SVC - name: PODINFO_SVC
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}" value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
restartPolicy: Never restartPolicy: Never

View File

@@ -2,6 +2,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-service-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-service-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:
@@ -21,5 +22,5 @@ spec:
curl -s ${PODINFO_SVC}/api/info | grep version curl -s ${PODINFO_SVC}/api/info | grep version
env: env:
- name: PODINFO_SVC - name: PODINFO_SVC
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}" value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
restartPolicy: Never restartPolicy: Never

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:

View File

@@ -3,6 +3,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: {{ template "podinfo.fullname" . }}-tls-test-{{ randAlphaNum 5 | lower }} name: {{ template "podinfo.fullname" . }}-tls-test-{{ randAlphaNum 5 | lower }}
namespace: {{ include "podinfo.namespace" . }}
labels: labels:
{{- include "podinfo.labels" . | nindent 4 }} {{- include "podinfo.labels" . | nindent 4 }}
annotations: annotations:
@@ -22,6 +23,6 @@ spec:
curl -sk ${PODINFO_SVC}/api/info | grep version curl -sk ${PODINFO_SVC}/api/info | grep version
env: env:
- name: PODINFO_SVC - name: PODINFO_SVC
value: "https://{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.tls.port }}" value: "https://{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.tls.port }}"
restartPolicy: Never restartPolicy: Never
{{- end }} {{- end }}

View File

@@ -8,7 +8,7 @@ backends: []
image: image:
repository: ghcr.io/stefanprodan/podinfo repository: ghcr.io/stefanprodan/podinfo
tag: 6.5.4 tag: 6.9.3
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
ui: ui:
@@ -41,6 +41,16 @@ service:
h2c: h2c:
enabled: false enabled: false
# config file settings
config:
# config file path
path: ""
# config file name
name: ""
# Additional command line arguments to pass to podinfo container
extraArgs: []
# enable tls on the podinfo service # enable tls on the podinfo service
tls: tls:
enabled: false enabled: false
@@ -83,7 +93,7 @@ cache: ""
redis: redis:
enabled: true enabled: true
repository: redis repository: redis
tag: 7.0.7 tag: 8.4.0
serviceAccount: serviceAccount:
# Specifies whether a service account should be created # Specifies whether a service account should be created
@@ -97,13 +107,19 @@ serviceAccount:
# set container security context # set container security context
securityContext: {} securityContext: {}
# set pod security context
podSecurityContext: {}
# -- Expose the service via Kubernetes Ingress
# Requires an Ingress controller
# Docs https://kubernetes.io/docs/concepts/services-networking/ingress/
ingress: ingress:
enabled: false enabled: false
className: "" className: ""
additionalLabels: {} additionalLabels: {}
annotations: {} annotations: {}
# kubernetes.io/ingress.class: nginx # kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true" # kubernetes.io/tls-acme: "true"
hosts: hosts:
- host: podinfo.local - host: podinfo.local
paths: paths:
@@ -114,6 +130,31 @@ ingress:
# hosts: # hosts:
# - chart-example.local # - chart-example.local
# -- Expose the service via Gateway HTTPRoute
# Requires a Gateway controller
# Docs https://gateway-api.sigs.k8s.io/guides/
httpRoute:
# HTTPRoute enabled.
enabled: false
# Add additional labels to the HTTPRoute.
additionalLabels: {}
# HTTPRoute annotations.
annotations: {}
# Which Gateways this Route is attached to.
parentRefs:
- name: gateway
sectionName: http
# namespace: default
# Hostnames matching HTTP header.
hostnames:
- podinfo.local
# List of rules and filters applied.
rules:
- matches:
- path:
type: PathPrefix
value: /
linkerd: linkerd:
profile: profile:
enabled: false enabled: false
@@ -131,6 +172,14 @@ resources:
cpu: 100m cpu: 100m
memory: 64Mi memory: 64Mi
# Extra environment variables for the podinfo container
extraEnvs: []
# Example on how to configure extraEnvs
# - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
# value: "http://otel:4317"
# - name: MULTIPLE_VALUES
# value: TEST
nodeSelector: {} nodeSelector: {}
tolerations: [] tolerations: []
@@ -138,3 +187,25 @@ tolerations: []
affinity: {} affinity: {}
podAnnotations: {} podAnnotations: {}
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
probes:
readiness:
initialDelaySeconds: 1
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
periodSeconds: 10
liveness:
initialDelaySeconds: 1
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
periodSeconds: 10
startup:
enable: false
initialDelaySeconds: 10
timeoutSeconds: 5
failureThreshold: 20
successThreshold: 1
periodSeconds: 10

View File

@@ -8,8 +8,9 @@ backends: []
image: image:
repository: ghcr.io/stefanprodan/podinfo repository: ghcr.io/stefanprodan/podinfo
tag: 6.5.4 tag: 6.9.3
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
pullSecrets: []
ui: ui:
color: "#34577c" color: "#34577c"
@@ -45,6 +46,24 @@ service:
h2c: h2c:
enabled: false enabled: false
# config file settings
config:
# config file path
path: ""
# config file name
name: ""
# Additional command line arguments to pass to podinfo container
extraArgs: []
# Extra environment variables for the podinfo container
extraEnvs: []
# Example on how to configure extraEnvs
# - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
# value: "http://otel:4317"
# - name: MULTIPLE_VALUES
# value: TEST
# enable tls on the podinfo service # enable tls on the podinfo service
tls: tls:
enabled: false enabled: false
@@ -86,8 +105,9 @@ cache: ""
# Redis deployment # Redis deployment
redis: redis:
enabled: false enabled: false
repository: redis repository: docker.io/redis
tag: 7.0.7 tag: 8.4.0
imagePullSecrets: []
serviceAccount: serviceAccount:
# Specifies whether a service account should be created # Specifies whether a service account should be created
@@ -101,6 +121,12 @@ serviceAccount:
# set container security context # set container security context
securityContext: {} securityContext: {}
# set pod security context
podSecurityContext: {}
# -- Expose the service via Kubernetes Ingress
# Requires an Ingress controller
# Docs https://kubernetes.io/docs/concepts/services-networking/ingress/
ingress: ingress:
enabled: false enabled: false
className: "" className: ""
@@ -118,6 +144,31 @@ ingress:
# hosts: # hosts:
# - chart-example.local # - chart-example.local
# -- Expose the service via Gateway HTTPRoute
# Requires a Gateway controller
# Docs https://gateway-api.sigs.k8s.io/guides/
httpRoute:
# HTTPRoute enabled.
enabled: false
# Add additional labels to the HTTPRoute.
additionalLabels: {}
# HTTPRoute annotations.
annotations: {}
# Which Gateways this Route is attached to.
parentRefs:
- name: gateway
sectionName: http
# namespace: default
# Hostnames matching HTTP header.
hostnames:
- podinfo.local
# List of rules and filters applied.
rules:
- matches:
- path:
type: PathPrefix
value: /
linkerd: linkerd:
profile: profile:
enabled: false enabled: false
@@ -142,6 +193,13 @@ affinity: {}
podAnnotations: {} podAnnotations: {}
# https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
topologySpreadConstraints: []
# Disruption budget will be configured only when the replicaCount is greater than 1
podDisruptionBudget: {}
# maxUnavailable: 1
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
probes: probes:
readiness: readiness:

View File

@@ -13,8 +13,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"github.com/stefanprodan/podinfo/pkg/api" "github.com/stefanprodan/podinfo/pkg/api/grpc"
"github.com/stefanprodan/podinfo/pkg/grpc" "github.com/stefanprodan/podinfo/pkg/api/http"
"github.com/stefanprodan/podinfo/pkg/signals" "github.com/stefanprodan/podinfo/pkg/signals"
"github.com/stefanprodan/podinfo/pkg/version" "github.com/stefanprodan/podinfo/pkg/version"
go_grpc "google.golang.org/grpc" go_grpc "google.golang.org/grpc"
@@ -138,11 +138,13 @@ func main() {
var grpcServer *go_grpc.Server var grpcServer *go_grpc.Server
if grpcCfg.Port > 0 { if grpcCfg.Port > 0 {
grpcSrv, _ := grpc.NewServer(&grpcCfg, logger) grpcSrv, _ := grpc.NewServer(&grpcCfg, logger)
//grpcinfoSrv, _ := grpc.NewInfoServer(&grpcCfg)
grpcServer = grpcSrv.ListenAndServe() grpcServer = grpcSrv.ListenAndServe()
} }
// load HTTP server config // load HTTP server config
var srvCfg api.Config var srvCfg http.Config
if err := viper.Unmarshal(&srvCfg); err != nil { if err := viper.Unmarshal(&srvCfg); err != nil {
logger.Panic("config unmarshal failed", zap.Error(err)) logger.Panic("config unmarshal failed", zap.Error(err))
} }
@@ -155,7 +157,7 @@ func main() {
) )
// start HTTP server // start HTTP server
srv, _ := api.NewServer(&srvCfg, logger) srv, _ := http.NewServer(&srvCfg, logger)
httpServer, httpsServer, healthy, ready := srv.ListenAndServe() httpServer, httpsServer, healthy, ready := srv.ListenAndServe()
// graceful shutdown // graceful shutdown

View File

@@ -23,7 +23,7 @@ spec:
spec: spec:
containers: containers:
- name: backend - name: backend
image: ghcr.io/stefanprodan/podinfo:6.5.4 image: ghcr.io/stefanprodan/podinfo:6.9.3
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http
@@ -42,7 +42,7 @@ spec:
- --grpc-port=9999 - --grpc-port=9999
- --grpc-service-name=backend - --grpc-service-name=backend
- --level=info - --level=info
- --cache-server=cache:6379 - --cache-server=tcp://cache:6379
env: env:
- name: PODINFO_UI_COLOR - name: PODINFO_UI_COLOR
value: "#34577c" value: "#34577c"

View File

@@ -13,7 +13,7 @@ spec:
spec: spec:
containers: containers:
- name: redis - name: redis
image: redis:7.0.7 image: docker.io/redis:8.4.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
command: command:
- redis-server - redis-server

View File

@@ -23,7 +23,7 @@ spec:
spec: spec:
containers: containers:
- name: frontend - name: frontend
image: ghcr.io/stefanprodan/podinfo:6.5.4 image: ghcr.io/stefanprodan/podinfo:6.9.3
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http
@@ -41,7 +41,7 @@ spec:
- --port-metrics=9797 - --port-metrics=9797
- --level=info - --level=info
- --backend-url=http://backend:9898/echo - --backend-url=http://backend:9898/echo
- --cache-server=cache:6379 - --cache-server=tcp://cache:6379
env: env:
- name: PODINFO_UI_COLOR - name: PODINFO_UI_COLOR
value: "#34577c" value: "#34577c"

View File

@@ -25,7 +25,7 @@ spec:
serviceAccountName: webapp serviceAccountName: webapp
containers: containers:
- name: backend - name: backend
image: ghcr.io/stefanprodan/podinfo:6.5.4 image: ghcr.io/stefanprodan/podinfo:6.9.3
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http

View File

@@ -25,7 +25,7 @@ spec:
serviceAccountName: webapp serviceAccountName: webapp
containers: containers:
- name: frontend - name: frontend
image: ghcr.io/stefanprodan/podinfo:6.5.4 image: ghcr.io/stefanprodan/podinfo:6.9.3
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http

129
go.mod
View File

@@ -1,89 +1,82 @@
module github.com/stefanprodan/podinfo module github.com/stefanprodan/podinfo
go 1.21 go 1.25
require ( require (
github.com/chzyer/readline v1.5.1 github.com/chzyer/readline v1.5.1
github.com/fatih/color v1.16.0 github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.9.0
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.2
github.com/gomodule/redigo v1.8.9 github.com/gomodule/redigo v1.9.3
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.3
github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_golang v1.23.2
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.10.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.18.1 github.com/spf13/viper v1.21.0
github.com/swaggo/http-swagger v1.3.4 github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.2 github.com/swaggo/swag v1.16.6
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.1 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.63.0
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0
go.opentelemetry.io/contrib/propagators/aws v1.21.1 go.opentelemetry.io/contrib/propagators/aws v1.38.0
go.opentelemetry.io/contrib/propagators/b3 v1.21.1 go.opentelemetry.io/contrib/propagators/b3 v1.38.0
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 go.opentelemetry.io/contrib/propagators/jaeger v1.38.0
go.opentelemetry.io/contrib/propagators/ot v1.21.1 go.opentelemetry.io/contrib/propagators/ot v1.38.0
go.opentelemetry.io/otel v1.21.0 go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
go.opentelemetry.io/otel/sdk v1.21.0 go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/trace v1.21.0 go.opentelemetry.io/otel/trace v1.38.0
go.uber.org/zap v1.26.0 go.uber.org/zap v1.27.0
golang.org/x/net v0.19.0 golang.org/x/net v0.47.0
google.golang.org/grpc v1.60.0 google.golang.org/grpc v1.76.0
google.golang.org/protobuf v1.36.10
) )
// Fix CVE-2022-32149
replace golang.org/x/text => golang.org/x/text v0.14.0
// Fix CVE-2022-28948
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
require ( require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.19.15 // indirect github.com/go-openapi/swag v0.23.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/procfs v0.11.1 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/spf13/afero v1.15.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect github.com/swaggo/files v1.0.1 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/sys v0.15.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/mod v0.30.0 // indirect
golang.org/x/tools v0.13.0 // indirect golang.org/x/sync v0.18.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect golang.org/x/sys v0.38.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect golang.org/x/text v0.31.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect golang.org/x/tools v0.39.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

323
go.sum
View File

@@ -2,242 +2,215 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v1.9.3 h1:dNPSXeXv6HCq2jdyWfjgmhBdqnR6PRO3m/G05nvpPC8=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/gomodule/redigo v1.9.3/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.1 h1:Ifzy1lucGMQJh6wPRxusde8bWaDhYjSNOqDyn6Hb4TM= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.1/go.mod h1:YfFNem80G9UZ/mL5zd5GGXZSy95eXK+RhzIWBkLjLSc= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.63.0 h1:rATLgFjv0P9qyXQR/aChJ6JVbMtXOQjt49GgT36cBbk=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.63.0/go.mod h1:34csimR1lUhdT5HH4Rii9aKPrvBcnFRwxLwcevsU+Kk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 h1:2pn7OzMewmYRiNtv1doZnLo3gONcnMHlFnmOR8Vgt+8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0/go.mod h1:rjbQTDEPQymPE0YnRQp9/NuPwwtL0sesz/fnqRW/v84=
go.opentelemetry.io/contrib/propagators/aws v1.21.1 h1:uQIQIDWb0gzyvon2ICnghpLAf9w7ADOCUiIiwCQgR2o= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
go.opentelemetry.io/contrib/propagators/aws v1.21.1/go.mod h1:kCcto3ACQxm+VrkQX/NK/TkDmAd99MQhvffzyTKhzL4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= go.opentelemetry.io/contrib/propagators/aws v1.38.0 h1:eRZ7asSbLc5dH7+TBzL6hFKb1dabz0IV51uUUwYRZts=
go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/contrib/propagators/aws v1.38.0/go.mod h1:wXqc9NTGcXapBExHBDVLEZlByu6quiQL8w7Tjgv8TCg=
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU=
go.opentelemetry.io/contrib/propagators/ot v1.21.1 h1:3TN5vkXjKYWp0YdMcnUEC/A+pBPvqz9V3nCS2xmcurk= go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 h1:nXGeLvT1QtCAhkASkP/ksjkTKZALIaQBIW+JSIw1KIc=
go.opentelemetry.io/contrib/propagators/ot v1.21.1/go.mod h1:oy0MYCbS/b3cqUDW37wBWtlwBIsutngS++Lklpgh+fc= go.opentelemetry.io/contrib/propagators/jaeger v1.38.0/go.mod h1:oMvOXk78ZR3KEuPMBgp/ThAMDy9ku/eyUVztr+3G6Wo=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/contrib/propagators/ot v1.38.0 h1:k4gSyyohaDXI8F9BDXYC3uO2vr5sRNeQFMsN9Zn0EoI=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/contrib/propagators/ot v1.38.0/go.mod h1:2hDsuiHRO39SRUMhYGqmj64z/IuMRoxE4bBSFR82Lo8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -23,7 +23,7 @@ spec:
spec: spec:
containers: containers:
- name: podinfod - name: podinfod
image: ghcr.io/stefanprodan/podinfo:6.5.4 image: ghcr.io/stefanprodan/podinfo:6.9.3
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http
@@ -72,3 +72,9 @@ spec:
requests: requests:
cpu: 100m cpu: 100m
memory: 64Mi memory: 64Mi
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}

View File

@@ -4,4 +4,3 @@ resources:
- hpa.yaml - hpa.yaml
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml

21
pkg/api/grpc/delay.go Normal file
View File

@@ -0,0 +1,21 @@
package grpc
import (
"context"
"time"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/delay"
"go.uber.org/zap"
)
type DelayServer struct {
pb.UnimplementedDelayServiceServer
config *Config
logger *zap.Logger
}
func (s *DelayServer) Delay(ctx context.Context, delayInput *pb.DelayRequest) (*pb.DelayResponse, error) {
time.Sleep(time.Duration(delayInput.Seconds) * time.Second)
return &pb.DelayResponse{Message: delayInput.Seconds}, nil
}

View File

@@ -0,0 +1,211 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: delay/delay.proto
package delay
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DelayRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
}
func (x *DelayRequest) Reset() {
*x = DelayRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_delay_delay_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DelayRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DelayRequest) ProtoMessage() {}
func (x *DelayRequest) ProtoReflect() protoreflect.Message {
mi := &file_delay_delay_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DelayRequest.ProtoReflect.Descriptor instead.
func (*DelayRequest) Descriptor() ([]byte, []int) {
return file_delay_delay_proto_rawDescGZIP(), []int{0}
}
func (x *DelayRequest) GetSeconds() int64 {
if x != nil {
return x.Seconds
}
return 0
}
type DelayResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message int64 `protobuf:"varint,1,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *DelayResponse) Reset() {
*x = DelayResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_delay_delay_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DelayResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DelayResponse) ProtoMessage() {}
func (x *DelayResponse) ProtoReflect() protoreflect.Message {
mi := &file_delay_delay_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DelayResponse.ProtoReflect.Descriptor instead.
func (*DelayResponse) Descriptor() ([]byte, []int) {
return file_delay_delay_proto_rawDescGZIP(), []int{1}
}
func (x *DelayResponse) GetMessage() int64 {
if x != nil {
return x.Message
}
return 0
}
var File_delay_delay_proto protoreflect.FileDescriptor
var file_delay_delay_proto_rawDesc = []byte{
0x0a, 0x11, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x65,
0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65,
0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x73, 0x22, 0x29, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32,
0x44, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x34, 0x0a, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x13, 0x2e, 0x64, 0x65, 0x6c, 0x61, 0x79,
0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
0x64, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x64, 0x65, 0x6c, 0x61, 0x79,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_delay_delay_proto_rawDescOnce sync.Once
file_delay_delay_proto_rawDescData = file_delay_delay_proto_rawDesc
)
func file_delay_delay_proto_rawDescGZIP() []byte {
file_delay_delay_proto_rawDescOnce.Do(func() {
file_delay_delay_proto_rawDescData = protoimpl.X.CompressGZIP(file_delay_delay_proto_rawDescData)
})
return file_delay_delay_proto_rawDescData
}
var file_delay_delay_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_delay_delay_proto_goTypes = []interface{}{
(*DelayRequest)(nil), // 0: delay.DelayRequest
(*DelayResponse)(nil), // 1: delay.DelayResponse
}
var file_delay_delay_proto_depIdxs = []int32{
0, // 0: delay.DelayService.Delay:input_type -> delay.DelayRequest
1, // 1: delay.DelayService.Delay:output_type -> delay.DelayResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_delay_delay_proto_init() }
func file_delay_delay_proto_init() {
if File_delay_delay_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_delay_delay_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DelayRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_delay_delay_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DelayResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_delay_delay_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_delay_delay_proto_goTypes,
DependencyIndexes: file_delay_delay_proto_depIdxs,
MessageInfos: file_delay_delay_proto_msgTypes,
}.Build()
File_delay_delay_proto = out.File
file_delay_delay_proto_rawDesc = nil
file_delay_delay_proto_goTypes = nil
file_delay_delay_proto_depIdxs = nil
}

View File

@@ -0,0 +1,17 @@
syntax = "proto3";
option go_package = "./delay";
package delay;
message DelayRequest {
int64 seconds = 1;
}
message DelayResponse {
int64 message = 1;
}
service DelayService {
rpc Delay (DelayRequest) returns (DelayResponse) {}
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: delay/delay.proto
package delay
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// DelayServiceClient is the client API for DelayService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DelayServiceClient interface {
Delay(ctx context.Context, in *DelayRequest, opts ...grpc.CallOption) (*DelayResponse, error)
}
type delayServiceClient struct {
cc grpc.ClientConnInterface
}
func NewDelayServiceClient(cc grpc.ClientConnInterface) DelayServiceClient {
return &delayServiceClient{cc}
}
func (c *delayServiceClient) Delay(ctx context.Context, in *DelayRequest, opts ...grpc.CallOption) (*DelayResponse, error) {
out := new(DelayResponse)
err := c.cc.Invoke(ctx, "/delay.DelayService/Delay", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DelayServiceServer is the server API for DelayService service.
// All implementations must embed UnimplementedDelayServiceServer
// for forward compatibility
type DelayServiceServer interface {
Delay(context.Context, *DelayRequest) (*DelayResponse, error)
mustEmbedUnimplementedDelayServiceServer()
}
// UnimplementedDelayServiceServer must be embedded to have forward compatible implementations.
type UnimplementedDelayServiceServer struct {
}
func (UnimplementedDelayServiceServer) Delay(context.Context, *DelayRequest) (*DelayResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delay not implemented")
}
func (UnimplementedDelayServiceServer) mustEmbedUnimplementedDelayServiceServer() {}
// UnsafeDelayServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DelayServiceServer will
// result in compilation errors.
type UnsafeDelayServiceServer interface {
mustEmbedUnimplementedDelayServiceServer()
}
func RegisterDelayServiceServer(s grpc.ServiceRegistrar, srv DelayServiceServer) {
s.RegisterService(&DelayService_ServiceDesc, srv)
}
func _DelayService_Delay_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DelayRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DelayServiceServer).Delay(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/delay.DelayService/Delay",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DelayServiceServer).Delay(ctx, req.(*DelayRequest))
}
return interceptor(ctx, in, info, handler)
}
// DelayService_ServiceDesc is the grpc.ServiceDesc for DelayService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DelayService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "delay.DelayService",
HandlerType: (*DelayServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Delay",
Handler: _DelayService_Delay_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "delay/delay.proto",
}

View File

@@ -0,0 +1,75 @@
package grpc
import (
"context"
"fmt"
"log"
"net"
"regexp"
"strconv"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/delay"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcDelay(t *testing.T) {
// Server initialization
// bufconn => uses in-memory connection instead of system network I/O
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
delay.RegisterDelayServiceServer(srv, &DelayServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
// - Test
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := delay.NewDelayServiceClient(conn)
res, err := client.Delay(context.Background(), &delay.DelayRequest{Seconds: 3})
// Check the status code is what we expect.
if _, ok := status.FromError(err); !ok {
t.Errorf("Delay returned type %T, want %T", err, status.Error)
}
if res != nil {
fmt.Printf("res %v\n", res)
}
// Check the response body is what we expect. Here we expect the response to be "3" as the delay is set to 3 seconds.
expected := "3"
r := regexp.MustCompile(expected)
if !r.MatchString(strconv.FormatInt(res.Message, 10)) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res.Message, expected)
}
}

20
pkg/api/grpc/echo.go Normal file
View File

@@ -0,0 +1,20 @@
package grpc
import (
"context"
"github.com/stefanprodan/podinfo/pkg/api/grpc/echo"
"go.uber.org/zap"
)
type echoServer struct {
echo.UnimplementedEchoServiceServer
config *Config
logger *zap.Logger
}
func (s *echoServer) Echo(ctx context.Context, message *echo.Message) (*echo.Message, error) {
s.logger.Info("Received message body from client:", zap.String("input body", message.Body))
return &echo.Message{Body: message.Body}, nil
}

View File

@@ -0,0 +1,146 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v4.24.3
// source: echo/echo.proto
package echo
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Message struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"`
}
func (x *Message) Reset() {
*x = Message{}
if protoimpl.UnsafeEnabled {
mi := &file_echo_echo_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Message) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message) ProtoMessage() {}
func (x *Message) ProtoReflect() protoreflect.Message {
mi := &file_echo_echo_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Message.ProtoReflect.Descriptor instead.
func (*Message) Descriptor() ([]byte, []int) {
return file_echo_echo_proto_rawDescGZIP(), []int{0}
}
func (x *Message) GetBody() string {
if x != nil {
return x.Body
}
return ""
}
var File_echo_echo_proto protoreflect.FileDescriptor
var file_echo_echo_proto_rawDesc = []byte{
0x0a, 0x0f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x04, 0x65, 0x63, 0x68, 0x6f, 0x22, 0x1d, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x32, 0x35, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x0d, 0x2e,
0x65, 0x63, 0x68, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x65,
0x63, 0x68, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a,
0x06, 0x2e, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_echo_echo_proto_rawDescOnce sync.Once
file_echo_echo_proto_rawDescData = file_echo_echo_proto_rawDesc
)
func file_echo_echo_proto_rawDescGZIP() []byte {
file_echo_echo_proto_rawDescOnce.Do(func() {
file_echo_echo_proto_rawDescData = protoimpl.X.CompressGZIP(file_echo_echo_proto_rawDescData)
})
return file_echo_echo_proto_rawDescData
}
var file_echo_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_echo_echo_proto_goTypes = []interface{}{
(*Message)(nil), // 0: echo.Message
}
var file_echo_echo_proto_depIdxs = []int32{
0, // 0: echo.EchoService.Echo:input_type -> echo.Message
0, // 1: echo.EchoService.Echo:output_type -> echo.Message
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_echo_echo_proto_init() }
func file_echo_echo_proto_init() {
if File_echo_echo_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_echo_echo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Message); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_echo_echo_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_echo_echo_proto_goTypes,
DependencyIndexes: file_echo_echo_proto_depIdxs,
MessageInfos: file_echo_echo_proto_msgTypes,
}.Build()
File_echo_echo_proto = out.File
file_echo_echo_proto_rawDesc = nil
file_echo_echo_proto_goTypes = nil
file_echo_echo_proto_depIdxs = nil
}

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
option go_package = "./echo";
package echo;
message Message {
string body = 1;
}
service EchoService {
rpc Echo(Message) returns (Message) {}
}

View File

@@ -0,0 +1,109 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.24.3
// source: echo/echo.proto
package echo
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
EchoService_Echo_FullMethodName = "/echo.EchoService/Echo"
)
// EchoServiceClient is the client API for EchoService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type EchoServiceClient interface {
Echo(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error)
}
type echoServiceClient struct {
cc grpc.ClientConnInterface
}
func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient {
return &echoServiceClient{cc}
}
func (c *echoServiceClient) Echo(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) {
out := new(Message)
err := c.cc.Invoke(ctx, EchoService_Echo_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EchoServiceServer is the server API for EchoService service.
// All implementations must embed UnimplementedEchoServiceServer
// for forward compatibility
type EchoServiceServer interface {
Echo(context.Context, *Message) (*Message, error)
mustEmbedUnimplementedEchoServiceServer()
}
// UnimplementedEchoServiceServer must be embedded to have forward compatible implementations.
type UnimplementedEchoServiceServer struct {
}
func (UnimplementedEchoServiceServer) Echo(context.Context, *Message) (*Message, error) {
return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented")
}
func (UnimplementedEchoServiceServer) mustEmbedUnimplementedEchoServiceServer() {}
// UnsafeEchoServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to EchoServiceServer will
// result in compilation errors.
type UnsafeEchoServiceServer interface {
mustEmbedUnimplementedEchoServiceServer()
}
func RegisterEchoServiceServer(s grpc.ServiceRegistrar, srv EchoServiceServer) {
s.RegisterService(&EchoService_ServiceDesc, srv)
}
func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Message)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EchoServiceServer).Echo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: EchoService_Echo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EchoServiceServer).Echo(ctx, req.(*Message))
}
return interceptor(ctx, in, info, handler)
}
// EchoService_ServiceDesc is the grpc.ServiceDesc for EchoService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var EchoService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "echo.EchoService",
HandlerType: (*EchoServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Echo",
Handler: _EchoService_Echo_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "echo/echo.proto",
}

65
pkg/api/grpc/echo_test.go Normal file
View File

@@ -0,0 +1,65 @@
package grpc
import (
"context"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/echo"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcEcho(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
s := NewMockGrpcServer()
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
echo.RegisterEchoServiceServer(srv, &echoServer{config: s.config, logger: s.logger})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := echo.NewEchoServiceClient(conn)
res, err := client.Echo(context.Background(), &echo.Message{Body: "test123-test"})
if _, ok := status.FromError(err); !ok {
t.Errorf("Echo returned type %T, want %T", err, status.Error)
}
expected := ".*body.*test123-test.*"
r := regexp.MustCompile(expected)
if !r.MatchString(res.String()) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res, expected)
}
}

19
pkg/api/grpc/env.go Normal file
View File

@@ -0,0 +1,19 @@
package grpc
import (
"context"
"go.uber.org/zap"
"os"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/env"
)
type EnvServer struct {
pb.UnimplementedEnvServiceServer
config *Config
logger *zap.Logger
}
func (s *EnvServer) Env(ctx context.Context, envInput *pb.EnvRequest) (*pb.EnvResponse, error) {
return &pb.EnvResponse{EnvVars: os.Environ()}, nil
}

199
pkg/api/grpc/env/env.pb.go vendored Normal file
View File

@@ -0,0 +1,199 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: env/env.proto
package env
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EnvRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *EnvRequest) Reset() {
*x = EnvRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_env_env_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EnvRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EnvRequest) ProtoMessage() {}
func (x *EnvRequest) ProtoReflect() protoreflect.Message {
mi := &file_env_env_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EnvRequest.ProtoReflect.Descriptor instead.
func (*EnvRequest) Descriptor() ([]byte, []int) {
return file_env_env_proto_rawDescGZIP(), []int{0}
}
type EnvResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
EnvVars []string `protobuf:"bytes,1,rep,name=envVars,proto3" json:"envVars,omitempty"`
}
func (x *EnvResponse) Reset() {
*x = EnvResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_env_env_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EnvResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EnvResponse) ProtoMessage() {}
func (x *EnvResponse) ProtoReflect() protoreflect.Message {
mi := &file_env_env_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EnvResponse.ProtoReflect.Descriptor instead.
func (*EnvResponse) Descriptor() ([]byte, []int) {
return file_env_env_proto_rawDescGZIP(), []int{1}
}
func (x *EnvResponse) GetEnvVars() []string {
if x != nil {
return x.EnvVars
}
return nil
}
var File_env_env_proto protoreflect.FileDescriptor
var file_env_env_proto_rawDesc = []byte{
0x0a, 0x0d, 0x65, 0x6e, 0x76, 0x2f, 0x65, 0x6e, 0x76, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x03, 0x65, 0x6e, 0x76, 0x22, 0x0c, 0x0a, 0x0a, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x22, 0x27, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73, 0x32, 0x38, 0x0a, 0x0a, 0x45,
0x6e, 0x76, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x45, 0x6e, 0x76,
0x12, 0x0f, 0x2e, 0x65, 0x6e, 0x76, 0x2e, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x10, 0x2e, 0x65, 0x6e, 0x76, 0x2e, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2f, 0x65, 0x6e, 0x76, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_env_env_proto_rawDescOnce sync.Once
file_env_env_proto_rawDescData = file_env_env_proto_rawDesc
)
func file_env_env_proto_rawDescGZIP() []byte {
file_env_env_proto_rawDescOnce.Do(func() {
file_env_env_proto_rawDescData = protoimpl.X.CompressGZIP(file_env_env_proto_rawDescData)
})
return file_env_env_proto_rawDescData
}
var file_env_env_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_env_env_proto_goTypes = []interface{}{
(*EnvRequest)(nil), // 0: env.EnvRequest
(*EnvResponse)(nil), // 1: env.EnvResponse
}
var file_env_env_proto_depIdxs = []int32{
0, // 0: env.EnvService.Env:input_type -> env.EnvRequest
1, // 1: env.EnvService.Env:output_type -> env.EnvResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_env_env_proto_init() }
func file_env_env_proto_init() {
if File_env_env_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_env_env_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EnvRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_env_env_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EnvResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_env_env_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_env_env_proto_goTypes,
DependencyIndexes: file_env_env_proto_depIdxs,
MessageInfos: file_env_env_proto_msgTypes,
}.Build()
File_env_env_proto = out.File
file_env_env_proto_rawDesc = nil
file_env_env_proto_goTypes = nil
file_env_env_proto_depIdxs = nil
}

15
pkg/api/grpc/env/env.proto vendored Normal file
View File

@@ -0,0 +1,15 @@
syntax = "proto3";
option go_package = "./env";
package env;
message EnvRequest {}
message EnvResponse {
repeated string envVars = 1;
}
service EnvService {
rpc Env (EnvRequest) returns (EnvResponse) {}
}

105
pkg/api/grpc/env/env_grpc.pb.go vendored Normal file
View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: env/env.proto
package env
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// EnvServiceClient is the client API for EnvService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type EnvServiceClient interface {
Env(ctx context.Context, in *EnvRequest, opts ...grpc.CallOption) (*EnvResponse, error)
}
type envServiceClient struct {
cc grpc.ClientConnInterface
}
func NewEnvServiceClient(cc grpc.ClientConnInterface) EnvServiceClient {
return &envServiceClient{cc}
}
func (c *envServiceClient) Env(ctx context.Context, in *EnvRequest, opts ...grpc.CallOption) (*EnvResponse, error) {
out := new(EnvResponse)
err := c.cc.Invoke(ctx, "/env.EnvService/Env", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EnvServiceServer is the server API for EnvService service.
// All implementations must embed UnimplementedEnvServiceServer
// for forward compatibility
type EnvServiceServer interface {
Env(context.Context, *EnvRequest) (*EnvResponse, error)
mustEmbedUnimplementedEnvServiceServer()
}
// UnimplementedEnvServiceServer must be embedded to have forward compatible implementations.
type UnimplementedEnvServiceServer struct {
}
func (UnimplementedEnvServiceServer) Env(context.Context, *EnvRequest) (*EnvResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Env not implemented")
}
func (UnimplementedEnvServiceServer) mustEmbedUnimplementedEnvServiceServer() {}
// UnsafeEnvServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to EnvServiceServer will
// result in compilation errors.
type UnsafeEnvServiceServer interface {
mustEmbedUnimplementedEnvServiceServer()
}
func RegisterEnvServiceServer(s grpc.ServiceRegistrar, srv EnvServiceServer) {
s.RegisterService(&EnvService_ServiceDesc, srv)
}
func _EnvService_Env_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EnvRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EnvServiceServer).Env(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/env.EnvService/Env",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EnvServiceServer).Env(ctx, req.(*EnvRequest))
}
return interceptor(ctx, in, info, handler)
}
// EnvService_ServiceDesc is the grpc.ServiceDesc for EnvService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var EnvService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "env.EnvService",
HandlerType: (*EnvServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Env",
Handler: _EnvService_Env_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "env/env.proto",
}

64
pkg/api/grpc/env_test.go Normal file
View File

@@ -0,0 +1,64 @@
package grpc
import (
"context"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/env"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcEnv(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
env.RegisterEnvServiceServer(srv, &EnvServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := env.NewEnvServiceClient(conn)
res, err := client.Env(context.Background(), &env.EnvRequest{})
if _, ok := status.FromError(err); !ok {
t.Errorf("Env returned type %T, want %T", err, status.Error)
}
expected := ".*PATH.*"
r := regexp.MustCompile(expected)
if !r.MatchString(res.String()) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res, expected)
}
}

34
pkg/api/grpc/headers.go Normal file
View File

@@ -0,0 +1,34 @@
package grpc
import (
"context"
"strings"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/headers"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
type HeaderServer struct {
pb.UnimplementedHeaderServiceServer
config *Config
logger *zap.Logger
}
func (s *HeaderServer) Header(ctx context.Context, in *pb.HeaderRequest) (*pb.HeaderResponse, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.DataLoss, "UnaryEcho: failed to get metadata")
}
// Creating slices beacause echoing the header metadata can't be predetermined by the proto contract
res := []string{}
for i, e := range md {
res = append(res, i+"="+strings.Join(e, ","))
}
return &pb.HeaderResponse{Headers: res}, nil
}

View File

@@ -0,0 +1,201 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: headers/headers.proto
package header
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type HeaderRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *HeaderRequest) Reset() {
*x = HeaderRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_headers_headers_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HeaderRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderRequest) ProtoMessage() {}
func (x *HeaderRequest) ProtoReflect() protoreflect.Message {
mi := &file_headers_headers_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderRequest.ProtoReflect.Descriptor instead.
func (*HeaderRequest) Descriptor() ([]byte, []int) {
return file_headers_headers_proto_rawDescGZIP(), []int{0}
}
type HeaderResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Headers []string `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"`
}
func (x *HeaderResponse) Reset() {
*x = HeaderResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_headers_headers_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HeaderResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderResponse) ProtoMessage() {}
func (x *HeaderResponse) ProtoReflect() protoreflect.Message {
mi := &file_headers_headers_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderResponse.ProtoReflect.Descriptor instead.
func (*HeaderResponse) Descriptor() ([]byte, []int) {
return file_headers_headers_proto_rawDescGZIP(), []int{1}
}
func (x *HeaderResponse) GetHeaders() []string {
if x != nil {
return x.Headers
}
return nil
}
var File_headers_headers_proto protoreflect.FileDescriptor
var file_headers_headers_proto_rawDesc = []byte{
0x0a, 0x15, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22,
0x0f, 0x0a, 0x0d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x22, 0x2a, 0x0a, 0x0e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x32, 0x4a, 0x0a, 0x0d,
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a,
0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x68, 0x65,
0x61, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_headers_headers_proto_rawDescOnce sync.Once
file_headers_headers_proto_rawDescData = file_headers_headers_proto_rawDesc
)
func file_headers_headers_proto_rawDescGZIP() []byte {
file_headers_headers_proto_rawDescOnce.Do(func() {
file_headers_headers_proto_rawDescData = protoimpl.X.CompressGZIP(file_headers_headers_proto_rawDescData)
})
return file_headers_headers_proto_rawDescData
}
var file_headers_headers_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_headers_headers_proto_goTypes = []interface{}{
(*HeaderRequest)(nil), // 0: header.headerRequest
(*HeaderResponse)(nil), // 1: header.headerResponse
}
var file_headers_headers_proto_depIdxs = []int32{
0, // 0: header.HeaderService.Header:input_type -> header.headerRequest
1, // 1: header.HeaderService.Header:output_type -> header.headerResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_headers_headers_proto_init() }
func file_headers_headers_proto_init() {
if File_headers_headers_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_headers_headers_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HeaderRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_headers_headers_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HeaderResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_headers_headers_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_headers_headers_proto_goTypes,
DependencyIndexes: file_headers_headers_proto_depIdxs,
MessageInfos: file_headers_headers_proto_msgTypes,
}.Build()
File_headers_headers_proto = out.File
file_headers_headers_proto_rawDesc = nil
file_headers_headers_proto_goTypes = nil
file_headers_headers_proto_depIdxs = nil
}

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
option go_package = "./header";
package header;
message HeaderRequest {}
message HeaderResponse {
repeated string headers = 1;
}
service HeaderService {
rpc Header(HeaderRequest) returns (HeaderResponse) {}
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: headers/headers.proto
package header
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// HeaderServiceClient is the client API for HeaderService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type HeaderServiceClient interface {
Header(ctx context.Context, in *HeaderRequest, opts ...grpc.CallOption) (*HeaderResponse, error)
}
type headerServiceClient struct {
cc grpc.ClientConnInterface
}
func NewHeaderServiceClient(cc grpc.ClientConnInterface) HeaderServiceClient {
return &headerServiceClient{cc}
}
func (c *headerServiceClient) Header(ctx context.Context, in *HeaderRequest, opts ...grpc.CallOption) (*HeaderResponse, error) {
out := new(HeaderResponse)
err := c.cc.Invoke(ctx, "/header.HeaderService/Header", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// HeaderServiceServer is the server API for HeaderService service.
// All implementations must embed UnimplementedHeaderServiceServer
// for forward compatibility
type HeaderServiceServer interface {
Header(context.Context, *HeaderRequest) (*HeaderResponse, error)
mustEmbedUnimplementedHeaderServiceServer()
}
// UnimplementedHeaderServiceServer must be embedded to have forward compatible implementations.
type UnimplementedHeaderServiceServer struct {
}
func (UnimplementedHeaderServiceServer) Header(context.Context, *HeaderRequest) (*HeaderResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Header not implemented")
}
func (UnimplementedHeaderServiceServer) mustEmbedUnimplementedHeaderServiceServer() {}
// UnsafeHeaderServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to HeaderServiceServer will
// result in compilation errors.
type UnsafeHeaderServiceServer interface {
mustEmbedUnimplementedHeaderServiceServer()
}
func RegisterHeaderServiceServer(s grpc.ServiceRegistrar, srv HeaderServiceServer) {
s.RegisterService(&HeaderService_ServiceDesc, srv)
}
func _HeaderService_Header_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HeaderRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HeaderServiceServer).Header(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/header.HeaderService/Header",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeaderServiceServer).Header(ctx, req.(*HeaderRequest))
}
return interceptor(ctx, in, info, handler)
}
// HeaderService_ServiceDesc is the grpc.ServiceDesc for HeaderService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var HeaderService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "header.HeaderService",
HandlerType: (*HeaderServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Header",
Handler: _HeaderService_Header_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "headers/headers.proto",
}

View File

@@ -0,0 +1,69 @@
package grpc
import (
"context"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/headers"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcHeader(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
header.RegisterHeaderServiceServer(srv, &HeaderServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
conn, err := grpc.DialContext(context.Background(), "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
headers := metadata.New(map[string]string{
"X-Test": "testing",
})
ctx := metadata.NewOutgoingContext(context.Background(), headers)
client := header.NewHeaderServiceClient(conn)
res, err := client.Header(ctx, &header.HeaderRequest{})
if _, ok := status.FromError(err); !ok {
t.Errorf("Header returned type %T, want %T", err, status.Error)
}
expected := ".*testing.*"
r := regexp.MustCompile(expected)
if !r.MatchString(res.String()) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res, expected)
}
}

70
pkg/api/grpc/info.go Normal file
View File

@@ -0,0 +1,70 @@
package grpc
import (
"context"
"go.uber.org/zap"
"log"
"runtime"
"strconv"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/info"
"github.com/stefanprodan/podinfo/pkg/version"
)
type infoServer struct {
pb.UnimplementedInfoServiceServer
config *Config
logger *zap.Logger
}
func (s *infoServer) Info(ctx context.Context, message *pb.InfoRequest) (*pb.InfoResponse, error) {
defer func() {
if r := recover(); r != nil {
log.Println("Recovered from panic:", r)
}
}()
data := RuntimeResponse{
Hostname: s.config.Hostname,
Version: version.VERSION,
Revision: version.REVISION,
Color: s.config.UIColor,
Logo: s.config.UILogo,
Message: s.config.UIMessage,
Goos: runtime.GOOS,
Goarch: runtime.GOARCH,
Runtime: runtime.Version(),
Numgoroutine: strconv.FormatInt(int64(runtime.NumGoroutine()), 10),
Numcpu: strconv.FormatInt(int64(runtime.NumCPU()), 10),
}
return &pb.InfoResponse{
Hostname: data.Hostname,
Version: data.Version,
Revision: data.Revision,
Color: data.Color,
Logo: data.Logo,
Message: data.Message,
Goos: data.Goos,
Goarch: data.Goarch,
Runtime: data.Runtime,
Numgoroutine: data.Numgoroutine,
Numcpu: data.Numcpu,
}, nil
}
type RuntimeResponse struct {
Hostname string `json:"hostname"`
Version string `json:"version"`
Revision string `json:"revision"`
Color string `json:"color"`
Logo string `json:"logo"`
Message string `json:"message"`
Goos string `json:"goos"`
Goarch string `json:"goarch"`
Runtime string `json:"runtime"`
Numgoroutine string `json:"num_goroutine"`
Numcpu string `json:"num_cpu"`
}

View File

@@ -0,0 +1,296 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: info/info.proto
package info
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type InfoRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *InfoRequest) Reset() {
*x = InfoRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_info_info_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InfoRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InfoRequest) ProtoMessage() {}
func (x *InfoRequest) ProtoReflect() protoreflect.Message {
mi := &file_info_info_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InfoRequest.ProtoReflect.Descriptor instead.
func (*InfoRequest) Descriptor() ([]byte, []int) {
return file_info_info_proto_rawDescGZIP(), []int{0}
}
type InfoResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
Color string `protobuf:"bytes,4,opt,name=color,proto3" json:"color,omitempty"`
Logo string `protobuf:"bytes,5,opt,name=logo,proto3" json:"logo,omitempty"`
Message string `protobuf:"bytes,6,opt,name=message,proto3" json:"message,omitempty"`
Goos string `protobuf:"bytes,7,opt,name=goos,proto3" json:"goos,omitempty"`
Goarch string `protobuf:"bytes,8,opt,name=goarch,proto3" json:"goarch,omitempty"`
Runtime string `protobuf:"bytes,9,opt,name=runtime,proto3" json:"runtime,omitempty"`
Numgoroutine string `protobuf:"bytes,10,opt,name=numgoroutine,proto3" json:"numgoroutine,omitempty"`
Numcpu string `protobuf:"bytes,11,opt,name=numcpu,proto3" json:"numcpu,omitempty"`
}
func (x *InfoResponse) Reset() {
*x = InfoResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_info_info_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InfoResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InfoResponse) ProtoMessage() {}
func (x *InfoResponse) ProtoReflect() protoreflect.Message {
mi := &file_info_info_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InfoResponse.ProtoReflect.Descriptor instead.
func (*InfoResponse) Descriptor() ([]byte, []int) {
return file_info_info_proto_rawDescGZIP(), []int{1}
}
func (x *InfoResponse) GetHostname() string {
if x != nil {
return x.Hostname
}
return ""
}
func (x *InfoResponse) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *InfoResponse) GetRevision() string {
if x != nil {
return x.Revision
}
return ""
}
func (x *InfoResponse) GetColor() string {
if x != nil {
return x.Color
}
return ""
}
func (x *InfoResponse) GetLogo() string {
if x != nil {
return x.Logo
}
return ""
}
func (x *InfoResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *InfoResponse) GetGoos() string {
if x != nil {
return x.Goos
}
return ""
}
func (x *InfoResponse) GetGoarch() string {
if x != nil {
return x.Goarch
}
return ""
}
func (x *InfoResponse) GetRuntime() string {
if x != nil {
return x.Runtime
}
return ""
}
func (x *InfoResponse) GetNumgoroutine() string {
if x != nil {
return x.Numgoroutine
}
return ""
}
func (x *InfoResponse) GetNumcpu() string {
if x != nil {
return x.Numcpu
}
return ""
}
var File_info_info_proto protoreflect.FileDescriptor
var file_info_info_proto_rawDesc = []byte{
0x0a, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x0d, 0x0a, 0x0b, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa6, 0x02, 0x0a, 0x0c, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a,
0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12,
0x12, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c,
0x6f, 0x67, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x67, 0x6f, 0x6f, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x6f, 0x6f,
0x73, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x6f, 0x61, 0x72, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x67, 0x6f, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e,
0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74,
0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x67, 0x6f, 0x72, 0x6f, 0x75, 0x74,
0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x67, 0x6f,
0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x63, 0x70,
0x75, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x63, 0x70, 0x75, 0x32,
0x3e, 0x0a, 0x0b, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2f,
0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x11, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x49, 0x6e,
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x69, 0x6e, 0x66, 0x6f,
0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_info_info_proto_rawDescOnce sync.Once
file_info_info_proto_rawDescData = file_info_info_proto_rawDesc
)
func file_info_info_proto_rawDescGZIP() []byte {
file_info_info_proto_rawDescOnce.Do(func() {
file_info_info_proto_rawDescData = protoimpl.X.CompressGZIP(file_info_info_proto_rawDescData)
})
return file_info_info_proto_rawDescData
}
var file_info_info_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_info_info_proto_goTypes = []interface{}{
(*InfoRequest)(nil), // 0: info.InfoRequest
(*InfoResponse)(nil), // 1: info.InfoResponse
}
var file_info_info_proto_depIdxs = []int32{
0, // 0: info.InfoService.Info:input_type -> info.InfoRequest
1, // 1: info.InfoService.Info:output_type -> info.InfoResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_info_info_proto_init() }
func file_info_info_proto_init() {
if File_info_info_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_info_info_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InfoRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_info_info_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InfoResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_info_info_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_info_info_proto_goTypes,
DependencyIndexes: file_info_info_proto_depIdxs,
MessageInfos: file_info_info_proto_msgTypes,
}.Build()
File_info_info_proto = out.File
file_info_info_proto_rawDesc = nil
file_info_info_proto_goTypes = nil
file_info_info_proto_depIdxs = nil
}

View File

@@ -0,0 +1,25 @@
syntax = "proto3";
option go_package = "./info";
package info;
message InfoRequest {}
message InfoResponse {
string hostname = 1;
string version = 2;
string revision = 3;
string color = 4 ;
string logo = 5 ;
string message = 6 ;
string goos = 7;
string goarch = 8;
string runtime = 9;
string numgoroutine = 10;
string numcpu = 11;
}
service InfoService {
rpc Info (InfoRequest) returns (InfoResponse) {}
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: info/info.proto
package info
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// InfoServiceClient is the client API for InfoService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type InfoServiceClient interface {
Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error)
}
type infoServiceClient struct {
cc grpc.ClientConnInterface
}
func NewInfoServiceClient(cc grpc.ClientConnInterface) InfoServiceClient {
return &infoServiceClient{cc}
}
func (c *infoServiceClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
out := new(InfoResponse)
err := c.cc.Invoke(ctx, "/info.InfoService/Info", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// InfoServiceServer is the server API for InfoService service.
// All implementations must embed UnimplementedInfoServiceServer
// for forward compatibility
type InfoServiceServer interface {
Info(context.Context, *InfoRequest) (*InfoResponse, error)
mustEmbedUnimplementedInfoServiceServer()
}
// UnimplementedInfoServiceServer must be embedded to have forward compatible implementations.
type UnimplementedInfoServiceServer struct {
}
func (UnimplementedInfoServiceServer) Info(context.Context, *InfoRequest) (*InfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
}
func (UnimplementedInfoServiceServer) mustEmbedUnimplementedInfoServiceServer() {}
// UnsafeInfoServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to InfoServiceServer will
// result in compilation errors.
type UnsafeInfoServiceServer interface {
mustEmbedUnimplementedInfoServiceServer()
}
func RegisterInfoServiceServer(s grpc.ServiceRegistrar, srv InfoServiceServer) {
s.RegisterService(&InfoService_ServiceDesc, srv)
}
func _InfoService_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InfoServiceServer).Info(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/info.InfoService/Info",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InfoServiceServer).Info(ctx, req.(*InfoRequest))
}
return interceptor(ctx, in, info, handler)
}
// InfoService_ServiceDesc is the grpc.ServiceDesc for InfoService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var InfoService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "info.InfoService",
HandlerType: (*InfoServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Info",
Handler: _InfoService_Info_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "info/info.proto",
}

65
pkg/api/grpc/info_test.go Normal file
View File

@@ -0,0 +1,65 @@
package grpc
import (
"context"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/info"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcInfo(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
s := NewMockGrpcServer()
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
info.RegisterInfoServiceServer(srv, &infoServer{config: s.config})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := info.NewInfoServiceClient(conn)
res, err := client.Info(context.Background(), &info.InfoRequest{})
if _, ok := status.FromError(err); !ok {
t.Errorf("Info returned type %T, want %T", err, status.Error)
}
expected := ".*color.*blue.*"
r := regexp.MustCompile(expected)
if !r.MatchString(res.String()) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res.Color, expected)
}
}

30
pkg/api/grpc/mock_grpc.go Normal file
View File

@@ -0,0 +1,30 @@
package grpc
import (
"go.uber.org/zap"
)
func NewMockGrpcServer() *Server {
config := &Config{
Port: 9999,
// ServerShutdownTimeout: 5 * time.Second,
// HttpServerTimeout: 30 * time.Second,
BackendURL: []string{},
ConfigPath: "/config",
DataPath: "/data",
// HttpClientTimeout: 30 * time.Second,
UIColor: "blue",
UIPath: ".ui",
UIMessage: "Greetings",
Hostname: "localhost",
}
logger, _ := zap.NewDevelopment()
return &Server{
//router: mux.NewRouter(),
logger: logger,
config: config,
//tracer: trace.NewNoopTracerProvider().Tracer("mock"),
}
}

22
pkg/api/grpc/panic.go Normal file
View File

@@ -0,0 +1,22 @@
package grpc
import (
"context"
// "log"
"os"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/panic"
"go.uber.org/zap"
)
type PanicServer struct {
pb.UnimplementedPanicServiceServer
config *Config
logger *zap.Logger
}
func (s *PanicServer) Panic(ctx context.Context, req *pb.PanicRequest) (*pb.PanicResponse, error) {
s.logger.Info("Panic command received")
os.Exit(225)
return &pb.PanicResponse{}, nil
}

View File

@@ -0,0 +1,189 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.6.1
// source: panic.proto
package panic
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type PanicRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *PanicRequest) Reset() {
*x = PanicRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_panic_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PanicRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PanicRequest) ProtoMessage() {}
func (x *PanicRequest) ProtoReflect() protoreflect.Message {
mi := &file_panic_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PanicRequest.ProtoReflect.Descriptor instead.
func (*PanicRequest) Descriptor() ([]byte, []int) {
return file_panic_proto_rawDescGZIP(), []int{0}
}
type PanicResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *PanicResponse) Reset() {
*x = PanicResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_panic_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PanicResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PanicResponse) ProtoMessage() {}
func (x *PanicResponse) ProtoReflect() protoreflect.Message {
mi := &file_panic_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PanicResponse.ProtoReflect.Descriptor instead.
func (*PanicResponse) Descriptor() ([]byte, []int) {
return file_panic_proto_rawDescGZIP(), []int{1}
}
var File_panic_proto protoreflect.FileDescriptor
var file_panic_proto_rawDesc = []byte{
0x0a, 0x0b, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70,
0x61, 0x6e, 0x69, 0x63, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x44, 0x0a, 0x0c, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x12, 0x13,
0x2e, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x2e, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x2e, 0x50, 0x61, 0x6e, 0x69,
0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e,
0x2f, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_panic_proto_rawDescOnce sync.Once
file_panic_proto_rawDescData = file_panic_proto_rawDesc
)
func file_panic_proto_rawDescGZIP() []byte {
file_panic_proto_rawDescOnce.Do(func() {
file_panic_proto_rawDescData = protoimpl.X.CompressGZIP(file_panic_proto_rawDescData)
})
return file_panic_proto_rawDescData
}
var file_panic_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_panic_proto_goTypes = []interface{}{
(*PanicRequest)(nil), // 0: panic.PanicRequest
(*PanicResponse)(nil), // 1: panic.PanicResponse
}
var file_panic_proto_depIdxs = []int32{
0, // 0: panic.PanicService.Panic:input_type -> panic.PanicRequest
1, // 1: panic.PanicService.Panic:output_type -> panic.PanicResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_panic_proto_init() }
func file_panic_proto_init() {
if File_panic_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_panic_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PanicRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_panic_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PanicResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_panic_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_panic_proto_goTypes,
DependencyIndexes: file_panic_proto_depIdxs,
MessageInfos: file_panic_proto_msgTypes,
}.Build()
File_panic_proto = out.File
file_panic_proto_rawDesc = nil
file_panic_proto_goTypes = nil
file_panic_proto_depIdxs = nil
}

View File

@@ -0,0 +1,17 @@
syntax = "proto3";
option go_package = "./panic";
package panic;
// The greeting service definition.
service PanicService {
rpc Panic (PanicRequest) returns (PanicResponse) {}
}
message PanicRequest {
}
message PanicResponse {
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.6.1
// source: panic.proto
package panic
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// PanicServiceClient is the client API for PanicService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PanicServiceClient interface {
Panic(ctx context.Context, in *PanicRequest, opts ...grpc.CallOption) (*PanicResponse, error)
}
type panicServiceClient struct {
cc grpc.ClientConnInterface
}
func NewPanicServiceClient(cc grpc.ClientConnInterface) PanicServiceClient {
return &panicServiceClient{cc}
}
func (c *panicServiceClient) Panic(ctx context.Context, in *PanicRequest, opts ...grpc.CallOption) (*PanicResponse, error) {
out := new(PanicResponse)
err := c.cc.Invoke(ctx, "/panic.PanicService/Panic", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PanicServiceServer is the server API for PanicService service.
// All implementations must embed UnimplementedPanicServiceServer
// for forward compatibility
type PanicServiceServer interface {
Panic(context.Context, *PanicRequest) (*PanicResponse, error)
mustEmbedUnimplementedPanicServiceServer()
}
// UnimplementedPanicServiceServer must be embedded to have forward compatible implementations.
type UnimplementedPanicServiceServer struct {
}
func (UnimplementedPanicServiceServer) Panic(context.Context, *PanicRequest) (*PanicResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Panic not implemented")
}
func (UnimplementedPanicServiceServer) mustEmbedUnimplementedPanicServiceServer() {}
// UnsafePanicServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to PanicServiceServer will
// result in compilation errors.
type UnsafePanicServiceServer interface {
mustEmbedUnimplementedPanicServiceServer()
}
func RegisterPanicServiceServer(s grpc.ServiceRegistrar, srv PanicServiceServer) {
s.RegisterService(&PanicService_ServiceDesc, srv)
}
func _PanicService_Panic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PanicRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PanicServiceServer).Panic(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/panic.PanicService/Panic",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PanicServiceServer).Panic(ctx, req.(*PanicRequest))
}
return interceptor(ctx, in, info, handler)
}
// PanicService_ServiceDesc is the grpc.ServiceDesc for PanicService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var PanicService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "panic.PanicService",
HandlerType: (*PanicServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Panic",
Handler: _PanicService_Panic_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "panic.proto",
}

99
pkg/api/grpc/server.go Normal file
View File

@@ -0,0 +1,99 @@
package grpc
import (
"fmt"
"net"
"github.com/stefanprodan/podinfo/pkg/api/grpc/echo"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/reflection"
"github.com/stefanprodan/podinfo/pkg/api/grpc/delay"
"github.com/stefanprodan/podinfo/pkg/api/grpc/env"
header "github.com/stefanprodan/podinfo/pkg/api/grpc/headers"
"github.com/stefanprodan/podinfo/pkg/api/grpc/info"
"github.com/stefanprodan/podinfo/pkg/api/grpc/panic"
"github.com/stefanprodan/podinfo/pkg/api/grpc/status"
"github.com/stefanprodan/podinfo/pkg/api/grpc/token"
"github.com/stefanprodan/podinfo/pkg/api/grpc/version"
)
type Server struct {
logger *zap.Logger
config *Config
}
type Config struct {
Port int `mapstructure:"grpc-port"`
ServiceName string `mapstructure:"grpc-service-name"`
BackendURL []string `mapstructure:"backend-url"`
UILogo string `mapstructure:"ui-logo"`
UIMessage string `mapstructure:"ui-message"`
UIColor string `mapstructure:"ui-color"`
UIPath string `mapstructure:"ui-path"`
DataPath string `mapstructure:"data-path"`
ConfigPath string `mapstructure:"config-path"`
CertPath string `mapstructure:"cert-path"`
Host string `mapstructure:"host"`
//Port string `mapstructure:"port"`
SecurePort string `mapstructure:"secure-port"`
PortMetrics int `mapstructure:"port-metrics"`
Hostname string `mapstructure:"hostname"`
H2C bool `mapstructure:"h2c"`
RandomDelay bool `mapstructure:"random-delay"`
RandomDelayUnit string `mapstructure:"random-delay-unit"`
RandomDelayMin int `mapstructure:"random-delay-min"`
RandomDelayMax int `mapstructure:"random-delay-max"`
RandomError bool `mapstructure:"random-error"`
Unhealthy bool `mapstructure:"unhealthy"`
Unready bool `mapstructure:"unready"`
JWTSecret string `mapstructure:"jwt-secret"`
CacheServer string `mapstructure:"cache-server"`
}
func NewServer(config *Config, logger *zap.Logger) (*Server, error) {
srv := &Server{
logger: logger,
config: config,
}
return srv, nil
}
func (s *Server) ListenAndServe() *grpc.Server {
listener, err := net.Listen("tcp", fmt.Sprintf(":%v", s.config.Port))
if err != nil {
s.logger.Fatal("failed to listen", zap.Int("port", s.config.Port))
}
srv := grpc.NewServer()
server := health.NewServer()
// Register grpc apis for reflection
echo.RegisterEchoServiceServer(srv, &echoServer{config: s.config, logger: s.logger})
version.RegisterVersionServiceServer(srv, &VersionServer{config: s.config, logger: s.logger})
panic.RegisterPanicServiceServer(srv, &PanicServer{config: s.config, logger: s.logger})
delay.RegisterDelayServiceServer(srv, &DelayServer{config: s.config, logger: s.logger})
header.RegisterHeaderServiceServer(srv, &HeaderServer{config: s.config, logger: s.logger})
info.RegisterInfoServiceServer(srv, &infoServer{config: s.config})
status.RegisterStatusServiceServer(srv, &StatusServer{config: s.config, logger: s.logger})
token.RegisterTokenServiceServer(srv, &TokenServer{config: s.config, logger: s.logger})
env.RegisterEnvServiceServer(srv, &EnvServer{config: s.config, logger: s.logger})
reflection.Register(srv)
grpc_health_v1.RegisterHealthServer(srv, server)
server.SetServingStatus(s.config.ServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
go func() {
if err := srv.Serve(listener); err != nil {
s.logger.Fatal("failed to serve", zap.Error(err))
}
}()
return srv
}

47
pkg/api/grpc/status.go Normal file
View File

@@ -0,0 +1,47 @@
package grpc
import (
"context"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/status"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type StatusServer struct {
pb.UnimplementedStatusServiceServer
config *Config
logger *zap.Logger
}
func (s *StatusServer) Status(ctx context.Context, req *pb.StatusRequest) (*pb.StatusResponse, error) {
reqCode := req.GetCode()
grpcCodes := map[string]codes.Code{
"Ok": codes.OK,
"Canceled": codes.Canceled,
"Unknown": codes.Unknown,
"InvalidArgument": codes.InvalidArgument,
"DeadlineExceeded": codes.DeadlineExceeded,
"NotFound": codes.NotFound,
"AlreadyExists": codes.AlreadyExists,
"PermissionDenied": codes.PermissionDenied,
"ResourceExhausted": codes.ResourceExhausted,
"FailedPrecondition": codes.FailedPrecondition,
"Aborted": codes.Aborted,
"OutOfRange": codes.OutOfRange,
"Unimplemented": codes.Unimplemented,
"Internal": codes.Internal,
"Unavailable": codes.Unavailable,
"DataLoss": codes.DataLoss,
"Unauthenticated": codes.Unauthenticated,
}
code, ok := grpcCodes[reqCode]
if !ok {
return nil, status.Error(codes.Unknown, "Unknown status code for more information check https://chromium.googlesource.com/external/github.com/grpc/grpc/+/refs/tags/v1.21.4-pre1/doc/statuscodes.md")
}
return &pb.StatusResponse{Status: reqCode}, status.Error(code, "")
}

View File

@@ -0,0 +1,211 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: status/status.proto
package status
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StatusRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
}
func (x *StatusRequest) Reset() {
*x = StatusRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_status_status_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StatusRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StatusRequest) ProtoMessage() {}
func (x *StatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_status_status_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead.
func (*StatusRequest) Descriptor() ([]byte, []int) {
return file_status_status_proto_rawDescGZIP(), []int{0}
}
func (x *StatusRequest) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
type StatusResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *StatusResponse) Reset() {
*x = StatusResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_status_status_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StatusResponse) ProtoMessage() {}
func (x *StatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_status_status_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead.
func (*StatusResponse) Descriptor() ([]byte, []int) {
return file_status_status_proto_rawDescGZIP(), []int{1}
}
func (x *StatusResponse) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
var File_status_status_proto protoreflect.FileDescriptor
var file_status_status_proto_rawDesc = []byte{
0x0a, 0x13, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x23, 0x0a,
0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x22, 0x28, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x4a, 0x0a, 0x0d,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a,
0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x73, 0x74,
0x61, 0x74, 0x75, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_status_status_proto_rawDescOnce sync.Once
file_status_status_proto_rawDescData = file_status_status_proto_rawDesc
)
func file_status_status_proto_rawDescGZIP() []byte {
file_status_status_proto_rawDescOnce.Do(func() {
file_status_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_status_status_proto_rawDescData)
})
return file_status_status_proto_rawDescData
}
var file_status_status_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_status_status_proto_goTypes = []interface{}{
(*StatusRequest)(nil), // 0: status.StatusRequest
(*StatusResponse)(nil), // 1: status.StatusResponse
}
var file_status_status_proto_depIdxs = []int32{
0, // 0: status.StatusService.Status:input_type -> status.StatusRequest
1, // 1: status.StatusService.Status:output_type -> status.StatusResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_status_status_proto_init() }
func file_status_status_proto_init() {
if File_status_status_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_status_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StatusRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_status_status_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StatusResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_status_status_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_status_status_proto_goTypes,
DependencyIndexes: file_status_status_proto_depIdxs,
MessageInfos: file_status_status_proto_msgTypes,
}.Build()
File_status_status_proto = out.File
file_status_status_proto_rawDesc = nil
file_status_status_proto_goTypes = nil
file_status_status_proto_depIdxs = nil
}

View File

@@ -0,0 +1,18 @@
syntax = "proto3";
option go_package = "./status";
package status;
// The greeting service definition.
service StatusService {
rpc Status (StatusRequest) returns (StatusResponse) {}
}
message StatusRequest {
string code = 1;
}
message StatusResponse {
string status = 1;
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: status/status.proto
package status
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// StatusServiceClient is the client API for StatusService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type StatusServiceClient interface {
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
}
type statusServiceClient struct {
cc grpc.ClientConnInterface
}
func NewStatusServiceClient(cc grpc.ClientConnInterface) StatusServiceClient {
return &statusServiceClient{cc}
}
func (c *statusServiceClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
out := new(StatusResponse)
err := c.cc.Invoke(ctx, "/status.StatusService/Status", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// StatusServiceServer is the server API for StatusService service.
// All implementations must embed UnimplementedStatusServiceServer
// for forward compatibility
type StatusServiceServer interface {
Status(context.Context, *StatusRequest) (*StatusResponse, error)
mustEmbedUnimplementedStatusServiceServer()
}
// UnimplementedStatusServiceServer must be embedded to have forward compatible implementations.
type UnimplementedStatusServiceServer struct {
}
func (UnimplementedStatusServiceServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Status not implemented")
}
func (UnimplementedStatusServiceServer) mustEmbedUnimplementedStatusServiceServer() {}
// UnsafeStatusServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to StatusServiceServer will
// result in compilation errors.
type UnsafeStatusServiceServer interface {
mustEmbedUnimplementedStatusServiceServer()
}
func RegisterStatusServiceServer(s grpc.ServiceRegistrar, srv StatusServiceServer) {
s.RegisterService(&StatusService_ServiceDesc, srv)
}
func _StatusService_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StatusServiceServer).Status(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/status.StatusService/Status",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StatusServiceServer).Status(ctx, req.(*StatusRequest))
}
return interceptor(ctx, in, info, handler)
}
// StatusService_ServiceDesc is the grpc.ServiceDesc for StatusService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var StatusService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "status.StatusService",
HandlerType: (*StatusServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Status",
Handler: _StatusService_Status_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "status/status.proto",
}

124
pkg/api/grpc/status_test.go Normal file
View File

@@ -0,0 +1,124 @@
package grpc
import (
"context"
"fmt"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
st "google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcStatusError(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
status.RegisterStatusServiceServer(srv, &StatusServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := status.NewStatusServiceClient(conn)
res, err := client.Status(context.Background(), &status.StatusRequest{Code: "NotFound"})
if err != nil {
if e, ok := st.FromError(err); ok {
if e.Code() != codes.NotFound {
if res != nil {
fmt.Printf("res %v\n", res)
}
t.Errorf("Status returned %s, want %s", fmt.Sprint(e.Code()), fmt.Sprint(codes.Aborted))
}
}
}
}
func TestGrpcStatusOk(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
status.RegisterStatusServiceServer(srv, &StatusServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := status.NewStatusServiceClient(conn)
res, err := client.Status(context.Background(), &status.StatusRequest{Code: "Ok"})
if err != nil {
if e, ok := st.FromError(err); ok {
t.Errorf("Status returned %s, want %s", fmt.Sprint(e.Code()), fmt.Sprint(codes.OK))
}
}
expected := ".*Ok.*"
r := regexp.MustCompile(expected)
if res != nil {
if !r.MatchString(res.Status) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res, expected)
}
}
}

103
pkg/api/grpc/token.go Normal file
View File

@@ -0,0 +1,103 @@
package grpc
import (
"context"
"strings"
"time"
"github.com/golang-jwt/jwt/v4"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/token"
)
type TokenServer struct {
pb.UnimplementedTokenServiceServer
config *Config
logger *zap.Logger
}
type jwtCustomClaims struct {
Name string `json:"name"`
jwt.StandardClaims
}
func (s *TokenServer) TokenGenerate(ctx context.Context, req *pb.TokenRequest) (*pb.TokenResponse, error) {
user := "anonymous"
expiresAt := time.Now().Add(time.Minute * 1).Unix()
claims := &jwtCustomClaims{
user,
jwt.StandardClaims{
Issuer: "podinfo",
ExpiresAt: expiresAt,
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
t, err := token.SignedString([]byte(s.config.JWTSecret))
if err != nil {
s.logger.Error("Failed to generate token", zap.Error(err))
return &pb.TokenResponse{}, err
}
var result = pb.TokenResponse{
Token: t,
ExpiresAt: time.Unix(claims.StandardClaims.ExpiresAt, 0).String(),
Message: "Token generated successfully",
}
return &result, nil
}
func (s *TokenServer) TokenValidate(ctx context.Context, req *pb.TokenRequest) (*pb.TokenResponse, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.DataLoss, "UnaryEcho: failed to get metadata")
}
authorization := md.Get("authorization")
if len(authorization) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Authorization token not found in metadata")
}
token := strings.TrimSpace(strings.TrimPrefix(authorization[0], "Bearer"))
claims := jwtCustomClaims{}
parsed_token, err := jwt.ParseWithClaims(token, &claims, func(parsed_token *jwt.Token) (interface{}, error) {
if _, ok := parsed_token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, status.Errorf(codes.Canceled, "invalid signing method")
}
return []byte(s.config.JWTSecret), nil
})
if err != nil {
if strings.Contains(err.Error(), "token is expired") || strings.Contains(err.Error(), "signature is invalid") {
return &pb.TokenResponse{
Message: err.Error(),
}, nil
}
return nil, status.Errorf(codes.Unauthenticated, "Unable to parse token")
}
if parsed_token.Valid {
if claims.StandardClaims.Issuer != "podinfo" {
return nil, status.Errorf(codes.OK, "Invalid issuer")
} else {
var result = pb.TokenResponse{
Token: claims.Name,
ExpiresAt: time.Unix(claims.StandardClaims.ExpiresAt, 0).String(),
}
return &result, nil
}
} else {
return nil, status.Errorf(codes.Unauthenticated, "Unauthenticated")
}
}

View File

@@ -0,0 +1,226 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.0
// source: token/token.proto
package token
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type TokenRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *TokenRequest) Reset() {
*x = TokenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_token_token_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TokenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenRequest) ProtoMessage() {}
func (x *TokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_token_token_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenRequest.ProtoReflect.Descriptor instead.
func (*TokenRequest) Descriptor() ([]byte, []int) {
return file_token_token_proto_rawDescGZIP(), []int{0}
}
type TokenResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
ExpiresAt string `protobuf:"bytes,2,opt,name=expiresAt,proto3" json:"expiresAt,omitempty"`
Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *TokenResponse) Reset() {
*x = TokenResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_token_token_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TokenResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenResponse) ProtoMessage() {}
func (x *TokenResponse) ProtoReflect() protoreflect.Message {
mi := &file_token_token_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenResponse.ProtoReflect.Descriptor instead.
func (*TokenResponse) Descriptor() ([]byte, []int) {
return file_token_token_proto_rawDescGZIP(), []int{1}
}
func (x *TokenResponse) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *TokenResponse) GetExpiresAt() string {
if x != nil {
return x.ExpiresAt
}
return ""
}
func (x *TokenResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_token_token_proto protoreflect.FileDescriptor
var file_token_token_proto_rawDesc = []byte{
0x0a, 0x11, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x0e, 0x0a, 0x0c, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5d, 0x0a, 0x0d, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12,
0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x8a, 0x01, 0x0a, 0x0c, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x14, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14,
0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_token_token_proto_rawDescOnce sync.Once
file_token_token_proto_rawDescData = file_token_token_proto_rawDesc
)
func file_token_token_proto_rawDescGZIP() []byte {
file_token_token_proto_rawDescOnce.Do(func() {
file_token_token_proto_rawDescData = protoimpl.X.CompressGZIP(file_token_token_proto_rawDescData)
})
return file_token_token_proto_rawDescData
}
var file_token_token_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_token_token_proto_goTypes = []interface{}{
(*TokenRequest)(nil), // 0: token.TokenRequest
(*TokenResponse)(nil), // 1: token.TokenResponse
}
var file_token_token_proto_depIdxs = []int32{
0, // 0: token.TokenService.TokenGenerate:input_type -> token.TokenRequest
0, // 1: token.TokenService.TokenValidate:input_type -> token.TokenRequest
1, // 2: token.TokenService.TokenGenerate:output_type -> token.TokenResponse
1, // 3: token.TokenService.TokenValidate:output_type -> token.TokenResponse
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_token_token_proto_init() }
func file_token_token_proto_init() {
if File_token_token_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_token_token_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TokenRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_token_token_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TokenResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_token_token_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_token_token_proto_goTypes,
DependencyIndexes: file_token_token_proto_depIdxs,
MessageInfos: file_token_token_proto_msgTypes,
}.Build()
File_token_token_proto = out.File
file_token_token_proto_rawDesc = nil
file_token_token_proto_goTypes = nil
file_token_token_proto_depIdxs = nil
}

View File

@@ -0,0 +1,20 @@
syntax = "proto3";
option go_package = "./token";
package token;
// The greeting service definition.
service TokenService {
rpc TokenGenerate (TokenRequest) returns (TokenResponse) {}
rpc TokenValidate (TokenRequest) returns (TokenResponse) {}
}
message TokenRequest {}
message TokenResponse {
string token = 1;
string expiresAt = 2;
string message = 3;
}

View File

@@ -0,0 +1,141 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.0
// source: token/token.proto
package token
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// TokenServiceClient is the client API for TokenService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TokenServiceClient interface {
TokenGenerate(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error)
TokenValidate(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error)
}
type tokenServiceClient struct {
cc grpc.ClientConnInterface
}
func NewTokenServiceClient(cc grpc.ClientConnInterface) TokenServiceClient {
return &tokenServiceClient{cc}
}
func (c *tokenServiceClient) TokenGenerate(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error) {
out := new(TokenResponse)
err := c.cc.Invoke(ctx, "/token.TokenService/TokenGenerate", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokenServiceClient) TokenValidate(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error) {
out := new(TokenResponse)
err := c.cc.Invoke(ctx, "/token.TokenService/TokenValidate", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// TokenServiceServer is the server API for TokenService service.
// All implementations must embed UnimplementedTokenServiceServer
// for forward compatibility
type TokenServiceServer interface {
TokenGenerate(context.Context, *TokenRequest) (*TokenResponse, error)
TokenValidate(context.Context, *TokenRequest) (*TokenResponse, error)
mustEmbedUnimplementedTokenServiceServer()
}
// UnimplementedTokenServiceServer must be embedded to have forward compatible implementations.
type UnimplementedTokenServiceServer struct {
}
func (UnimplementedTokenServiceServer) TokenGenerate(context.Context, *TokenRequest) (*TokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method TokenGenerate not implemented")
}
func (UnimplementedTokenServiceServer) TokenValidate(context.Context, *TokenRequest) (*TokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method TokenValidate not implemented")
}
func (UnimplementedTokenServiceServer) mustEmbedUnimplementedTokenServiceServer() {}
// UnsafeTokenServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TokenServiceServer will
// result in compilation errors.
type UnsafeTokenServiceServer interface {
mustEmbedUnimplementedTokenServiceServer()
}
func RegisterTokenServiceServer(s grpc.ServiceRegistrar, srv TokenServiceServer) {
s.RegisterService(&TokenService_ServiceDesc, srv)
}
func _TokenService_TokenGenerate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokenServiceServer).TokenGenerate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/token.TokenService/TokenGenerate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokenServiceServer).TokenGenerate(ctx, req.(*TokenRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TokenService_TokenValidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokenServiceServer).TokenValidate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/token.TokenService/TokenValidate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokenServiceServer).TokenValidate(ctx, req.(*TokenRequest))
}
return interceptor(ctx, in, info, handler)
}
// TokenService_ServiceDesc is the grpc.ServiceDesc for TokenService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TokenService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "token.TokenService",
HandlerType: (*TokenServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "TokenGenerate",
Handler: _TokenService_TokenGenerate_Handler,
},
{
MethodName: "TokenValidate",
Handler: _TokenService_TokenValidate_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "token/token.proto",
}

View File

@@ -0,0 +1,66 @@
package grpc
import (
"context"
"log"
"net"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/token"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcToken(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
config := &Config{}
config.JWTSecret = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
token.RegisterTokenServiceServer(srv, &TokenServer{config: config})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := token.NewTokenServiceClient(conn)
res, err := client.TokenGenerate(context.Background(), &token.TokenRequest{})
if _, ok := status.FromError(err); !ok {
t.Errorf("Token Handler returned type %T, want %T", err, status.Error)
}
var token = token.TokenResponse{
Token: res.Token,
ExpiresAt: res.ExpiresAt,
}
if token.Token == "" {
t.Fatalf("Handler returned no token")
}
}

19
pkg/api/grpc/version.go Normal file
View File

@@ -0,0 +1,19 @@
package grpc
import (
"context"
pb "github.com/stefanprodan/podinfo/pkg/api/grpc/version"
"github.com/stefanprodan/podinfo/pkg/version"
"go.uber.org/zap"
)
type VersionServer struct {
pb.UnimplementedVersionServiceServer
config *Config
logger *zap.Logger
}
func (s *VersionServer) Version(ctx context.Context, req *pb.VersionRequest) (*pb.VersionResponse, error) {
return &pb.VersionResponse{Version: version.VERSION, Commit: version.REVISION}, nil
}

View File

@@ -0,0 +1,211 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.6.1
// source: version.proto
package version
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type VersionRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *VersionRequest) Reset() {
*x = VersionRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_version_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VersionRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VersionRequest) ProtoMessage() {}
func (x *VersionRequest) ProtoReflect() protoreflect.Message {
mi := &file_version_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VersionRequest.ProtoReflect.Descriptor instead.
func (*VersionRequest) Descriptor() ([]byte, []int) {
return file_version_proto_rawDescGZIP(), []int{0}
}
type VersionResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
Commit string `protobuf:"bytes,2,opt,name=commit,proto3" json:"commit,omitempty"`
}
func (x *VersionResponse) Reset() {
*x = VersionResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_version_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VersionResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VersionResponse) ProtoMessage() {}
func (x *VersionResponse) ProtoReflect() protoreflect.Message {
mi := &file_version_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead.
func (*VersionResponse) Descriptor() ([]byte, []int) {
return file_version_proto_rawDescGZIP(), []int{1}
}
func (x *VersionResponse) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *VersionResponse) GetCommit() string {
if x != nil {
return x.Commit
}
return ""
}
var File_version_proto protoreflect.FileDescriptor
var file_version_proto_rawDesc = []byte{
0x0a, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x0f, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x32,
0x50, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x3e, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_version_proto_rawDescOnce sync.Once
file_version_proto_rawDescData = file_version_proto_rawDesc
)
func file_version_proto_rawDescGZIP() []byte {
file_version_proto_rawDescOnce.Do(func() {
file_version_proto_rawDescData = protoimpl.X.CompressGZIP(file_version_proto_rawDescData)
})
return file_version_proto_rawDescData
}
var file_version_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_version_proto_goTypes = []interface{}{
(*VersionRequest)(nil), // 0: version.VersionRequest
(*VersionResponse)(nil), // 1: version.VersionResponse
}
var file_version_proto_depIdxs = []int32{
0, // 0: version.VersionService.Version:input_type -> version.VersionRequest
1, // 1: version.VersionService.Version:output_type -> version.VersionResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_version_proto_init() }
func file_version_proto_init() {
if File_version_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_version_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*VersionRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_version_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*VersionResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_version_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_version_proto_goTypes,
DependencyIndexes: file_version_proto_depIdxs,
MessageInfos: file_version_proto_msgTypes,
}.Build()
File_version_proto = out.File
file_version_proto_rawDesc = nil
file_version_proto_goTypes = nil
file_version_proto_depIdxs = nil
}

View File

@@ -0,0 +1,18 @@
syntax = "proto3";
option go_package = "./version";
package version;
service VersionService {
rpc Version (VersionRequest) returns (VersionResponse) {}
}
message VersionRequest {}
message VersionResponse {
string version = 1;
string commit = 2;
}

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.6.1
// source: version.proto
package version
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// VersionServiceClient is the client API for VersionService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type VersionServiceClient interface {
Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error)
}
type versionServiceClient struct {
cc grpc.ClientConnInterface
}
func NewVersionServiceClient(cc grpc.ClientConnInterface) VersionServiceClient {
return &versionServiceClient{cc}
}
func (c *versionServiceClient) Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) {
out := new(VersionResponse)
err := c.cc.Invoke(ctx, "/version.VersionService/Version", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// VersionServiceServer is the server API for VersionService service.
// All implementations must embed UnimplementedVersionServiceServer
// for forward compatibility
type VersionServiceServer interface {
Version(context.Context, *VersionRequest) (*VersionResponse, error)
mustEmbedUnimplementedVersionServiceServer()
}
// UnimplementedVersionServiceServer must be embedded to have forward compatible implementations.
type UnimplementedVersionServiceServer struct {
}
func (UnimplementedVersionServiceServer) Version(context.Context, *VersionRequest) (*VersionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
}
func (UnimplementedVersionServiceServer) mustEmbedUnimplementedVersionServiceServer() {}
// UnsafeVersionServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to VersionServiceServer will
// result in compilation errors.
type UnsafeVersionServiceServer interface {
mustEmbedUnimplementedVersionServiceServer()
}
func RegisterVersionServiceServer(s grpc.ServiceRegistrar, srv VersionServiceServer) {
s.RegisterService(&VersionService_ServiceDesc, srv)
}
func _VersionService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VersionRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(VersionServiceServer).Version(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/version.VersionService/Version",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(VersionServiceServer).Version(ctx, req.(*VersionRequest))
}
return interceptor(ctx, in, info, handler)
}
// VersionService_ServiceDesc is the grpc.ServiceDesc for VersionService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var VersionService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "version.VersionService",
HandlerType: (*VersionServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Version",
Handler: _VersionService_Version_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "version.proto",
}

View File

@@ -0,0 +1,66 @@
package grpc
import (
"context"
"fmt"
"log"
"net"
"regexp"
"testing"
"github.com/stefanprodan/podinfo/pkg/api/grpc/version"
v "github.com/stefanprodan/podinfo/pkg/version"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)
func TestGrpcVersion(t *testing.T) {
lis := bufconn.Listen(1024 * 1024)
t.Cleanup(func() {
lis.Close()
})
srv := grpc.NewServer()
t.Cleanup(func() {
srv.Stop()
})
version.RegisterVersionServiceServer(srv, &VersionServer{})
go func() {
if err := srv.Serve(lis); err != nil {
log.Fatalf("srv.Serve %v", err)
}
}()
dialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
ctx := context.Background()
conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer(dialer), grpc.WithInsecure())
t.Cleanup(func() {
conn.Close()
})
if err != nil {
t.Fatalf("grpc.DialContext %v", err)
}
client := version.NewVersionServiceClient(conn)
res, err := client.Version(context.Background(), &version.VersionRequest{})
if _, ok := status.FromError(err); !ok {
t.Errorf("Version returned type %T, want %T", err, status.Error)
}
expected := fmt.Sprintf(".*%s.*", v.VERSION)
r := regexp.MustCompile(expected)
if !r.MatchString(res.String()) {
t.Fatalf("Returned unexpected body:\ngot \n%v \nwant \n%s",
res, expected)
}
}

Some files were not shown because too many files have changed in this diff Show More