Compare commits

...

331 Commits
6.0.2 ... 6.8.0

Author SHA1 Message Date
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
Jason
0d2c428859 refactor(trustpolicy): jasonthedeveloper -> stefanprodan 2024-02-09 10:59:44 +11:00
Jason
ecaa7cf4d3 ci(release): trigger on tag push 2024-02-09 10:47:11 +11:00
Jason
8447b6985b ci(notation): remove release workflow 2024-02-09 10:42:51 +11:00
Jason
9371d6d153 ci(release): sign artefacts using notation 2024-02-09 10:41:19 +11:00
Jason
20b8c1043c Merge branch 'master' into feat/notation 2024-02-09 10:14:38 +11:00
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
Stefan Prodan
dc830d02a6 Enable GitHub Sponsors 2023-12-30 22:18:54 +02:00
Stefan Prodan
badf3271a1 Merge pull request #332 from arunsathiya/master
ci: Use `GITHUB_OUTPUT` instead of set-output
2023-12-29 00:11:06 +02:00
Arun
9f9c2f3245 Use GITHUB_OUTPUT envvar instead of set-output command as the latter is deprecated 2023-12-28 13:21:55 -08:00
Stefan Prodan
33dac1ba40 Merge pull request #329 from stefanprodan/release-6.5.4
Release 6.5.4
2023-12-17 16:44:12 +02:00
Stefan Prodan
1cf8b8aeef Release 6.5.4
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-12-17 16:36:33 +02:00
Stefan Prodan
22fb1c3d34 Merge pull request #328 from stefanprodan/timoni-schemas-update
Update Timoni CUE schemas
2023-12-17 16:34:38 +02:00
Stefan Prodan
adf8157da6 Update Timoni CUE schemas
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-12-17 15:53:22 +02:00
Stefan Prodan
03f8ad0251 Merge pull request #327 from stefanprodan/up-deps
Update Go dependencies
2023-12-17 15:18:23 +02:00
Stefan Prodan
101e371e96 Update Go dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-12-17 15:14:43 +02:00
Stefan Prodan
53c9f3ad9b Merge pull request #326 from stefanprodan/alpine-3.19
Update Alpine to 3.19
2023-12-17 15:10:30 +02:00
Stefan Prodan
a69f0282fd Update Alpine to 3.19
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-12-17 15:07:34 +02:00
Jason
174d183056 refactor(rename): policy.json -> trustpolicy.json 2023-12-14 16:16:12 +11:00
Jason
7bb64e7567 fix(trustpolicy): small typo in registryScopes 2023-12-08 17:30:47 +11:00
Jason
49a4b31d53 feat(notation): update registry scopes 2023-12-07 18:06:52 +11:00
Jason
c29e013a33 feat(notation): add trust store policy 2023-12-07 16:57:04 +11:00
Jason
45ecda63bb ci(release): don't trigger on tag push 2023-12-07 16:26:01 +11:00
Jason
4868f430c7 ci(release): trigger on tag 2023-12-07 16:15:17 +11:00
Jason
ca9c6bb4f8 ci(release): sign artefacts using notaiton 2023-12-07 16:06:40 +11:00
Jason
86f3b1a57c ci(release): create notation config folder 2023-12-07 15:52:29 +11:00
Jason
b22dd96a54 feat(notation): add signingkey.json config 2023-12-07 15:51:22 +11:00
Jason
5aaf95849e ci(release): setup signing keys for notation 2023-12-07 15:50:30 +11:00
Jason
e197eca420 ci(release): add notation release workflow 2023-12-07 15:46:22 +11:00
Stefan Prodan
73fcdbe4a6 Merge pull request #320 from duxinxiao/patch-1
Add comment on sleep during graceful shutdown
2023-11-15 13:32:44 +02:00
du
074d0f9ff2 add comment on sleep during graceful shutdown 2023-11-15 18:47:52 +08:00
Stefan Prodan
d9bc6301e9 Merge pull request #316 from stefanprodan/release-6.5.3
Release 6.5.3
2023-10-30 14:38:28 +02:00
Stefan Prodan
a0e323e331 Release 6.5.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 14:27:41 +02:00
Stefan Prodan
1ee349fa17 Merge pull request #315 from stefanprodan/timoni-tests
timoni: Add connectivity test to module
2023-10-30 14:25:12 +02:00
Stefan Prodan
0f526c3cd4 timoni: Run module tests in CI
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 14:11:41 +02:00
Stefan Prodan
021c55fed9 timoni: Add connectivity test to module
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 14:10:25 +02:00
Stefan Prodan
bb2408d17d Merge pull request #314 from stefanprodan/timoni-vet-module
timoni: Add debug values and vet module in CI
2023-10-30 12:56:48 +02:00
Stefan Prodan
5eb3cafd6a timoni: Vet module in CI
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 12:51:28 +02:00
Stefan Prodan
df0f8ba885 timoni: Add debug values
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 12:51:03 +02:00
Stefan Prodan
19a59d96f1 timoni: Update module schemas
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 12:41:21 +02:00
Stefan Prodan
401461595a Merge pull request #313 from stefanprodan/docs-cosign-verify
docs: Verify podinfo release assets with cosign
2023-10-30 12:32:21 +02:00
Stefan Prodan
bd77584ade docs: Verify podinfo release assets with cosign
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-30 12:28:21 +02:00
Stefan Prodan
87e0dbaa7e Merge pull request #312 from stefanprodan/dependabot/go_modules/google.golang.org/grpc-1.58.3
Bump google.golang.org/grpc from 1.58.2 to 1.58.3
2023-10-26 00:38:00 +03:00
dependabot[bot]
c5494104a1 Bump google.golang.org/grpc from 1.58.2 to 1.58.3
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.58.2 to 1.58.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.58.2...v1.58.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 21:27:33 +00:00
Stefan Prodan
74c60a927c Merge pull request #310 from stefanprodan/release-6.5.2
Release 6.5.2
2023-10-12 12:18:47 +03:00
Stefan Prodan
ecdf07c4d5 Release 6.5.2
Fix for CVE-2023-39325 and CVE-2023-38545

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-12 12:11:37 +03:00
Stefan Prodan
ff29c549ff Merge pull request #309 from stefanprodan/dependabot/go_modules/golang.org/x/net-0.17.0
Bump golang.org/x/net from 0.15.0 to 0.17.0
2023-10-12 09:24:03 +03:00
dependabot[bot]
fa75fc0520 Bump golang.org/x/net from 0.15.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.15.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.15.0...v0.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-11 23:14:03 +00:00
Stefan Prodan
0bc496456d Merge pull request #307 from stefanprodan/release-6.5.1
Release 6.5.1
2023-10-02 21:04:32 +03:00
Stefan Prodan
398c543171 Release 6.5.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-02 20:58:27 +03:00
Stefan Prodan
a54dc2a9c7 Merge pull request #306 from stefanprodan/update-otel-deps
Update Go dependencies
2023-10-02 20:57:13 +03:00
Stefan Prodan
bfa42afa1f Bump Go to 1.21
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-02 20:46:06 +03:00
Stefan Prodan
590987704e Update open telemetry packages
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-02 20:45:20 +03:00
Stefan Prodan
d561182076 Merge pull request #305 from stefanprodan/timoni-v0.14
Update module to Timoni v0.14 APIs
2023-10-02 20:41:06 +03:00
Stefan Prodan
72bd6faf35 Update module to Timoni v0.14 APIs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-10-02 20:36:58 +03:00
Stefan Prodan
2cbe0fcdff Merge pull request #304 from stefanprodan/release-6.5.0
Release v6.5.0
2023-09-23 12:35:00 +03:00
Stefan Prodan
87e594b109 Release 6.5.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 12:29:59 +03:00
Stefan Prodan
7ec9e6c84a Merge pull request #303 from stefanprodan/publish-timoni-module
Publish signed Timoni module to GHCR
2023-09-23 12:22:06 +03:00
Stefan Prodan
8183d0d5fc Publish signed Timoni module to GHCR
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 12:16:48 +03:00
Stefan Prodan
aa27416651 Merge pull request #302 from stefanprodan/module-imps
Timoni module improvements
2023-09-23 11:35:47 +03:00
Stefan Prodan
b0594a85b9 Add e2e tests for Timoni module
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 11:29:47 +03:00
Stefan Prodan
e816d1b5bc Add UI configuration
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 10:04:56 +03:00
Stefan Prodan
6316e213d1 Improve monitoring config
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 09:25:25 +03:00
Stefan Prodan
a1b112f4e1 Mark vendored code
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 00:43:20 +03:00
Stefan Prodan
1495fd888e Merge pull request #301 from stefanprodan/timoni-module
Add Timoni module
2023-09-23 00:37:48 +03:00
Stefan Prodan
dfc4a6d37e Add Timoni module
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-23 00:33:36 +03:00
Stefan Prodan
aaa47e535f Merge pull request #300 from stefanprodan/up-deps
Update dependencies
2023-09-22 23:29:36 +03:00
Stefan Prodan
0278e11a05 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-09-22 23:24:32 +03:00
Stefan Prodan
12ceae475f Merge pull request #284 from johankok/add-additional-labels-to-ingress
Added additionalLabels option for ingress in helm chart
2023-09-22 23:13:11 +03:00
Stefan Prodan
4892983fd1 Merge pull request #290 from stefanprodan/release-6.4.1
Release v6.4.1
2023-08-10 15:25:19 +03:00
Stefan Prodan
bcf492e92b Release v6.4.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-08-10 15:10:01 +03:00
Stefan Prodan
a54550e439 Merge pull request #289 from stefanprodan/go-1.21
Build with Go 1.21
2023-08-10 15:08:37 +03:00
Stefan Prodan
29dd482f49 Build with Go 1.21
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-08-10 15:04:03 +03:00
Stefan Prodan
3a7d4d1544 Merge pull request #285 from stefanprodan/up-deps
Update dependencies
2023-08-10 14:59:18 +03:00
Stefan Prodan
c14b116dea Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-08-07 16:20:42 +03:00
Johan Kok
12c078938d Added additionalLabels option for ingress 2023-07-17 17:50:42 +02:00
Stefan Prodan
dd3869b1a1 Merge pull request #274 from stefanprodan/alpine-3.18
Update base image to Alpine 3.18
2023-06-26 13:02:18 +03:00
Stefan Prodan
45cfe3abc2 Update base image to Alpine 3.18
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-06-26 12:57:54 +03:00
Stefan Prodan
fcf573111b Merge pull request #273 from stefanprodan/release-6.4.0
Release 6.4.0
2023-06-26 12:55:42 +03:00
Stefan Prodan
cadabcc6a5 Release 6.4.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-06-26 12:50:40 +03:00
Stefan Prodan
9dfb676083 Sign release tags with OpenPGP
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-06-26 12:49:33 +03:00
Stefan Prodan
e06a5517da Merge pull request #272 from stefanprodan/deps-up
Update dependencies
2023-06-22 18:51:41 +03:00
Stefan Prodan
fedab0de38 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-06-22 18:36:47 +03:00
Stefan Prodan
7d13025a35 Merge pull request #271 from jjchambl/feature/add_dynamic_paths
feat(echo): add dynamic path support for echo endpoint
2023-06-22 18:30:00 +03:00
Jacob Chambliss
7280e43cbf chore: add pathprefix to enable dynamic paths for echo 2023-06-08 10:14:21 -05:00
Jacob Chambliss
3ef0b4cd09 feat: add dynamic path support for echo endpoint 2023-06-07 16:55:25 -05:00
Stefan Prodan
073f1ec5af Merge pull request #265 from stefanprodan/release-6.3.6
Release 6.3.6
2023-05-03 17:26:29 +03:00
Stefan Prodan
1e0307c759 Release 6.3.6
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-05-03 17:22:28 +03:00
Stefan Prodan
d4d75c2fbf Merge pull request #264 from stefanprodan/update-otel
Update dependencies
2023-05-03 17:10:32 +03:00
Stefan Prodan
2a6533c68a Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-05-03 17:00:48 +03:00
Stefan Prodan
0647aea75b Merge pull request #263 from mstiri/feature/add-startup-probe
chart: Add optional startupProbe values
2023-04-22 14:37:35 +02:00
Mossaab Stiri
8c258bb1d8 Add startupProbe for deployment and use a flag to enable/disable it 2023-04-18 13:20:47 +02:00
Stefan Prodan
58726f0bd2 Merge pull request #262 from stefanprodan/update-deps
Update dependencies
2023-04-06 11:21:52 +03:00
Stefan Prodan
bc08542ed3 Generate CUE go.mod in CI
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-04-06 11:18:03 +03:00
Stefan Prodan
bbce3f3f67 Update dependencies
- github.com/spf13/cobra v1.7.0
- github.com/swaggo/http-swagger v1.3.4
- github.com/swaggo/swag v1.8.12
- google.golang.org/grpc v1.54.0

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-04-06 10:35:43 +03:00
Stefan Prodan
67e2c98a60 Merge pull request #260 from stefanprodan/cosign-update
Update sigstore/cosign-installer to v3
2023-03-09 11:07:16 +02:00
Stefan Prodan
938b00be6d Update sigstore/cosign-installer to v3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-03-09 11:01:32 +02:00
Stefan Prodan
e6c7657155 Merge pull request #259 from stefanprodan/release-6.3.5
Release 6.3.5
2023-03-09 10:47:40 +02:00
Stefan Prodan
d75e8d7838 Release 6.3.5
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-03-09 10:42:52 +02:00
Stefan Prodan
74d6532429 Merge pull request #258 from stefanprodan/otel-updates
Update open telemetry dependencies
2023-03-09 10:41:49 +02:00
Stefan Prodan
8187f79475 Update open telemetry dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-03-09 10:37:39 +02:00
Stefan Prodan
2b6f4f0a7d Merge pull request #257 from hiddeco/update-autoscaling-apis
Update `autoscaling/v2beta2` to `autoscaling/v2`
2023-03-09 10:30:04 +02:00
Hidde Beydals
3a4a99697b Update autoscaling/v2beta2 to autoscaling/v2
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
2023-03-09 09:23:00 +01:00
Stefan Prodan
1abc44f0d8 Merge pull request #254 from stefanprodan/release-6.3.4
Release v6.3.4
2023-02-21 10:49:33 +02:00
Stefan Prodan
3d798af827 Release v6.3.4
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-21 10:44:37 +02:00
Stefan Prodan
f8f8073946 Merge pull request #253 from stefanprodan/update-deps-xnet
Update dependencies
2023-02-21 10:41:42 +02:00
Stefan Prodan
c8c7a6d1bb Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-21 10:37:19 +02:00
Stefan Prodan
eac008b339 Merge pull request #249 from exfly/be-fix-stress-typo
Fix beginStressTest memory log typo
2023-02-05 13:45:00 +02:00
exfly
d2227a4204 Fix beginStressTest memory log typo 2023-02-05 13:03:04 +08:00
Stefan Prodan
ae3fe3da98 Merge pull request #247 from stefanprodan/release-6.3.3
Release v6.3.3
2023-02-03 13:08:33 +02:00
Stefan Prodan
42fdaf8e7a Release v6.3.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 13:01:30 +02:00
Stefan Prodan
3e2d907993 Merge pull request #246 from stefanprodan/go-1.20
build: Update Go to 1.20
2023-02-03 12:57:39 +02:00
Stefan Prodan
21136b6405 build: Update Go to 1.20
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 12:45:46 +02:00
Stefan Prodan
e8c388a3fd Merge pull request #245 from stefanprodan/release-6.3.2
Release v6.3.3
2023-02-03 12:28:34 +02:00
Stefan Prodan
abc38e1bff Release v6.3.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 12:25:11 +02:00
Stefan Prodan
bf4a3140fe Merge pull request #244 from stefanprodan/slsa-sbom
build: Enable SBOM and SLSA Provenance
2023-02-03 12:23:00 +02:00
Stefan Prodan
de2dd687cb build: Enable SBOM and SLSA Provenance
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 12:19:26 +02:00
Stefan Prodan
f7a9563986 Merge pull request #243 from stefanprodan/release-6.3.1
Release v6.3.1
2023-02-03 11:52:05 +02:00
Stefan Prodan
a699fffe7b Release v6.3.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 11:47:55 +02:00
Stefan Prodan
24e5de8934 Merge pull request #242 from stefanprodan/golang-jwt
Update dependencies
2023-02-03 11:46:53 +02:00
Stefan Prodan
298c1ae941 Update dependencies
- Replace `dgrijalva/jwt-go` with `golang-jwt/jwt`
- Replace `ioutil` with `io` and `os`

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2023-02-03 11:42:17 +02:00
Stefan Prodan
fdd0a0b7da Merge pull request #240 from stefanprodan/kubeconform
Validate manifests with kubeconform
2022-12-23 13:28:18 +02:00
Stefan Prodan
8bab17843c Validate manifests with kubeconform
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-23 13:23:24 +02:00
Stefan Prodan
34c5ab57b6 Merge pull request #239 from stefanprodan/cue-hpa-v2
Update HPA to v2 in CUE definitions
2022-12-23 12:30:23 +02:00
Stefan Prodan
0f9c989b68 Update HPA to v2 in CUE definitions
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-23 12:18:50 +02:00
Stefan Prodan
e2e85a9604 Merge pull request #238 from stefanprodan/release-v6.3.0
Release v6.3.0
2022-12-21 12:58:20 +02:00
Stefan Prodan
b687d3c76f Update Alpine to v3.17
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 12:53:43 +02:00
Stefan Prodan
dbbb415194 Release v6.3.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 12:50:25 +02:00
Stefan Prodan
1a89d81ebb Merge pull request #237 from stefanprodan/hpa-v2
Update HPA to autoscaling/v2
2022-12-21 12:43:55 +02:00
Stefan Prodan
b39526ebe8 Set Kubernetes 1.23.0 as the minimum required version
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 12:33:47 +02:00
Stefan Prodan
607303dca9 Update HPA to autoscaling/v2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 12:07:31 +02:00
Stefan Prodan
3053e634f9 Merge pull request #236 from stefanprodan/update-workflows
Update GitHub workflows
2022-12-21 12:00:59 +02:00
Stefan Prodan
4f1e56ae83 Update GitHub workflows
- replace `engineerd/setup-kind` with `helm/kind-action`
- use  `azure/setup-helm` to install the Helm CLI

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 11:55:36 +02:00
Stefan Prodan
f0590a03e0 Merge pull request #235 from stefanprodan/update-x/net
Update dependencies
2022-12-21 11:23:32 +02:00
Stefan Prodan
aa815625d9 Update dependencies
Fix for golang.org/x/net CVEs

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-12-21 11:18:30 +02:00
Stefan Prodan
8615cb75d9 Merge pull request #233 from stefanprodan/release-6.2.3
Release v6.2.3
2022-11-09 13:17:16 +02:00
Stefan Prodan
b23ebb15cb Release v6.2.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-11-09 13:12:30 +02:00
Stefan Prodan
dcb5b13023 Merge pull request #232 from stefanprodan/deps-update
Update dependencies
2022-11-09 13:10:23 +02:00
Stefan Prodan
71869089fa Update dependencies
- github.com/prometheus/client_golang v1.14.0
- github.com/spf13/cobra v1.6.1
- github.com/spf13/viper v1.14.0
- go.opentelemetry.io/contrib/propagators/ot v1.11.1
- golang.org/x/net v0.2.0

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-11-09 12:59:22 +02:00
Stefan Prodan
1cf228c67b Merge pull request #228 from stefanprodan/release-6.2.2
Release 6.2.2
2022-10-20 12:25:15 +03:00
Stefan Prodan
b6e81a931b Release 6.2.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-10-20 12:12:44 +03:00
Stefan Prodan
744597a481 Merge pull request #227 from stefanprodan/deps-up
Update dependencies
2022-10-20 12:05:40 +03:00
Stefan Prodan
389c86ee93 Update dependencies
Fix CVE-2022-32149 of `golang.org/x/text`

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-10-20 12:00:33 +03:00
Stefan Prodan
34db5fa463 Merge pull request #226 from cv65kr/feat/graceful-shutdown
Enable graceful shutdown for gRPC server
2022-10-20 11:48:43 +03:00
Kajetan
0d62402ae9 Graceful shutdown 2022-10-18 17:31:51 +02:00
Stefan Prodan
e40d32ba87 Merge pull request #224 from jkremser/helm-probes
Add a way to customize liveness and readiness probes in helm chart
2022-10-06 15:17:54 +02:00
Jirka Kremser
3879b59f43 Add a way to customize liveness and readiness probes in helm chart
Signed-off-by: Jirka Kremser <jiri.kremser@gmail.com>
2022-10-03 17:36:14 +02:00
Stefan Prodan
44157ecd84 Merge pull request #222 from stefanprodan/release-6.2.1
Release 6.2.1
2022-09-29 12:54:45 +03:00
Stefan Prodan
bfa8d8032f Release 6.2.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-09-29 12:49:43 +03:00
Stefan Prodan
b1251214f6 Merge pull request #221 from stefanprodan/update-golang.org/x/net
Update dependencies
2022-09-29 12:41:38 +03:00
Stefan Prodan
f1168c4946 Update dependencies
Fix for golang.org/x/net CVE-2022-27664

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-09-29 12:36:35 +03:00
Stefan Prodan
013343a232 Merge pull request #220 from stefanprodan/go1.19
Build with Go 1.19
2022-09-29 12:31:39 +03:00
Stefan Prodan
d460863f3b Merge pull request #217 from Boojapho/imagepullsecret
feat(helm): added imagepullsecrets
2022-09-29 12:31:26 +03:00
Stefan Prodan
25a1e26159 Build with Go 1.19
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-09-29 12:24:20 +03:00
Stefan Prodan
b39afea117 Merge pull request #219 from stefanprodan/build-revision
ci: Add revision to Docker build args
2022-09-29 12:23:27 +03:00
Stefan Prodan
6d11ef9baf ci: Add revision to Docker build args
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-09-29 12:18:53 +03:00
Michael McLeroy
baf128d856 feat(helm): added imagepullsecrets 2022-09-13 15:55:16 -04:00
Stefan Prodan
79f8138328 Merge pull request #215 from stefanprodan/fix-flux-oci
Fix Flux tagging action
2022-08-15 15:48:06 +03:00
Stefan Prodan
ceed4e7870 Fix Flux tagging action
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-08-15 15:43:33 +03:00
Stefan Prodan
bfce2199e8 Merge pull request #214 from stefanprodan/release-6.2.0
Release 6.2.0
2022-08-15 15:36:39 +03:00
Stefan Prodan
d55bb8eabd Release 6.2.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-08-15 15:29:44 +03:00
Stefan Prodan
5fb056ebcb Merge pull request #213 from stefanprodan/update-actions
Update GitHub Actions workflows
2022-08-15 15:28:53 +03:00
Stefan Prodan
35b9c9f946 Update GitHub Actions workflows
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-08-15 15:22:02 +03:00
Stefan Prodan
74e0aeeff7 Merge pull request #212 from stefanprodan/update-deps
Update dependencies
2022-08-15 15:10:54 +03:00
Stefan Prodan
bbb081b0e1 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-08-15 15:06:41 +03:00
Stefan Prodan
c16318bb85 Merge pull request #211 from stefanprodan/flux-oci
Publish OCI artifacts on release with Flux
2022-08-15 15:01:51 +03:00
Stefan Prodan
86d5fe86e4 Publish OCI artifacts on release with Flux
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-08-15 14:56:50 +03:00
Stefan Prodan
b3b00fe354 Merge pull request #209 from stefanprodan/release-6.1.8
Release 6.1.8
2022-07-28 13:13:30 +03:00
Stefan Prodan
a7bcfaf9b3 Release 6.1.8
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-07-28 13:06:55 +03:00
Stefan Prodan
1d4c534728 Merge pull request #208 from stefanprodan/update-go-yaml
Update gopkg.in/yaml.v3 to v3.0.1
2022-07-28 13:05:52 +03:00
Stefan Prodan
f2e0aa154d Update gopkg.in/yaml.v3 to v3.0.1
Fix CVE-2022-28948

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-07-28 12:59:12 +03:00
Stefan Prodan
6d5b3d254a Merge pull request #207 from stefanprodan/release-6.1.7
Release 6.1.7
2022-07-27 19:19:21 +03:00
Stefan Prodan
9b9f11da95 Release 6.1.7
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-07-27 19:11:48 +03:00
Stefan Prodan
1a55e30bcf Merge pull request #206 from stefanprodan/update-swagger
Update Swagger packages and definition
2022-07-27 19:10:11 +03:00
Stefan Prodan
394c40e3ff Update Swagger packages and definition
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-07-27 18:59:22 +03:00
Stefan Prodan
b76b1a38c9 Merge pull request #204 from FlomoN/master
Add path based params to OpenAPI spec
2022-06-22 11:11:40 +03:00
FlomoN
2eb17d80c8 add some more params to other api routes with path based params 2022-06-20 18:37:13 +02:00
FlomoN
678a42ce34 recreate docs 2022-06-20 18:26:34 +02:00
FlomoN
2da59980fe switch to for installing swag 2022-06-20 18:05:53 +02:00
FlomoN
8697f091f3 Add params to godoc for cache 2022-06-20 14:20:34 +02:00
Stefan Prodan
4d2cf65260 Merge pull request #202 from TaylorMonacelli/patch-1
Fix test error "Error: release: not found"
2022-06-14 11:58:54 +03:00
Taylor Monacelli
116a378991 Fix test error "Error: release: not found" 2022-06-12 12:05:41 -07:00
Stefan Prodan
450796ddb2 Merge pull request #200 from stefanprodan/release-6.1.6
Release v6.1.6
2022-05-31 13:11:27 +03:00
Stefan Prodan
cb8c1fcec1 Release v6.1.6
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-05-31 13:04:28 +03:00
Stefan Prodan
37da8d1c74 Merge pull request #199 from stefanprodan/update-deps
Update dependencies
2022-05-31 13:01:10 +03:00
Stefan Prodan
e55ebd258d Update dependencies
Fix CVE-2022-28948

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-05-31 12:42:25 +03:00
Stefan Prodan
6b869d1a18 Merge pull request #198 from stefanprodan/go-1.18
Update Go to 1.18 and Alpine to 3.16
2022-05-24 13:06:50 +03:00
Stefan Prodan
dea973d614 Release podinfo 6.1.5
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-05-24 12:09:58 +03:00
Stefan Prodan
f4199ab8bc Update Go to 1.18 and Alpine to 3.16
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-05-24 12:09:08 +03:00
Paul Carlton
19603ddfc1 Fix panic triggering via HTTP API (#197)
Fix GET /panic

The GET /panic api call is not working due the the logger.Panic method
failing to call panic. This change replaces the logger.Panic method
call with logger.Info and adds a call to os.Exit(255).
2022-05-24 12:03:54 +03:00
Stefan Prodan
bf09377bfd Merge pull request #194 from stefanprodan/release-v6.1.4
Release v6.1.4
2022-04-18 10:00:06 +03:00
Stefan Prodan
075712dd73 Release v6.1.4
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-18 09:56:02 +03:00
Stefan Prodan
07dd9a3c3e Merge pull request #193 from stefanprodan/deps-up
Update dependencies
2022-04-18 09:54:32 +03:00
Stefan Prodan
63ac69ea69 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-18 09:49:42 +03:00
Stefan Prodan
3db382d2c9 Merge pull request #192 from stefanprodan/cue-refac
Refactor CUE module
2022-04-18 09:44:21 +03:00
Stefan Prodan
9f88a0e940 Refactor CUE module
- set default labels and annotations
- fix the service monitor selector
- allow setting ingress annotations
- remove embedded cert
- add cert-manager example for ingress
- set CPU scaling as default in HPA
- rename app input to config
- rename app out to objects

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-17 15:43:09 +03:00
Stefan Prodan
c6a2c90497 Merge pull request #191 from stefanprodan/exclude-cue-vendor
Exclude the CUE vendor packages from Git
2022-04-14 19:31:59 +03:00
Stefan Prodan
54908f7d51 Exclude the CUE vendor packages from Git
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-14 19:03:58 +03:00
Stefan Prodan
36bf90b008 Merge pull request #190 from stefanprodan/release-6.1.3
Release v6.1.3
2022-04-13 11:52:28 +03:00
Stefan Prodan
dd9020c8b2 Release v6.1.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-13 11:43:55 +03:00
Stefan Prodan
51009591a5 Merge pull request #189 from stefanprodan/redis-url-fix
Add protocol to Redis URL
2022-04-13 11:42:55 +03:00
Stefan Prodan
2b8c71ba78 Add protocol to Redis URL
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-13 11:37:49 +03:00
Stefan Prodan
203f7e1bf0 Merge pull request #187 from stefanprodan/release-6.1.2
Release 6.1.2
2022-04-11 16:35:21 +03:00
Stefan Prodan
8179263f52 Release 6.1.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-11 16:30:15 +03:00
Stefan Prodan
b26a34b5b6 cue: Fix label selectors
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-11 16:29:35 +03:00
Stefan Prodan
cd7a0fb18e Rename cue module
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-04-11 15:45:12 +03:00
Stefan Prodan
c1fd17e50a Merge pull request #185 from phoban01/piarash/cue-module
Add CUE module for generating Kubernetes manifests
2022-04-11 15:38:29 +03:00
Piaras Hoban
f98267009e cue: move cue fmt check above dirty working tree check in test workflow
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 11:56:59 +01:00
Piaras Hoban
7d0203196a cue: add cue format and validation checks to github actions test workflow
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 11:03:22 +01:00
Piaras Hoban
673966bae4 cue: remove linkerd ServiceProfile resource
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 10:44:35 +01:00
Piaras Hoban
9265828c4f cue: patch version in main.cue with makefile version-set rule
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 10:44:01 +01:00
Piaras Hoban
0f68b60870 cue: remove default tag from config.image
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 10:27:14 +01:00
Piaras Hoban
217a27ce02 cue: rename directory from cuelang -> cue
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-11 10:26:00 +01:00
Piaras Hoban
fc172b0e7c add cuelang module for podinfo
Signed-off-by: Piaras Hoban <phoban01@gmail.com>
2022-04-06 17:50:41 +01:00
Stefan Prodan
b891025365 Fix Helm OCI packaging job
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-30 11:38:41 +03:00
Stefan Prodan
3c3f2a2e60 Merge pull request #183 from stefanprodan/release-6.1.1
Release v6.1.1
2022-03-30 11:24:21 +03:00
Stefan Prodan
06b5e969db Publish v6.1.1
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-30 11:17:38 +03:00
Stefan Prodan
8508550ee6 Merge pull request #182 from stefanprodan/helm-oci
Published signed Helm charts to GHCR
2022-03-30 11:16:19 +03:00
Stefan Prodan
5c1032c578 Published signed Helm charts to GHCR
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-30 11:11:45 +03:00
Stefan Prodan
9febc66b98 Merge pull request #180 from mmontes11/redis-basic-auth
Adapted cache to support redis authentication
2022-03-29 10:26:13 +03:00
Stefan Prodan
59dc738b25 Merge pull request #181 from nozaq/fix-typo
Fix a typo
2022-03-29 10:25:56 +03:00
nozaq
8524be7240 Fix a typo 2022-03-27 21:44:09 +09:00
Martín Montes
065a18c258 Adapted cache to support redis authentication 2022-03-23 22:13:14 +01:00
Stefan Prodan
79279ccb31 Merge pull request #178 from stefanprodan/release-6.1.0
Release 6.1.0
2022-03-12 13:29:52 +02:00
Stefan Prodan
7e1ef7457e Release 6.1.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-12 13:25:23 +02:00
Stefan Prodan
af4919172a Merge pull request #177 from stefanprodan/cosign
Sign container images with cosign and GitHub OIDC
2022-03-12 13:24:26 +02:00
Stefan Prodan
532e8f85b5 Merge pull request #167 from utkuozdemir/patch-1
Fix ingress URL in Helm chart NOTES.txt
2022-03-12 13:24:13 +02:00
Stefan Prodan
7c90501b8b Sign container images with cosign and GitHub OIDC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-12 13:15:09 +02:00
Stefan Prodan
5f1fb66f6f Merge pull request #176 from stefanprodan/disable-otel
Disable tracing by default
2022-03-12 13:04:59 +02:00
Stefan Prodan
be80733cea Disable tracing by default
To enable OTEL tracing, the `--otel-service-name` flag must be set.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-12 12:58:39 +02:00
Stefan Prodan
8572a390f7 Merge pull request #170 from rajatvig/otel
Add support for OpenTelemetry to podinfo http API
2022-03-12 12:05:16 +02:00
Stefan Prodan
b2a41c64de Update Trivy vulnerability scanner
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-09 15:38:51 +02:00
Stefan Prodan
11cf36d838 Merge pull request #175 from stefanprodan/go-1.17
Update Go to v1.17
2022-03-09 15:21:47 +02:00
Stefan Prodan
5d440e41da Release 6.0.4
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-09 15:16:34 +02:00
Stefan Prodan
170b912d25 Update Go to v1.17
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-09 15:06:55 +02:00
Rajat Vig
38a7952407 Reformat 2022-01-10 16:19:45 +00:00
Rajat Vig
de90d92697 Remove default to insecure GRPC 2022-01-02 00:19:18 +00:00
Rajat Vig
22ee79fcb8 Add the copyheaders code back 2021-12-22 14:13:36 +00:00
Rajat Vig
03ffc8bc34 Create a new otel directory; Add a readme and makefile 2021-12-22 12:15:56 +00:00
Rajat Vig
c4f2a6c5e6 Setup different name; Copying of headers is not required for spans 2021-12-22 01:29:21 +00:00
Rajat Vig
ab9f7410c2 Get a docker-compose for example; Port code to otel-grpc 2021-12-22 01:09:49 +00:00
Rajat Vig
2c85a72737 Add back copyTraceHeaders() as OpenTelemetry does not default propagate 2021-12-16 14:12:32 +00:00
Rajat Vig
3970a3a323 Add noop tracer to the mockServer; migrate to go 1.17 2021-12-16 13:37:01 +00:00
Ilya Dmitrichenko
61d6ed42f5 Add OpenTelemetry tracer 2021-12-16 12:39:10 +00:00
Utku Özdemir
bb11285c6f Fix ingress URL in Helm chart NOTES.txt
Fixes the notes that are printed when the Helm chart is installed with `ingress.enabled: true`.

Before:
```
1. Get the application URL by running these commands:
  https://map[host:podinfo.example.com paths:[map[path:/ pathType:ImplementationSpecific]]]
```

After the change:
```
1. Get the application URL by running these commands:
  https://podinfo.example.com/
```

The changed part is taken as-is from the output of the `helm create` command of Helm version 3.7.1.
Tested & working as expected.
2021-11-30 15:32:01 +01:00
Stefan Prodan
132f4e7192 Merge pull request #165 from cv65kr/cv65kr-patch-1
Remove duplicated endpoint
2021-11-14 16:12:13 +02:00
Kajetan
6c596bf19b Remove duplicated endpoint 2021-11-14 14:36:09 +01:00
Stefan Prodan
ea292aa958 Merge pull request #160 from stefanprodan/release-6.0.3
Release v6.0.3
2021-10-21 17:50:42 +03:00
Stefan Prodan
33fa856b63 Release v6.0.3
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-10-21 17:45:33 +03:00
Stefan Prodan
6065c5aa79 Merge pull request #159 from stefanprodan/tonistiigi/xx
Use tonistiigi/xx for multi-arch builds
2021-10-21 17:44:21 +03:00
Stefan Prodan
0771a597e6 Use tonistiigi/xx for multi-arch builds
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-10-21 17:35:43 +03:00
261 changed files with 33959 additions and 1540 deletions

View File

@@ -1,9 +1,10 @@
# Podinfo signed releases
Podinfo deployment manifests are published to GitHub Container Registry as OCI artifacts
and are signed using [cosign](https://github.com/sigstore/cosign).
Podinfo release assets (container image, Helm chart, Flux artifact, Timoni module)
are published to GitHub Container Registry and are signed with
[Cosign v2](https://github.com/sigstore/cosign) keyless & GitHub Actions OIDC.
## Verify the artifacts with cosign
## Verify podinfo with cosign
Install the [cosign](https://github.com/sigstore/cosign) CLI:
@@ -11,29 +12,50 @@ Install the [cosign](https://github.com/sigstore/cosign) CLI:
brew install sigstore/tap/cosign
```
Verify a podinfo release with cosign CLI:
### Container image
Verify the podinfo container image hosted on GHCR:
```sh
cosign verify -key https://raw.githubusercontent.com/stefanprodan/podinfo/master/cosign/cosign.pub \
ghcr.io/stefanprodan/podinfo-config:latest
cosign verify ghcr.io/stefanprodan/podinfo:6.5.0 \
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
## Download the artifacts with crane
Install the [crane](https://github.com/google/go-containerregistry/tree/main/cmd/crane) CLI:
Verify the podinfo container image hosted on Docker Hub:
```sh
brew install crane
cosign verify docker.io/stefanprodan/podinfo:6.5.0 \
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
Download the podinfo deployment manifests with crane CLI:
### Helm chart
```console
$ crane export ghcr.io/stefanprodan/podinfo-deploy:latest -| tar -xf -
Verify the podinfo [Helm](https://helm.sh) chart hosted on GHCR:
$ ls -1
deployment.yaml
hpa.yaml
kustomization.yaml
service.yaml
```sh
cosign verify ghcr.io/stefanprodan/charts/podinfo:6.5.0 \
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
### Flux artifact
Verify the podinfo [Flux](https://fluxcd.io) artifact hosted on GHCR:
```sh
cosign verify ghcr.io/stefanprodan/manifests/podinfo:6.5.0 \
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
### Timoni module
Verify the podinfo [Timoni](https://timoni.sh) module hosted on GHCR:
```sh
cosign verify ghcr.io/stefanprodan/modules/podinfo:6.5.0 \
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
timoni/podinfo/cue.mod/** linguist-vendored

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: stefanprodan

View File

@@ -1,33 +0,0 @@
name: Setup Helm CLI
description: A GitHub Action for running Helm commands
author: Stefan Prodan
branding:
color: blue
icon: command
inputs:
version:
description: "Helm version"
required: true
runs:
using: composite
steps:
- name: "Download helm binary to tmp"
shell: bash
run: |
VERSION=${{ inputs.version }}
BIN_URL="https://get.helm.sh/helm-v${VERSION}-linux-amd64.tar.gz"
curl -sL ${BIN_URL} -o /tmp/helm.tar.gz
mkdir -p /tmp/helm
tar -C /tmp/helm/ -zxvf /tmp/helm.tar.gz
- name: "Add helm binary to /usr/local/bin"
shell: bash
run: |
sudo cp /tmp/helm/linux-amd64/helm /usr/local/bin
- name: "Cleanup tmp"
shell: bash
run: |
rm -rf /tmp/helm/ /tmp/helm.tar.gz
- name: "Verify correct installation of binary"
shell: bash
run: |
helm version

38
.github/actions/kubeconform/action.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Setup kubeconform
description: A GitHub Action for running kubeconform commands
author: Stefan Prodan
branding:
color: blue
icon: command
inputs:
version:
description: "kubeconform version e.g. 0.5.0 (defaults to latest stable release)"
required: false
arch:
description: "arch can be amd64 or arm64"
required: true
default: "amd64"
runs:
using: composite
steps:
- name: "Download binary to the GH runner cache"
shell: bash
run: |
ARCH=${{ inputs.arch }}
VERSION=${{ inputs.version }}
if [ -z $VERSION ]; then
VERSION=$(curl https://api.github.com/repos/yannh/kubeconform/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
fi
BIN_URL="https://github.com/yannh/kubeconform/releases/download/v${VERSION}/kubeconform-linux-${ARCH}.tar.gz"
BIN_DIR=$RUNNER_TOOL_CACHE/kubeconform/$VERSION/$ARCH
if [[ ! -x "$BIN_DIR/kind" ]]; then
mkdir -p $BIN_DIR
cd $BIN_DIR
curl -sL $BIN_URL | tar xz
chmod +x kubeconform
fi
echo "$BIN_DIR" >> "$GITHUB_PATH"

View File

@@ -1,51 +0,0 @@
package kubernetes
name = input.metadata.name
kind = input.kind
is_service {
input.kind = "Service"
}
is_deployment {
input.kind = "Deployment"
}
is_pod {
input.kind = "Pod"
}
split_image(image) = [image, "latest"] {
not contains(image, ":")
}
split_image(image) = [image_name, tag] {
[image_name, tag] = split(image, ":")
}
pod_containers(pod) = all_containers {
keys = {"containers", "initContainers"}
all_containers = [c | keys[k]; c = pod.spec[k][_]]
}
containers[container] {
pods[pod]
all_containers = pod_containers(pod)
container = all_containers[_]
}
containers[container] {
all_containers = pod_containers(input)
container = all_containers[_]
}
pods[pod] {
is_deployment
pod = input.spec.template
}
pods[pod] {
is_pod
pod = input
}

View File

@@ -1,43 +0,0 @@
package main
import data.kubernetes
name = input.metadata.name
# Deny containers with latest image tag
deny[msg] {
kubernetes.containers[container]
[image_name, "latest"] = kubernetes.split_image(container.image)
msg = sprintf("%s in the %s %s has an image %s, using the latest tag", [container.name, kubernetes.kind, kubernetes.name, image_name])
}
# Deny services without app label selector
service_labels {
input.spec.selector["app"]
}
deny[msg] {
kubernetes.is_service
not service_labels
msg = sprintf("Service %s should set app label selector", [name])
}
# Deny deployments without app label selector
match_labels {
input.spec.selector.matchLabels["app"]
}
deny[msg] {
kubernetes.is_deployment
not match_labels
msg = sprintf("Service %s should set app label selector", [name])
}
# Warn if deployments have no prometheus pod annotations
annotations {
input.spec.template.metadata.annotations["prometheus.io/scrape"]
input.spec.template.metadata.annotations["prometheus.io/port"]
}
warn[msg] {
kubernetes.is_deployment
not annotations
msg = sprintf("Deployment %s should set prometheus.io/scrape and prometheus.io/port pod annotations", [name])
}

View File

@@ -3,21 +3,29 @@ name: cve-scan
on:
push:
branches:
- 'master'
- "master"
permissions:
contents: read
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build image
id: build
run: |
IMAGE=test/podinfo:${GITHUB_SHA}
docker build -t ${IMAGE} .
echo "::set-output name=image::$IMAGE"
- name: Scan image
uses: docker://docker.io/aquasec/trivy:latest
echo "image=$IMAGE" >> $GITHUB_OUTPUT
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
args: --cache-dir /var/lib/trivy --no-progress --exit-code 1 --severity MEDIUM,HIGH,CRITICAL ${{ steps.build.outputs.image }}
image-ref: ${{ steps.build.outputs.image }}
format: table
exit-code: "1"
ignore-unfixed: true
vuln-type: os,library
severity: CRITICAL,HIGH

View File

@@ -6,28 +6,27 @@ on:
branches:
- 'master'
permissions:
contents: read
jobs:
kind-helm:
strategy:
matrix:
helm-version:
- 3.6.0
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0
uses: helm/kind-action@v1.10.0
with:
version: v0.11.1
cluster_name: kind
- name: Build container image
run: |
./test/build.sh
kind load docker-image test/podinfo:latest
- name: Setup Helm
uses: ./.github/actions/helm
uses: azure/setup-helm@v3
with:
version: ${{ matrix.helm-version }}
version: v3.16.1
- name: Deploy
run: ./test/deploy.sh
- name: Run integration tests
@@ -36,3 +35,44 @@ jobs:
if: failure()
run: |
kubectl logs -l app=podinfo || true
kind-timoni:
runs-on: ubuntu-latest
services:
registry:
image: registry:2
ports:
- 5000:5000
env:
PODINFO_IMAGE_URL: "test/podinfo"
PODINFO_MODULE_URL: "oci://localhost:5000/podinfo"
PODINFO_VERSION: "0.0.0-devel"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Timoni
uses: stefanprodan/timoni/actions/setup@main
- name: Setup Kubernetes
uses: helm/kind-action@v1.10.0
with:
cluster_name: kind
- name: Build container
run: |
docker build -t ${PODINFO_IMAGE_URL}:${PODINFO_VERSION} --build-arg "REVISION=${GITHUB_SHA}" -f Dockerfile.xx .
kind load docker-image ${PODINFO_IMAGE_URL}:${PODINFO_VERSION}
- name: Vet module
run: |
timoni mod vet ./timoni/podinfo --debug
- name: Build module
run: |
timoni mod push ./timoni/podinfo ${PODINFO_MODULE_URL} -v ${PODINFO_VERSION}
- name: Apply bundle
run: |
timoni bundle apply -f ./timoni/bundles/test.podinfo.cue --runtime-from-env
- name: Verify status
run: |
timoni -n podinfo status backend
timoni -n podinfo status frontend
- name: Debug failure
if: failure()
run: |
kubectl -n podinfo get all || true

View File

@@ -2,32 +2,59 @@ name: release
on:
push:
tags: '*'
tags:
- '*'
permissions:
contents: read
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write # needed to write releases
id-token: write # needed for keyless signing
packages: write # needed for ghcr access
steps:
- uses: actions/checkout@v2
- uses: imjasonh/setup-crane@v0.1
- uses: sigstore/cosign-installer@main
- uses: actions/checkout@v4
- uses: sigstore/cosign-installer@v3
- uses: fluxcd/flux2/action@main
- uses: stefanprodan/timoni/actions/setup@main
- name: Setup Notation CLI
uses: notaryproject/notation-action/setup@v1
with:
version: "1.1.0"
- name: Setup Notation signing keys
run: |
mkdir -p ~/.config/notation/localkeys/
cp ./.notation/signingkeys.json ~/.config/notation/
cp ./.notation/notation.crt ~/.config/notation/localkeys/
echo "$NOTATION_KEY" > ~/.config/notation/localkeys/notation.key
env:
NOTATION_KEY: ${{ secrets.NOTATION_SIGNING_KEY }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.24.x
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: v3.16.1
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v3
with:
platforms: all
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -38,30 +65,64 @@ jobs:
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF/refs\/tags\//}
fi
echo ::set-output name=BUILD_DATE::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
echo ::set-output name=VERSION::${VERSION}
- name: Publish multi-arch image
uses: docker/build-push-action@v2
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
echo "REVISION=${GITHUB_SHA}" >> $GITHUB_OUTPUT
- name: Generate images meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
docker.io/stefanprodan/podinfo
ghcr.io/stefanprodan/podinfo
tags: |
type=raw,value=${{ steps.prep.outputs.VERSION }}
type=raw,value=latest
- name: Publish multi-arch image
uses: docker/build-push-action@v5
with:
sbom: true
provenance: true
push: true
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
file: ./Dockerfile.xx
build-args: |
REVISION=${{ steps.prep.outputs.REVISION }}
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: |
docker.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
docker.io/stefanprodan/podinfo:latest
ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
org.opencontainers.image.source=${{ github.event.repository.html_url }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ steps.prep.outputs.VERSION }}
org.opencontainers.image.created=${{ steps.prep.outputs.BUILD_DATE }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Publish Timoni module to GHCR
run: |
timoni mod push ./timoni/podinfo oci://ghcr.io/stefanprodan/modules/podinfo \
--sign cosign \
--version ${{ steps.prep.outputs.VERSION }} \
-a 'org.opencontainers.image.source=https://github.com/stefanprodan/podinfo' \
-a 'org.opencontainers.image.licenses=Apache-2.0' \
-a 'org.opencontainers.image.description=A timoni.sh module for deploying Podinfo.' \
-a 'org.opencontainers.image.documentation=https://github.com/stefanprodan/podinfo/blob/main/timoni/podinfo/README.md'
- name: Publish Helm chart to GHCR
run: |
helm package charts/podinfo
helm push podinfo-${{ steps.prep.outputs.VERSION }}.tgz oci://ghcr.io/stefanprodan/charts
rm podinfo-${{ steps.prep.outputs.VERSION }}.tgz
- name: Publish Flux OCI artifact to GHCR
run: |
flux push artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} \
--path="./kustomize" \
--source="${{ github.event.repository.html_url }}" \
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
flux tag artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --tag latest
- name: Sign artifacts with Cosign
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign docker.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/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --yes
- name: Publish base image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
with:
push: true
builder: ${{ steps.buildx.outputs.name }}
@@ -75,28 +136,35 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish config artifact
run: |
cd kustomize
tar -cf config.tar * --numeric-owner --owner=0 --group=0
crane append -f config.tar -t ghcr.io/stefanprodan/podinfo-config:${{ steps.prep.outputs.VERSION }}
crane tag ghcr.io/stefanprodan/podinfo-config:${{ steps.prep.outputs.VERSION }} latest
rm config.tar
- name: Sign config artifact
flux push artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} \
--path="./kustomize" \
--source="${{ github.event.repository.html_url }}" \
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
flux tag artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --tag latest
- name: Sign config artifact with cso
run: |
echo "$COSIGN_KEY" > /tmp/cosign.key
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-config:${{ steps.prep.outputs.VERSION }}
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-config:latest
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
env:
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
COSIGN_KEY: ${{secrets.COSIGN_KEY}}
- name: Sign artifacts with Notation
run: |
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 }}
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
- uses: ./.github/actions/release-notes
- name: Generate release notes
run: |
echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org stefanprodan -repo podinfo -since-latest-release >> /tmp/release.txt
- name: Publish release
uses: goreleaser/goreleaser-action@v1
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --release-notes=/tmp/release.txt
args: release --release-notes=/tmp/release.txt --skip=validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -6,42 +6,67 @@ on:
branches:
- 'master'
permissions:
contents: read
env:
KUBERNETES_VERSION: 1.31.0
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Restore Go cache
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: 1.16.x
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: v${{ env.KUBERNETES_VERSION }}
- name: Setup kubeconform
uses: ./.github/actions/kubeconform
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: v3.16.1
- name: Setup CUE
uses: cue-lang/setup-cue@v1.0.0
- name: Setup Timoni
uses: stefanprodan/timoni/actions/setup@main
- name: Run unit tests
run: make test
- name: Validate Helm chart
run: |
helm lint ./charts/podinfo/
helm template ./charts/podinfo/ | kubeconform -strict -summary -kubernetes-version ${{ env.KUBERNETES_VERSION }}
- name: Validate Kustomize overlay
run: |
kubectl kustomize ./kustomize/ | kubeconform -strict -summary -kubernetes-version ${{ env.KUBERNETES_VERSION }}
- name: Verify CUE formatting
working-directory: ./timoni/podinfo
run: |
cue fmt ./...
status=$(git status . --porcelain)
[[ -z "$status" ]] || {
echo "CUE files are not correctly formatted"
echo "$status"
git diff
exit 1
}
- name: Validate Timoni module
working-directory: ./timoni/podinfo
run: |
timoni mod lint .
timoni build podinfo . -f test_values.cue | kubeconform -strict -summary -skip=ServiceMonitor -kubernetes-version ${{ env.KUBERNETES_VERSION }}
- name: Check if working tree is dirty
run: |
if [[ $(git diff --stat) != '' ]]; then
echo 'run make test and commit changes'
exit 1
fi
- name: Validate Helm chart
uses: stefanprodan/kube-tools@v1
with:
kubectl: 1.19.11
helm: 2.17.0
helmv3: 3.6.0
command: |
helmv3 template ./charts/podinfo | kubeval --strict --kubernetes-version 1.19.11 --schema-location https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master
- name: Validate kustomization
uses: stefanprodan/kube-tools@v1
with:
kubectl: 1.19.11
command: |
kustomize build ./kustomize | kubeval --strict --kubernetes-version 1.19.11 --schema-location https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master
kustomize build ./kustomize | conftest test -p .github/policy -

8
.gitignore vendored
View File

@@ -19,4 +19,10 @@ release/
build/
gcloud/
dist/
bin/
bin/
cue/cue.mod/gen/
cue/go.mod
cue/go.sum
.notation/podinfo.csr
.notation/podinfo.key

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

21
.notation/notation.crt Normal file
View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDbDCCAlSgAwIBAgIUP7zhmTw5XTWLcgBGkBEsErMOkz4wDQYJKoZIhvcNAQEL
BQAwWjELMAkGA1UEBhMCUk8xCzAJBgNVBAgMAkJVMRIwEAYDVQQHDAlCdWNoYXJl
c3QxDzANBgNVBAoMBk5vdGFyeTEZMBcGA1UEAwwQc3RlZmFucHJvZGFuLmNvbTAe
Fw0yNDAyMjUxMDAyMzZaFw0yOTAyMjQxMDAyMzZaMFoxCzAJBgNVBAYTAlJPMQsw
CQYDVQQIDAJCVTESMBAGA1UEBwwJQnVjaGFyZXN0MQ8wDQYDVQQKDAZOb3Rhcnkx
GTAXBgNVBAMMEHN0ZWZhbnByb2Rhbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDtH4oPi3SyX/DGv6NdjIvmApvD9eeSgsmHdwpAly8T9D2me+fx
Z+wRNJmq4aq/A1anX+Sg28iwHzV+1WKpsHnjYzDAJSEYP2S8A5H1nGRKUoibdijw
C3QBh5C75rjF/tmZVSX/Vgbf3HJJEsF4WUxWabLxoV2QLo7UlEsQd9+bSeKNMncx
1+E6FdbRCrYo90iobvZJ8K/S2zCWq/JTeHfTnmSEDhx6nMJcaSjvMPn3zyauWcQw
dDpkcaGiJ64fEJRT2OFxXv9u+vDmIMKzo/Wjbd+IzFj6YY4VisK88aU7tmDelnk5
gQB9eu62PFoaVsYJp4VOhblFKvGJpQwbWB9BAgMBAAGjKjAoMA4GA1UdDwEB/wQE
AwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEA
6x+C6hAIbLwMvkNx4K5p7Qe/pLQR0VwQFAw10yr/5KSN+YKFpon6pQ0TebL7qll+
uBGZvtQhN6v+DlnVqB7lvJKd+89isgirkkews5KwuXg7Gv5UPIugH0dXISZU8DMJ
7J4oKREv5HzdFmfsUfNlQcfyVTjKL6UINXfKGdqNNxXxR9b4a1TY2JcmEhzBTHaq
ZqX6HK784a0dB7aHgeFrFwPCCP4M684Hs7CFbk3jo2Ef4ljnB5AyWpe8pwCLMdRt
UjSjL5xJWVQvRU+STQsPr6SvpokPCG4rLQyjgeYYk4CCj5piSxbSUZFavq8v1y7Y
m91USVqfeUX7ZzjDxPHE2A==
-----END CERTIFICATE-----

View File

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

View File

@@ -0,0 +1,19 @@
{
"version": "1.0",
"trustPolicies": [
{
"name": "stefanprodan.com",
"registryScopes": [
"ghcr.io/stefanprodan/podinfo-deploy",
"ghcr.io/stefanprodan/charts/podinfo"
],
"signatureVerification": {
"level" : "strict"
},
"trustStores": [ "ca:stefanprodan.com" ],
"trustedIdentities": [
"x509.subject: C=RO, ST=BU, L=Bucharest, O=Notary, CN=stefanprodan.com"
]
}
]
}

View File

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

View File

@@ -1,4 +1,4 @@
FROM golang:1.16
FROM golang:1.24
WORKDIR /workspace

53
Dockerfile.xx Normal file
View File

@@ -0,0 +1,53 @@
ARG GO_VERSION=1.24
ARG XX_VERSION=1.6.1
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine as builder
# Copy the build utilities.
COPY --from=xx / /
ARG TARGETPLATFORM
ARG REVISION
RUN mkdir -p /podinfo/
WORKDIR /podinfo
COPY . .
RUN go mod download
ENV CGO_ENABLED=0
RUN xx-go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-a -o bin/podinfo cmd/podinfo/*
RUN xx-go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-a -o bin/podcli cmd/podcli/*
FROM alpine:3.21
ARG BUILD_DATE
ARG VERSION
ARG REVISION
LABEL maintainer="stefanprodan"
RUN addgroup -S app \
&& adduser -S -G app app \
&& apk --no-cache add \
ca-certificates curl netcat-openbsd
WORKDIR /home/app
COPY --from=builder /podinfo/bin/podinfo .
COPY --from=builder /podinfo/bin/podcli /usr/local/bin/podcli
COPY ./ui ./ui
RUN chown -R app:app ./
USER app
CMD ["./podinfo"]

View File

@@ -16,16 +16,21 @@ run:
--ui-logo=https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif $(EXTRA_RUN_ARGS)
.PHONY: test
test:
test: tidy fmt vet
go test ./... -coverprofile cover.out
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/podinfo ./cmd/podinfo/*
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:
rm -f go.sum; go mod tidy -compat=1.24
vet:
go vet ./...
fmt:
gofmt -l -s -w ./
goimports -l -w ./
go fmt ./...
build-charts:
helm lint charts/*
@@ -34,6 +39,13 @@ build-charts:
build-container:
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
build-xx:
docker buildx build \
--platform=linux/amd64 \
-t $(DOCKER_IMAGE_NAME):$(VERSION) \
--load \
-f Dockerfile.xx .
build-base:
docker build -f Dockerfile.base -t $(DOCKER_REPOSITORY)/podinfo-base:latest .
@@ -59,22 +71,29 @@ push-container:
version-set:
@next="$(TAG)" && \
current="$(VERSION)" && \
sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values-prod.yaml && \
sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
echo "Version $$next set in code, deployment, chart and kustomize"
/usr/bin/sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values-prod.yaml && \
/usr/bin/sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
/usr/bin/sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
/usr/bin/sed -i '' "s/$$current/$$next/g" timoni/podinfo/values.cue && \
echo "Version $$next set in code, deployment, module, chart and kustomize"
release:
git tag $(VERSION)
git tag -s -m $(VERSION) $(VERSION)
git push origin $(VERSION)
swagger:
go get github.com/swaggo/swag/cmd/swag
cd pkg/api && $$(go env GOPATH)/bin/swag init -g server.go
go install github.com/swaggo/swag/cmd/swag@latest
go get github.com/swaggo/swag/gen@latest
go get github.com/swaggo/swag/cmd/swag@latest
cd pkg/api/http && $$(go env GOPATH)/bin/swag init -g server.go
.PHONY: timoni-build
timoni-build:
@timoni build podinfo ./timoni/podinfo -f ./timoni/podinfo/debug_values.cue

View File

@@ -15,18 +15,17 @@ Specifications:
* Health checks (readiness and liveness)
* Graceful shutdown on interrupt signals
* File watcher for secrets and configmaps
* Instrumented with Prometheus
* Tracing with Istio and Jaeger
* Linkerd service profile
* Instrumented with Prometheus and Open Telemetry
* Structured logging with zap
* 12-factor app with viper
* Fault injection (random errors and latency)
* Swagger docs
* Helm and Kustomize installers
* Timoni, Helm and Kustomize installers
* End-to-End testing with Kubernetes Kind and Helm
* Kustomize testing with GitHub Actions and Open Policy Agent
* Multi-arch container image with Docker buildx and Github Actions
* CVE scanning with trivy
* Multi-arch container image with Docker buildx and GitHub Actions
* Container image signing with Sigstore cosign
* SBOMs and SLSA Provenance embedded in the container image
* CVE scanning with Trivy
Web API:
@@ -58,6 +57,16 @@ Web API:
gRPC API:
* `/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:
@@ -67,17 +76,26 @@ To access the Swagger UI open `<podinfo-host>/swagger/index.html` in a browser.
### Guides
* [GitOps Progressive Deliver with Flagger, Helm v3 and Linkerd](https://helm.workshop.flagger.dev/intro/)
* [GitOps Progressive Deliver on EKS with Flagger and AppMesh](https://eks.handson.flagger.dev/prerequisites/)
* [Automated canary deployments with Flagger and Istio](https://medium.com/google-cloud/automated-canary-deployments-with-flagger-and-istio-ac747827f9d1)
* [Kubernetes autoscaling with Istio metrics](https://medium.com/google-cloud/kubernetes-autoscaling-with-istio-metrics-76442253a45a)
* [Autoscaling EKS on Fargate with custom metrics](https://aws.amazon.com/blogs/containers/autoscaling-eks-on-fargate-with-custom-metrics/)
* [Managing Helm releases the GitOps way](https://medium.com/google-cloud/managing-helm-releases-the-gitops-way-207a6ac6ff0e)
* [Securing EKS Ingress With Contour And Lets Encrypt The GitOps Way](https://aws.amazon.com/blogs/containers/securing-eks-ingress-contour-lets-encrypt-gitops/)
* [Getting started with Timoni](https://timoni.sh/quickstart/)
* [Getting started with Flux](https://fluxcd.io/flux/get-started/)
* [Progressive Deliver with Flagger and Linkerd](https://docs.flagger.app/tutorials/linkerd-progressive-delivery)
* [Automated canary deployments with Kubernetes Gateway API](https://docs.flagger.app/tutorials/gatewayapi-progressive-delivery)
### Install
Helm:
To install Podinfo on Kubernetes the minimum required version is **Kubernetes v1.23**.
#### Timoni
Install with [Timoni](https://timoni.sh):
```bash
timoni -n default apply podinfo oci://ghcr.io/stefanprodan/modules/podinfo
```
#### Helm
Install from github.io:
```bash
helm repo add podinfo https://stefanprodan.github.io/podinfo
@@ -88,7 +106,7 @@ helm upgrade --install --wait frontend \
--set backend=http://backend-podinfo:9898/echo \
podinfo/podinfo
helm test frontend
helm test frontend --namespace test
helm upgrade --install --wait backend \
--namespace test \
@@ -96,13 +114,20 @@ helm upgrade --install --wait backend \
podinfo/podinfo
```
Kustomize:
Install from ghcr.io:
```bash
helm upgrade --install --wait podinfo --namespace default \
oci://ghcr.io/stefanprodan/charts/podinfo
```
#### Kustomize
```bash
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
```
Docker:
#### Docker
```bash
docker run -dp 9898:9898 stefanprodan/podinfo

View File

@@ -1,6 +1,6 @@
apiVersion: v1
version: 6.0.2
appVersion: 6.0.2
version: 6.8.0
appVersion: 6.8.0
name: podinfo
engine: gotpl
description: Podinfo Helm chart for Kubernetes
@@ -10,4 +10,4 @@ maintainers:
name: stefanprodan
sources:
- https://github.com/stefanprodan/podinfo
kubeVersion: ">=1.19.0-0"
kubeVersion: ">=1.23.0-0"

View File

@@ -9,7 +9,23 @@ for end-to-end testing and workshops.
## Installing the Chart
To install the chart with the release name `my-release`:
The Podinfo charts are published to
[GitHub Container Registry](https://github.com/stefanprodan/podinfo/pkgs/container/charts%2Fpodinfo)
and signed with [Cosign](https://github.com/sigstore/cosign) & GitHub Actions OIDC.
To install the chart with the release name `my-release` from GHCR:
```console
$ helm upgrade -i my-release oci://ghcr.io/stefanprodan/charts/podinfo
```
To verify a chart with Cosign:
```console
$ cosign verify ghcr.io/stefanprodan/charts/podinfo:<VERSION>
```
Alternatively, you can install the chart from GitHub pages:
```console
$ helm repo add podinfo https://stefanprodan.github.io/podinfo
@@ -34,60 +50,67 @@ 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.
Parameter | Default | Description
--- | --- | ---
`replicaCount` | `1` | Desired number of pods
`logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error`
`backend` | `None` | Echo backend URL
`backends` | `[]` | Array of echo backend URLs
`cache` | `None` | Redis address in the format `<host>:<port>`
`redis.enabled` | `false` | Create Redis deployment for caching purposes
`ui.color` | `#34577c` | UI color
`ui.message` | `None` | UI greetings message
`ui.logo` | `None` | UI logo
`faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds
`faults.error` | `false` | 1/3 chances of a random HTTP response error
`faults.unhealthy` | `false` | When set, the healthy state is never reached
`faults.unready` | `false` | When set, the ready state is never reached
`faults.testFail` | `false` | When set, a helm test is included which always fails
`faults.testTimeout` | `false` | When set, a helm test is included which always times out
`image.repository` | `stefanprodan/podinfo` | Image repository
`image.tag` | `<VERSION>` | Image tag
`image.pullPolicy` | `IfNotPresent` | Image pull policy
`service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app)
`service.type` | `ClusterIP` | Type of the Kubernetes Service
`service.metricsPort` | `9797` | Prometheus metrics endpoint port
`service.httpPort` | `9898` | Container HTTP port
`service.externalPort` | `9898` | ClusterIP HTTP port
`service.grpcPort` | `9999` | ClusterIP gPRC port
`service.grpcService` | `podinfo` | gPRC service name
`service.nodePort` | `31198` | NodePort for the HTTP endpoint
`h2c.enabled` | `false` | Allow upgrading to h2c (non-TLS version of HTTP/2)
`hpa.enabled` | `false` | Enables the Kubernetes HPA
`hpa.maxReplicas` | `10` | Maximum amount of pods
`hpa.cpu` | `None` | Target CPU usage per pod
`hpa.memory` | `None` | Target memory usage per pod
`hpa.requests` | `None` | Target HTTP requests per second per pod
`serviceAccount.enabled` | `false` | Whether a service account should be created
`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
`securityContext` | `{}` | The security context to be set on the podinfo container
`linkerd.profile.enabled` | `false` | Create Linkerd service profile
`serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created
`serviceMonitor.interval` | `15s` | Prometheus scraping interval
`serviceMonitor.additionalLabels` | `{}` | Add additional labels to the service monitor |
`ingress.enabled` | `false` | Enables Ingress
`ingress.className ` | `""` | Use ingressClassName
`ingress.annotations` | `{}` | Ingress annotations
`ingress.hosts` | `[]` | Ingress accepted hosts
`ingress.tls` | `[]` | Ingress TLS configuration
`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
`podAnnotations` | `{}` | Pod annotations
| Parameter | Default | Description |
| --------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `replicaCount` | `1` | Desired number of pods |
| `logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `backend` | `None` | Echo backend URL |
| `backends` | `[]` | Array of echo backend URLs |
| `cache` | `None` | Redis address in the format `tcp://<host>:<port>` |
| `redis.enabled` | `false` | Create Redis deployment for caching purposes |
| `ui.color` | `#34577c` | UI color |
| `ui.message` | `None` | UI greetings message |
| `ui.logo` | `None` | UI logo |
| `faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds |
| `faults.error` | `false` | 1/3 chances of a random HTTP response error |
| `faults.unhealthy` | `false` | When set, the healthy state is never reached |
| `faults.unready` | `false` | When set, the ready state is never reached |
| `faults.testFail` | `false` | When set, a helm test is included which always fails |
| `faults.testTimeout` | `false` | When set, a helm test is included which always times out |
| `image.repository` | `stefanprodan/podinfo` | Image repository |
| `image.tag` | `<VERSION>` | Image tag |
| `image.pullPolicy` | `IfNotPresent` | Image pull policy |
| `service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app) |
| `service.type` | `ClusterIP` | Type of the Kubernetes Service |
| `service.metricsPort` | `9797` | Prometheus metrics endpoint port |
| `service.httpPort` | `9898` | Container HTTP port |
| `service.externalPort` | `9898` | ClusterIP HTTP port |
| `service.grpcPort` | `9999` | ClusterIP gPRC port |
| `service.grpcService` | `podinfo` | gPRC service name |
| `service.nodePort` | `31198` | NodePort for the HTTP endpoint |
| `h2c.enabled` | `false` | Allow upgrading to h2c (non-TLS version of HTTP/2) |
| `extraEnvs` | `[]` | Extra environment variables for the podinfo container |
| `config.path` | `""` | config file path |
| `config.name` | `""` | config file name |
| `extraArgs` | `[]` | Additional command line arguments to pass to podinfo container |
| `hpa.enabled` | `false` | Enables the Kubernetes HPA |
| `hpa.maxReplicas` | `10` | Maximum amount of pods |
| `hpa.cpu` | `None` | Target CPU usage per pod |
| `hpa.memory` | `None` | Target memory usage per pod |
| `hpa.requests` | `None` | Target HTTP requests per second per pod |
| `serviceAccount.enabled` | `false` | Whether a service account should be created |
| `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 |
| `serviceAccount.imagePullSecrets` | `[]` | List of image pull secrets if pulling from private registries. |
| `securityContext` | `{}` | The security context to be set on the podinfo container |
| `podSecurityContext` | `{}` | The security context to be set on the pod |
| `linkerd.profile.enabled` | `false` | Create Linkerd service profile |
| `serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created |
| `serviceMonitor.interval` | `15s` | Prometheus scraping interval |
| `serviceMonitor.additionalLabels` | `{}` | Add additional labels to the service monitor |
| `ingress.enabled` | `false` | Enables Ingress |
| `ingress.className` | `""` | Use ingressClassName |
| `ingress.additionalLabels` | `{}` | Add additional labels to the ingress |
| `ingress.annotations` | `{}` | Ingress annotations |
| `ingress.hosts` | `[]` | Ingress accepted hosts |
| `ingress.tls` | `[]` | Ingress TLS configuration |
| `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 |
| `podAnnotations` | `{}` | Pod annotations |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
@@ -110,14 +133,3 @@ $ helm install my-release podinfo/podinfo -f values.yaml
```
> **Tip**: You can use the default [values.yaml](values.yaml)
## Upgrading the chart
### To =< 5.0.0
Version 5.0.0 is a major update.
* The chart now follows the new Kubernetes label recommendations:
<https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/>
The simplest way to update is to do a force upgrade, which recreates the resources by doing a delete and an install.

View File

@@ -1,7 +1,9 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- 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" . }})

View File

@@ -73,7 +73,7 @@ spec:
{{- if .Values.cache }}
- --cache-server={{ .Values.cache }}
{{- else if .Values.redis.enabled }}
- --cache-server={{ template "podinfo.fullname" . }}-redis:6379
- --cache-server=tcp://{{ template "podinfo.fullname" . }}-redis:6379
{{- end }}
- --level={{ .Values.logLevel }}
- --random-delay={{ .Values.faults.delay }}
@@ -87,6 +87,15 @@ spec:
{{- if .Values.h2c.enabled }}
- --h2c
{{- end }}
{{- with .Values.config.path }}
- --config-path={{ . }}
{{- end }}
{{- with .Values.config.name }}
- --config={{ . }}
{{- end }}
{{- with .Values.extraArgs }}
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if .Values.ui.message }}
- name: PODINFO_UI_MESSAGE
@@ -104,6 +113,9 @@ spec:
- name: PODINFO_BACKEND_URL
value: {{ .Values.backend }}
{{- end }}
{{- if .Values.extraEnvs }}
{{ toYaml .Values.extraEnvs | indent 10 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.httpPort | default 9898 }}
@@ -129,6 +141,22 @@ spec:
containerPort: {{ .Values.service.grpcPort }}
protocol: TCP
{{- end }}
{{- if .Values.probes.startup.enable }}
startupProbe:
exec:
command:
- podcli
- check
- http
- localhost:{{ .Values.service.httpPort | default 9898 }}/healthz
{{- with .Values.probes.startup }}
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
failureThreshold: {{ .failureThreshold | default 3 }}
successThreshold: {{ .successThreshold | default 1 }}
periodSeconds: {{ .periodSeconds | default 10 }}
{{- end }}
{{- end }}
livenessProbe:
exec:
command:
@@ -136,8 +164,13 @@ spec:
- check
- http
- localhost:{{ .Values.service.httpPort | default 9898 }}/healthz
initialDelaySeconds: 1
timeoutSeconds: 5
{{- with .Values.probes.liveness }}
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
failureThreshold: {{ .failureThreshold | default 3 }}
successThreshold: {{ .successThreshold | default 1 }}
periodSeconds: {{ .periodSeconds | default 10 }}
{{- end }}
readinessProbe:
exec:
command:
@@ -145,8 +178,13 @@ spec:
- check
- http
- localhost:{{ .Values.service.httpPort | default 9898 }}/readyz
initialDelaySeconds: 1
timeoutSeconds: 5
{{- with .Values.probes.readiness }}
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
failureThreshold: {{ .failureThreshold | default 3 }}
successThreshold: {{ .successThreshold | default 1 }}
periodSeconds: {{ .periodSeconds | default 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /data
@@ -157,6 +195,10 @@ spec:
{{- end }}
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.podSecurityContext }}
securityContext:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
@@ -177,3 +219,7 @@ spec:
secret:
secretName: {{ template "podinfo.tlsSecretName" . }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -1,5 +1,5 @@
{{- if .Values.hpa.enabled -}}
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ template "podinfo.fullname" . }}

View File

@@ -7,6 +7,9 @@ metadata:
name: {{ $fullName }}
labels:
{{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.ingress.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}

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: {{ .Release.Namespace }}
labels:
{{- include "podinfo.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "podinfo.selectorLabels" . | nindent 6 }}
{{- toYaml .Values.podDisruptionBudget | nindent 2 }}
{{- end }}

View File

@@ -5,4 +5,8 @@ metadata:
name: {{ template "podinfo.serviceAccountName" . }}
labels:
{{- include "podinfo.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 2 }}
{{- end -}}
{{- end -}}

View File

@@ -8,7 +8,7 @@ backends: []
image:
repository: ghcr.io/stefanprodan/podinfo
tag: 6.0.2
tag: 6.8.0
pullPolicy: IfNotPresent
ui:
@@ -41,6 +41,16 @@ service:
h2c:
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
tls:
enabled: false
@@ -77,13 +87,13 @@ hpa:
# average http requests per second per pod (k8s-prometheus-adapter)
requests:
# Redis address in the format <host>:<port>
# Redis address in the format tcp://<host>:<port>
cache: ""
# Redis deployment
redis:
enabled: true
repository: redis
tag: 6.0.8
tag: 7.0.7
serviceAccount:
# Specifies whether a service account should be created
@@ -91,13 +101,19 @@ serviceAccount:
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name:
# List of image pull secrets if pulling from private registries
imagePullSecrets: []
# set container security context
securityContext: {}
# set pod security context
podSecurityContext: {}
ingress:
enabled: false
className: ""
additionalLabels: {}
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
@@ -128,6 +144,14 @@ resources:
cpu: 100m
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: {}
tolerations: []

View File

@@ -8,7 +8,7 @@ backends: []
image:
repository: ghcr.io/stefanprodan/podinfo
tag: 6.0.2
tag: 6.8.0
pullPolicy: IfNotPresent
ui:
@@ -45,6 +45,16 @@ service:
h2c:
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
tls:
enabled: false
@@ -81,13 +91,13 @@ hpa:
# average http requests per second per pod (k8s-prometheus-adapter)
requests:
# Redis address in the format <host>:<port>
# Redis address in the format tcp://<host>:<port>
cache: ""
# Redis deployment
redis:
enabled: false
repository: redis
tag: 6.0.8
tag: 7.0.7
serviceAccount:
# Specifies whether a service account should be created
@@ -95,13 +105,19 @@ serviceAccount:
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name:
# List of image pull secrets if pulling from private registries
imagePullSecrets: []
# set container security context
securityContext: {}
# set pod security context
podSecurityContext: {}
ingress:
enabled: false
className: ""
additionalLabels: {}
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
@@ -131,6 +147,14 @@ resources:
cpu: 1m
memory: 16Mi
# 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: {}
tolerations: []
@@ -138,3 +162,32 @@ tolerations: []
affinity: {}
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
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

@@ -2,7 +2,6 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -14,10 +13,11 @@ import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/stefanprodan/podinfo/pkg/api"
"github.com/stefanprodan/podinfo/pkg/grpc"
"github.com/stefanprodan/podinfo/pkg/api/grpc"
"github.com/stefanprodan/podinfo/pkg/api/http"
"github.com/stefanprodan/podinfo/pkg/signals"
"github.com/stefanprodan/podinfo/pkg/version"
go_grpc "google.golang.org/grpc"
)
func main() {
@@ -29,11 +29,11 @@ func main() {
fs.Int("port-metrics", 0, "metrics port")
fs.Int("grpc-port", 0, "gRPC port")
fs.String("grpc-service-name", "podinfo", "gPRC service name")
fs.String("level", "info", "log level debug, info, warn, error, flat or panic")
fs.String("level", "info", "log level debug, info, warn, error, fatal or panic")
fs.StringSlice("backend-url", []string{}, "backend service URL")
fs.Duration("http-client-timeout", 2*time.Minute, "client timeout duration")
fs.Duration("http-server-timeout", 30*time.Second, "server read and write timeout duration")
fs.Duration("http-server-shutdown-timeout", 5*time.Second, "server graceful shutdown timeout duration")
fs.Duration("server-shutdown-timeout", 5*time.Second, "server graceful shutdown timeout duration")
fs.String("data-path", "/data", "data local path")
fs.String("config-path", "", "config dir path")
fs.String("cert-path", "/data/cert", "certificate path for HTTPS port")
@@ -52,7 +52,8 @@ func main() {
fs.Bool("unready", false, "when set, ready state is never reached")
fs.Int("stress-cpu", 0, "number of CPU cores with 100 load")
fs.Int("stress-memory", 0, "MB of data to load into memory")
fs.String("cache-server", "", "Redis address in the format <host>:<port>")
fs.String("cache-server", "", "Redis address in the format 'tcp://<host>:<port>'")
fs.String("otel-service-name", "", "service name for reporting to open telemetry address, when not set tracing is disabled")
versionFlag := fs.BoolP("version", "v", false, "get version number")
@@ -134,13 +135,16 @@ func main() {
}
// start gRPC server
var grpcServer *go_grpc.Server
if grpcCfg.Port > 0 {
grpcSrv, _ := grpc.NewServer(&grpcCfg, logger)
go grpcSrv.ListenAndServe()
//grpcinfoSrv, _ := grpc.NewInfoServer(&grpcCfg)
grpcServer = grpcSrv.ListenAndServe()
}
// load HTTP server config
var srvCfg api.Config
var srvCfg http.Config
if err := viper.Unmarshal(&srvCfg); err != nil {
logger.Panic("config unmarshal failed", zap.Error(err))
}
@@ -153,9 +157,13 @@ func main() {
)
// start HTTP server
srv, _ := api.NewServer(&srvCfg, logger)
srv, _ := http.NewServer(&srvCfg, logger)
httpServer, httpsServer, healthy, ready := srv.ListenAndServe()
// graceful shutdown
stopCh := signals.SetupSignalHandler()
srv.ListenAndServe(stopCh)
sd, _ := signals.NewShutdown(srvCfg.ServerShutdownTimeout, logger)
sd.Graceful(stopCh, httpServer, httpsServer, grpcServer, healthy, ready)
}
func initZap(logLevel string) (*zap.Logger, error) {
@@ -237,12 +245,12 @@ func beginStressTest(cpus int, mem int, logger *zap.Logger) {
logger.Error("memory stress failed", zap.Error(err))
}
stressMemoryPayload, err = ioutil.ReadFile(path)
stressMemoryPayload, err = os.ReadFile(path)
f.Close()
os.Remove(path)
if err != nil {
logger.Error("memory stress failed", zap.Error(err))
}
logger.Info("starting CPU stress", zap.Int("memory", len(stressMemoryPayload)))
logger.Info("starting MEMORY stress", zap.Int("memory", len(stressMemoryPayload)))
}
}

View File

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

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend

View File

@@ -13,7 +13,7 @@ spec:
spec:
containers:
- name: redis
image: redis:6.0.1
image: redis:7.0.7
imagePullPolicy: IfNotPresent
command:
- redis-server

View File

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

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend

View File

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

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend

View File

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

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend

104
go.mod
View File

@@ -1,24 +1,90 @@
module github.com/stefanprodan/podinfo
go 1.16
go 1.24
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
github.com/fatih/color v1.9.0
github.com/fsnotify/fsnotify v1.4.9
github.com/gomodule/redigo v1.8.4
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/prometheus/client_golang v1.11.0
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.8.1
github.com/swaggo/http-swagger v1.0.0
github.com/swaggo/swag v1.7.0
go.uber.org/zap v1.19.1
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
google.golang.org/grpc v1.38.0
github.com/chzyer/readline v1.5.1
github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.8.0
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/gomodule/redigo v1.9.2
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/prometheus/client_golang v1.21.1
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/spf13/viper v1.19.0
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.4
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.60.0
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0
go.opentelemetry.io/contrib/propagators/aws v1.35.0
go.opentelemetry.io/contrib/propagators/b3 v1.35.0
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0
go.opentelemetry.io/contrib/propagators/ot v1.35.0
go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
go.opentelemetry.io/otel/sdk v1.35.0
go.opentelemetry.io/otel/trace v1.35.0
go.uber.org/zap v1.27.0
golang.org/x/net v0.37.0
google.golang.org/grpc v1.71.0
google.golang.org/protobuf v1.36.5
)
// Fix CVE-2022-32149
replace golang.org/x/text => golang.org/x/text v0.23.0
// Fix CVE-2022-28948
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/swaggo/files v1.0.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/tools v0.31.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

947
go.sum
View File

@@ -1,751 +1,238 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
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/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
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/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU=
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I=
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI=
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg=
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
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 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
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/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.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.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s=
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
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/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
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/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/http-swagger v1.0.0 h1:ksYgVBCYmAaxFsGVGojlPROgYfiQQSllETTWMtHJHTo=
github.com/swaggo/http-swagger v1.0.0/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8=
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
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/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.60.0 h1:iLuogsToNW6QaOYPcbIwhkdRTkc0gvXzuiajObXc6WY=
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.60.0/go.mod h1:XNSNQBtSOifFUw0aQUyBN0Ff+0NddEnbSATy2QlFgm8=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0 h1:0tY123n7CdWMem7MOVdKOt0YfshufLCwfE5Bob+hQuM=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/contrib/propagators/aws v1.35.0 h1:xoXA+5dVwsf5uE5GvSJ3lKiapyMFuIzbEmJwQ0JP+QU=
go.opentelemetry.io/contrib/propagators/aws v1.35.0/go.mod h1:s11Orts/IzEgw9Srw5iRXtk2kM2j3jt/45noUWyf60E=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg=
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0 h1:UIrZgRBHUrYRlJ4V419lVb4rs2ar0wFzKNAebaP05XU=
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0/go.mod h1:0ciyFyYZxE6JqRAQvIgGRabKWDUmNdW3GAQb6y/RlFU=
go.opentelemetry.io/contrib/propagators/ot v1.35.0 h1:ZsgYijVvOpju4mq3g4QyqCwLKs2vKenlCpZHbKu50OA=
go.opentelemetry.io/contrib/propagators/ot v1.35.0/go.mod h1:t1ZwtgjEtDH9uW6OlCRVLL2wOgsTJmp0pJwNouUq+HE=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

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

View File

@@ -1,4 +1,4 @@
apiVersion: autoscaling/v2beta2
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: podinfo

View File

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

20
otel/Makefile Normal file
View File

@@ -0,0 +1,20 @@
DC=docker-compose -f docker-compose.yaml
.PHONY: help
.DEFAULT_GOAL := help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
stop: ## Stop all Docker Containers run in Compose
$(DC) stop
clean: stop ## Clean all Docker Containers and Volumes
$(DC) down --rmi local --remove-orphans -v
$(DC) rm -f -v
build: clean ## Rebuild the Docker Image for use by Compose
$(DC) build
run: stop ## Run the Application
$(DC) up

37
otel/README.md Normal file
View File

@@ -0,0 +1,37 @@
# Tracing Demo
The directory contains sample [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector)
and [Jaeger](https://www.jaegertracing.io) configurations for a tracing demo.
## Configuration
The provided [docker-compose.yaml](docker-compose.yaml) sets up 4 Containers
1. PodInfo Frontend on port 9898
2. PodInfo Backend on port 9899
3. OpenTelemetry Collector listening on port 4317 for GRPC
4. Jaeger all-in-one listening on multiple ports
## How does it work?
The frontend pods are configured to call onto the backend pods. Both the podinfo
pods are configured to send traces over to the collector at port 4317 using GRPC.
The collector forwards all received spans to Jaeger over port 14250 and Jaeger
exposes a UI over port `16686`.
## Running it locally
1. Start all the Containers
```shell
make run
```
2. Send some sample requests
```shell
curl -v http://localhost:9898/status/200
curl -X POST -v http://localhost:9898/api/echo
```
3. Visit `http://localhost:16686/` to see the spans
4. Stop all the containers
```shell
make stop
```

35
otel/docker-compose.yaml Normal file
View File

@@ -0,0 +1,35 @@
version: '2'
services:
podinfo_frontend:
build: ..
command: ./podinfo --backend-url http://podinfo_backend:9899/status/200 --otel-service-name=podinfo_frontend
environment:
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel:4317
ports:
- "9898:9898"
podinfo_backend:
build: ..
command: ./podinfo --port 9899 --otel-service-name=podinfo_backend
environment:
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel:4317
ports:
- "9899:9899"
otel:
command: --config otel-config.yaml
image: otel/opentelemetry-collector:0.41.0
ports:
- "4317:4317"
volumes:
- ${PWD}/otel-config.yaml:/otel-config.yaml
jaeger:
image: jaegertracing/all-in-one:1.29.0
ports:
- "5775:5775/udp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
- "16686:16686"
- "14268:14268"
- "14250:14250"
- "9411:9411"

26
otel/otel-config.yaml Normal file
View File

@@ -0,0 +1,26 @@
receivers:
otlp:
protocols:
grpc:
http:
processors:
exporters:
jaeger:
endpoint: jaeger:14250
tls:
insecure: true
extensions:
health_check:
pprof:
zpages:
service:
extensions: [health_check,pprof,zpages]
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [jaeger]

View File

@@ -1,34 +0,0 @@
package api
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestEchoHandler(t *testing.T) {
expected := `{"test": true}`
req, err := http.NewRequest("POST", "/api/echo", strings.NewReader(expected))
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
srv := NewMockServer()
handler := http.HandlerFunc(srv.echoHandler)
handler.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusAccepted {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusAccepted)
}
// Check the response body is what we expect.
if rr.Body.String() != expected {
t.Fatalf("handler returned unexpected body:\ngot \n%v \nwant \n%s",
rr.Body.String(), expected)
}
}

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