mirror of
https://github.com/labring/sealos.git
synced 2026-09-21 05:44:43 +08:00
feat(service): add Hubble service to enhance observability (#5729)
feat(service): add Hubble service to enhance observability.
This commit is contained in:
@@ -88,6 +88,7 @@ jobs:
|
||||
exceptionmonitor,
|
||||
devbox,
|
||||
vlogs,
|
||||
hubble,
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -237,6 +238,7 @@ jobs:
|
||||
exceptionmonitor,
|
||||
devbox,
|
||||
vlogs,
|
||||
hubble,
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ use (
|
||||
./pay
|
||||
./devbox
|
||||
./vlogs
|
||||
./hubble
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
@@ -2,10 +2,12 @@ cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||
cel.dev/expr v0.16.1 h1:NR0+oFYzR1CqLFhTAqg3ql59G9VfN8fKq1TCHJ6gq1g=
|
||||
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
|
||||
cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8=
|
||||
cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
|
||||
cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0=
|
||||
cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
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=
|
||||
@@ -188,6 +190,7 @@ cloud.google.com/go/compute/metadata v0.2.0 h1:nBbNSZyDpkNlo3DepaaLKVuO7ClyifSAm
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
|
||||
@@ -760,6 +763,7 @@ cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/v
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
@@ -817,6 +821,7 @@ github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrG
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||
github.com/apache/arrow/go/v11 v11.0.0 h1:hqauxvFQxww+0mEU/2XHG6LT7eZternCZq+A5Yly2uM=
|
||||
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
|
||||
@@ -897,6 +902,7 @@ github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFos
|
||||
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
|
||||
github.com/casbin/casbin/v2 v2.37.0 h1:/poEwPSovi4bTOcP752/CsTQiRz2xycyVKFG7GUhbDw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
|
||||
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/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||
@@ -940,6 +946,7 @@ github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+g
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
|
||||
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
@@ -953,6 +960,7 @@ github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSk
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||
github.com/containers/storage v1.50.2 h1:Fys4BjFUVNRBEXlO70hFI48VW4EXsgnGisTpk9tTMsE=
|
||||
github.com/containers/storage v1.50.2/go.mod h1:dpspZsUrcKD8SpTofvKWhwPDHD0MkO4Q7VE+oYdWkiA=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
@@ -1006,6 +1014,7 @@ github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:
|
||||
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
|
||||
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
|
||||
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
|
||||
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
|
||||
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
|
||||
github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les=
|
||||
github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
|
||||
@@ -1016,6 +1025,7 @@ github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byA
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||
@@ -1027,6 +1037,7 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/flowstack/go-jsonschema v0.1.1 h1:dCrjGJRXIlbDsLAgTJZTjhwUJnnxVWl1OgNyYh5nyDc=
|
||||
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
|
||||
@@ -1069,6 +1080,7 @@ github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaC
|
||||
github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-zookeeper/zk v1.0.2 h1:4mx0EYENAdX/B/rbunjlt5+4RTA/a9SMHBRuSKdGxPM=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
@@ -1088,6 +1100,7 @@ github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
|
||||
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
|
||||
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
@@ -1108,6 +1121,7 @@ github.com/google/cel-go v0.12.6 h1:kjeKudqV0OygrAqA9fX6J55S8gj+Jre2tckIm5RoG4M=
|
||||
github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw=
|
||||
github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ=
|
||||
github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
|
||||
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
|
||||
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
|
||||
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
|
||||
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
@@ -1123,6 +1137,7 @@ github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMc
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||
github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||
@@ -1134,6 +1149,7 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||
github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM=
|
||||
@@ -1146,6 +1162,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A=
|
||||
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
@@ -1164,6 +1181,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||
@@ -1174,6 +1192,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjd
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||
github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
@@ -1245,11 +1264,13 @@ github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJz
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
|
||||
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
@@ -1328,15 +1349,18 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
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/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY=
|
||||
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
|
||||
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
@@ -1359,6 +1383,7 @@ github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
@@ -1367,6 +1392,7 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
@@ -1375,6 +1401,7 @@ github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16A
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
|
||||
@@ -1409,11 +1436,13 @@ github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
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/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
|
||||
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
|
||||
github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
@@ -1447,6 +1476,7 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
@@ -1476,6 +1506,14 @@ github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJV
|
||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0 h1:QIF48X1cihydXibm+4wfAc0r/qyPyuFiPFRNphdMpEE=
|
||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400 h1:091wFNQB3PXcL5+me0joH7EiyqQaI0wGMpEjVCkK04U=
|
||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs=
|
||||
github.com/smartwalle/alipay/v3 v3.2.25 h1:cRDN+fpDWTVHnuHIF/vsJETskRXS/S+fDOdAkzXmV/Q=
|
||||
github.com/smartwalle/alipay/v3 v3.2.25/go.mod h1:lVqFiupPf8YsAXaq5JXcwqnOUC2MCF+2/5vub+RlagE=
|
||||
github.com/smartwalle/ncrypto v1.0.4 h1:P2rqQxDepJwgeO5ShoC+wGcK2wNJDmcdBOWAksuIgx8=
|
||||
github.com/smartwalle/ncrypto v1.0.4/go.mod h1:Dwlp6sfeNaPMnOxMNayMTacvC5JGEVln3CVdiVDgbBk=
|
||||
github.com/smartwalle/ngx v1.0.9 h1:pUXDvWRZJIHVrCKA1uZ15YwNti+5P4GuJGbpJ4WvpMw=
|
||||
github.com/smartwalle/ngx v1.0.9/go.mod h1:mx/nz2Pk5j+RBs7t6u6k22MPiBG/8CtOMpCnALIG8Y0=
|
||||
github.com/smartwalle/nsign v1.0.9 h1:8poAgG7zBd8HkZy9RQDwasC6XZvJpDGQWSjzL2FZL6E=
|
||||
github.com/smartwalle/nsign v1.0.9/go.mod h1:eY6I4CJlyNdVMP+t6z1H6Jpd4m5/V+8xi44ufSTxXgc=
|
||||
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
@@ -1509,6 +1547,7 @@ github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1Fof
|
||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec h1:q6XVwXmKvCRHRqesF3cSv6lNqqHi0QWOvgDlSohg8UA=
|
||||
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
|
||||
github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e h1:mOtuXaRAbVZsxAHVdPR3IjfmN8T1h2iczJLynhLybf8=
|
||||
@@ -1561,6 +1600,7 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
|
||||
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||
@@ -1574,45 +1614,53 @@ go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY=
|
||||
go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
|
||||
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
|
||||
go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs=
|
||||
go.etcd.io/etcd/client/v2 v2.305.7 h1:AELPkjNR3/igjbO7CjyF1fPuVPjrblliiKj+Y6xSGOU=
|
||||
go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq9BgzFU6s=
|
||||
go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4=
|
||||
go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA=
|
||||
go.etcd.io/etcd/client/v2 v2.305.16 h1:kQrn9o5czVNaukf2A2At43cE9ZtWauOtf9vRZuiKXow=
|
||||
go.etcd.io/etcd/client/v2 v2.305.16/go.mod h1:h9YxWCzcdvZENbfzBTFCnoNumr2ax3F19sKMqHFmXHE=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek=
|
||||
go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw=
|
||||
go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
|
||||
go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
|
||||
go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE=
|
||||
go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.7 h1:obOzeVwerFwZ9trMWapU/VjDcYUJb5OfgC1zqEGWO/0=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.7/go.mod h1:kcOfWt3Ov9zgYdOiJ/o1Y9zFfLhQjylTgL4Lru8opRo=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.16 h1:cnavs5WSPWeK4TYwPYfmcr3Joz9BH+TZ6qoUtz6/+mc=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.16/go.mod h1:+lutCZHG5MBBFI/U4eYT5yL7sJfnexsoM20Y0t2uNuY=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.7 h1:aN79qxLmV3SvIq84aNTliYGmjwsW6NqJSnqmI1HLJKc=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.7/go.mod h1:TflkAb/8Uy6JFBxcRaH2Fr6Slm9mCPVdI2efzxY96yU=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI=
|
||||
go.etcd.io/etcd/server/v3 v3.5.7 h1:BTBD8IJUV7YFgsczZMHhMTS67XuA4KpRquL0MFOJGRk=
|
||||
go.etcd.io/etcd/server/v3 v3.5.7/go.mod h1:gxBgT84issUVBRpZ3XkW1T55NjOb4vZZRI4wVvNhf4A=
|
||||
go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg=
|
||||
go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo=
|
||||
go.etcd.io/etcd/server/v3 v3.5.16 h1:d0/SAdJ3vVsZvF8IFVb1k8zqMZ+heGcNfft71ul9GWE=
|
||||
go.etcd.io/etcd/server/v3 v3.5.16/go.mod h1:ynhyZZpdDp1Gq49jkUg5mfkDWZwXnn3eIqCqtJnrD/s=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
@@ -1624,16 +1672,19 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.3
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1 h1:sxoY9kG1s1WpSYNyzm24rlwH4lnRYFXUVVBmKMBfRgw=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||
go.opentelemetry.io/otel v1.10.0 h1:Y7DTJMR6zs1xkS/upamJYk0SxxN4C9AqRd77jmZnyY4=
|
||||
go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
||||
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||
@@ -1643,16 +1694,19 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0 h1:pDDYmo0QadUPal5fwXo
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0 h1:KtiUEhQmj/Pa874bVYKGNVdq8NPKiacPbaRRtgXi+t4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h1:OfUCyyIiDvNXHWpcWgbF+MWvqPZiNa3YDEnivcnYsV0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
|
||||
go.opentelemetry.io/otel/metric v0.31.0 h1:6SiklT+gfWAwWUR0meEMxQBtihpiEs4c+vL9spDTqUs=
|
||||
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
|
||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||
@@ -1660,6 +1714,7 @@ go.opentelemetry.io/otel/sdk v1.10.0 h1:jZ6K7sVn04kk/3DNUdJ4mqRlGDiXAVuIG+MMENpT
|
||||
go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
|
||||
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
|
||||
@@ -1668,6 +1723,7 @@ go.opentelemetry.io/otel/trace v1.10.0 h1:npQMbR8o7mum8uF95yFbOEJffhs1sbCOfDh8zA
|
||||
go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
@@ -1676,6 +1732,7 @@ go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJP
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
@@ -1703,6 +1760,7 @@ golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ug
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
|
||||
@@ -1720,6 +1778,7 @@ golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@@ -1846,6 +1905,7 @@ gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuB
|
||||
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b h1:Qh4dB5D/WpoUUp3lSod7qgoyEHbDGPUWjIbnqdqqe1k=
|
||||
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
|
||||
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=
|
||||
@@ -1887,6 +1947,7 @@ google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy
|
||||
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY=
|
||||
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg=
|
||||
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
|
||||
google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE=
|
||||
google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE=
|
||||
@@ -1907,6 +1968,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
|
||||
@@ -1936,6 +1998,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
@@ -1959,6 +2022,7 @@ google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9Y
|
||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
||||
google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
|
||||
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
|
||||
@@ -1980,6 +2044,7 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
@@ -2007,6 +2072,7 @@ k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E=
|
||||
k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y=
|
||||
k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o=
|
||||
k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM=
|
||||
k8s.io/apiserver v0.32.1 h1:oo0OozRos66WFq87Zc5tclUX2r0mymoVHRq8JmR7Aak=
|
||||
k8s.io/apiserver v0.32.1/go.mod h1:UcB9tWjBY7aryeI5zAgzVJB/6k7E97bkr1RgqDz0jPw=
|
||||
k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
|
||||
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||
@@ -2017,11 +2083,13 @@ k8s.io/code-generator v0.27.2 h1:RmK0CnU5qRaK6WRtSyWNODmfTZNoJbrizpVcsgbtrvI=
|
||||
k8s.io/code-generator v0.27.2/go.mod h1:DPung1sI5vBgn4AGKtlPRQAyagj/ir/4jI55ipZHVww=
|
||||
k8s.io/code-generator v0.29.0 h1:2LQfayGDhaIlaamXjIjEQlCMy4JNCH9lrzas4DNW1GQ=
|
||||
k8s.io/code-generator v0.29.0/go.mod h1:5bqIZoCxs2zTRKMWNYqyQWW/bajc+ah4rh0tMY8zdGA=
|
||||
k8s.io/code-generator v0.32.1 h1:4lw1kFNDuFYXquTkB7Sl5EwPMUP2yyW9hh6BnFfRZFY=
|
||||
k8s.io/code-generator v0.32.1/go.mod h1:zaILfm00CVyP/6/pJMJ3zxRepXkxyDfUV5SNG4CjZI4=
|
||||
k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo=
|
||||
k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo=
|
||||
k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s=
|
||||
k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M=
|
||||
k8s.io/component-base v0.32.1 h1:/5IfJ0dHIKBWysGV0yKTFfacZ5yNV1sulPh3ilJjRZk=
|
||||
k8s.io/component-base v0.32.1/go.mod h1:j1iMMHi/sqAHeG5z+O9BFNCF698a1u0186zkjMZQ28w=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
|
||||
@@ -2031,6 +2099,7 @@ k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAE
|
||||
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo=
|
||||
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
|
||||
k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4=
|
||||
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
@@ -2042,6 +2111,7 @@ k8s.io/kms v0.27.2 h1:wCdmPCa3kubcVd3AssOeaVjLQSu45k5g/vruJ3iqwDU=
|
||||
k8s.io/kms v0.27.2/go.mod h1:dahSqjI05J55Fo5qipzvHSRbm20d7llrSeQjjl86A7c=
|
||||
k8s.io/kms v0.29.0 h1:KJ1zaZt74CgvgV3NR7tnURJ/mJOKC5X3nwon/WdwgxI=
|
||||
k8s.io/kms v0.29.0/go.mod h1:mB0f9HLxRXeXUfHfn1A7rpwOlzXI1gIWu86z6buNoYA=
|
||||
k8s.io/kms v0.32.1 h1:TW6cswRI/fawoQRFGWLmEceO37rZXupdoRdmO019jCc=
|
||||
k8s.io/kms v0.32.1/go.mod h1:Bk2evz/Yvk0oVrvm4MvZbgq8BD34Ksxs2SRHn4/UiOM=
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||
@@ -2068,6 +2138,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6U
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||
sigs.k8s.io/controller-runtime v0.15.2 h1:9V7b7SDQSJ08IIsJ6CY1CE85Okhp87dyTMNDG0FS7f4=
|
||||
sigs.k8s.io/controller-runtime v0.15.2/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk=
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/go.sum
|
||||
/.idea/.gitignore
|
||||
@@ -0,0 +1,7 @@
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
ARG TARGETARCH
|
||||
COPY bin/service-hubble-$TARGETARCH /manager
|
||||
EXPOSE 8428
|
||||
USER 65532:65532
|
||||
|
||||
ENTRYPOINT [ "/manager", "config/config.yml" ]
|
||||
@@ -0,0 +1,57 @@
|
||||
IMG ?= bearslyricattack/sealos-hubble-service:latest
|
||||
#IMG ?= ghcr.io/labring/sealos-collector-service:latest
|
||||
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
ifeq (,$(shell go env GOBIN))
|
||||
GOBIN=$(shell go env GOPATH)/bin
|
||||
else
|
||||
GOBIN=$(shell go env GOBIN)
|
||||
endif
|
||||
|
||||
# only support linux, non cgo
|
||||
PLATFORMS ?= linux_arm64 linux_amd64
|
||||
GOOS=linux
|
||||
CGO_ENABLED=0
|
||||
TARGETARCH=amd64
|
||||
GOARCH=$(shell go env GOARCH)
|
||||
|
||||
GO_BUILD_FLAGS=-trimpath -ldflags "-s -w"
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
##@ General
|
||||
|
||||
# The help target prints out all targets with their descriptions organized
|
||||
# beneath their categories. The categories are represented by '##@' and the
|
||||
# target descriptions by '##'. The awk commands is responsible for reading the
|
||||
# entire set of makefiles included in this invocation, looking for lines of the
|
||||
# file as xyz: ## something, and then pretty-format the target and help. Then,
|
||||
# if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||
# More info on the usage of ANSI control characters for terminal formatting:
|
||||
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
|
||||
# More info on the awk command:
|
||||
# http://linuxcommand.org/lc3_adv_awk.php
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help.
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
##@ Build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(SERVICE_NAME)
|
||||
|
||||
.PHONY: build
|
||||
build: clean ## Build service-hub binary.
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) go build $(GO_BUILD_FLAGS) -o bin/manager cmd/main.go
|
||||
|
||||
.PHONY: docker-build
|
||||
docker-build: build
|
||||
mv bin/manager bin/service-hubble-${TARGETARCH}
|
||||
docker build -t $(IMG) .
|
||||
|
||||
.PHONY: docker-push
|
||||
docker-push:
|
||||
docker push $(IMG)
|
||||
@@ -0,0 +1,265 @@
|
||||
# Hubble Service
|
||||
|
||||
A high-performance monitoring data collection and caching service for Sealos, designed to aggregate and serve network flow metrics from Cilium Hubble with Redis-based caching for optimal performance.
|
||||
|
||||
## Overview
|
||||
|
||||
Hubble Service acts as an intermediary layer between Cilium Hubble and frontend applications, providing:
|
||||
|
||||
- **Real-time Data Collection**: Continuously collects network flow metrics from Cilium Hubble Relay
|
||||
- **High-Performance Caching**: Redis-based caching layer for fast data retrieval
|
||||
- **RESTful API**: Clean HTTP endpoints for accessing monitoring data
|
||||
- **Authentication Support**: Built-in whitelist-based authentication mechanism
|
||||
- **Graceful Shutdown**: Proper signal handling for zero-downtime deployments
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ Cilium Hubble │────▶│ Hubble │────▶│ Redis │
|
||||
│ Relay │ │ Service │ │ Cache │
|
||||
└─────────────────┘ └──────────────┘ └─────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ Frontend │
|
||||
│ Applications │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Efficient Data Collection**: Connects to Hubble Relay for streaming network flow data
|
||||
- **Redis Integration**: Persistent caching with configurable TTL
|
||||
- **HTTP API Server**: RESTful endpoints for data retrieval
|
||||
- **TLS Support**: Secure communication with Hubble Relay
|
||||
- **Configurable Authentication**: Whitelist-based access control
|
||||
- **Production Ready**: Graceful shutdown, health checks, and proper error handling
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes cluster with Cilium and Hubble enabled
|
||||
- Redis instance (for caching)
|
||||
- Go 1.20+ (for development)
|
||||
- Docker (for containerization)
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Start
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone https://github.com/labring/sealos.git
|
||||
cd sealos/service/hubble
|
||||
```
|
||||
|
||||
2. **Configure the service**
|
||||
|
||||
Edit `config.yml` to match your environment:
|
||||
```yaml
|
||||
auth:
|
||||
whiteList: ["allowed-namespace-1", "allowed-namespace-2"]
|
||||
http:
|
||||
addr: ":8080"
|
||||
hubble:
|
||||
addr: "hubble-relay.kube-system.svc.cluster.local:80"
|
||||
redis:
|
||||
addr: "redis.default.svc.cluster.local:6379"
|
||||
username: "default"
|
||||
password: "your-redis-password"
|
||||
db: 10
|
||||
```
|
||||
|
||||
3. **Build and deploy**
|
||||
|
||||
Using Docker:
|
||||
```bash
|
||||
# Build the Docker image
|
||||
make docker-build IMG=your-registry/hubble-service:latest
|
||||
|
||||
# Push to registry
|
||||
make docker-push IMG=your-registry/hubble-service:latest
|
||||
|
||||
# Deploy to Kubernetes
|
||||
kubectl apply -f deploy/manifests/
|
||||
```
|
||||
|
||||
### Kubernetes Deployment
|
||||
|
||||
1. **Update the deployment manifest**
|
||||
|
||||
Edit `deploy/manifests/deploy.yaml` with your image and configuration:
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: hubble-service
|
||||
image: your-registry/hubble-service:latest
|
||||
env:
|
||||
- name: HUBBLE_RELAY_ADDR
|
||||
value: "hubble-relay.kube-system.svc.cluster.local:80"
|
||||
- name: REDIS_ADDR
|
||||
value: "redis.default.svc.cluster.local:6379"
|
||||
```
|
||||
|
||||
2. **Apply the manifests**
|
||||
```bash
|
||||
kubectl apply -f deploy/manifests/
|
||||
```
|
||||
|
||||
3. **Verify deployment**
|
||||
```bash
|
||||
kubectl get pods -l app=hubble-service
|
||||
kubectl logs -l app=hubble-service
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `CONFIG_PATH` | Path to configuration file | `./config.yml` |
|
||||
| `HUBBLE_RELAY_ADDR` | Hubble Relay service address | `hubble-relay.kube-system.svc.cluster.local:80` |
|
||||
| `REDIS_ADDR` | Redis server address | Required |
|
||||
| `REDIS_PASSWORD` | Redis authentication password | Optional |
|
||||
| `HTTP_PORT` | HTTP server listening port | `:8080` |
|
||||
| `AUTH_WHITELIST` | Comma-separated list of allowed namespaces | Optional |
|
||||
|
||||
### Configuration File
|
||||
|
||||
The service can be configured via a YAML file:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
whiteList: [] # List of allowed namespaces
|
||||
http:
|
||||
addr: ":8080" # HTTP server address
|
||||
hubble:
|
||||
addr: "hubble-relay.kube-system.svc.cluster.local:80"
|
||||
redis:
|
||||
addr: "localhost:6379"
|
||||
username: "default"
|
||||
password: ""
|
||||
db: 10
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Health Check
|
||||
```
|
||||
GET /health
|
||||
```
|
||||
Returns service health status
|
||||
|
||||
### Get Flow Metrics
|
||||
```
|
||||
GET /api/v1/flows
|
||||
```
|
||||
Returns cached network flow data
|
||||
|
||||
### Get Namespace Metrics
|
||||
```
|
||||
GET /api/v1/metrics/namespace/{namespace}
|
||||
```
|
||||
Returns metrics for a specific namespace
|
||||
|
||||
## Development
|
||||
|
||||
### Local Development
|
||||
|
||||
1. **Install dependencies**
|
||||
```bash
|
||||
go mod download
|
||||
```
|
||||
|
||||
2. **Run locally**
|
||||
```bash
|
||||
# Start Redis locally
|
||||
docker run -d -p 6379:6379 redis
|
||||
|
||||
# Run the service
|
||||
go run cmd/main.go -config=config.yml
|
||||
```
|
||||
|
||||
3. **Run tests**
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
### Building from Source
|
||||
|
||||
```bash
|
||||
# Build binary
|
||||
go build -o hubble-service cmd/main.go
|
||||
|
||||
# Build with specific version
|
||||
go build -ldflags="-X main.version=v1.0.0" -o hubble-service cmd/main.go
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
The service exposes internal metrics that can be scraped by Prometheus:
|
||||
|
||||
- `hubble_collector_flows_total` - Total number of flows collected
|
||||
- `hubble_cache_hits_total` - Cache hit rate
|
||||
- `hubble_cache_misses_total` - Cache miss rate
|
||||
- `hubble_api_requests_total` - API request count
|
||||
- `hubble_api_request_duration_seconds` - API request latency
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Cannot connect to Hubble Relay**
|
||||
- Verify Hubble is enabled in your Cilium installation
|
||||
- Check the Hubble Relay service is running: `kubectl get svc -n kube-system hubble-relay`
|
||||
- Ensure network policies allow communication
|
||||
|
||||
2. **Redis connection errors**
|
||||
- Verify Redis is accessible from the pod
|
||||
- Check Redis credentials and database number
|
||||
- Ensure Redis has sufficient memory
|
||||
|
||||
3. **No data returned from API**
|
||||
- Check collector logs for errors
|
||||
- Verify Hubble is generating flow data
|
||||
- Ensure Redis cache is working properly
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging by setting the environment variable:
|
||||
```bash
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions! Please see [CONTRIBUTING.md](../../CONTRIBUTING.md) for details.
|
||||
|
||||
1. Fork the repository
|
||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2023 Sealos Contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
## Support
|
||||
|
||||
For issues and questions:
|
||||
- GitHub Issues: [https://github.com/labring/sealos/issues](https://github.com/labring/sealos/issues)
|
||||
- Documentation: [https://docs.sealos.io](https://docs.sealos.io)
|
||||
@@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/labring/sealos/service/hubble/collector"
|
||||
"github.com/labring/sealos/service/hubble/config"
|
||||
"github.com/labring/sealos/service/hubble/datastore"
|
||||
"github.com/labring/sealos/service/hubble/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
configPath := flag.String("config", "", "path to configuration file")
|
||||
flag.Parse()
|
||||
|
||||
cfg, err := config.LoadConfig(*configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
redisClient := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.Redis.Addr,
|
||||
Username: cfg.Redis.Username,
|
||||
Password: cfg.Redis.Password,
|
||||
DB: cfg.Redis.DB,
|
||||
})
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := redisClient.Ping(ctx).Err(); err != nil {
|
||||
cancel()
|
||||
log.Fatalf("Failed to connect to Redis: %v", err)
|
||||
}
|
||||
log.Println("Successfully connected to Redis")
|
||||
dataStore := datastore.NewDataStore(redisClient)
|
||||
ctx, cancel = context.WithCancel(context.Background())
|
||||
collector, err := collector.NewCollector(cfg.Hubble.Addr, dataStore, true)
|
||||
if err != nil {
|
||||
cancel()
|
||||
log.Fatalf("Failed to create collector: %v", err)
|
||||
}
|
||||
go collector.Start(ctx)
|
||||
server := server.NewServer(dataStore, cfg.Auth.WhiteList)
|
||||
httpServer := &http.Server{
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
Addr: cfg.HTTP.Port,
|
||||
Handler: server.Router,
|
||||
}
|
||||
go func() {
|
||||
log.Printf("Starting HTTP server on %s", cfg.HTTP.Port)
|
||||
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("HTTP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set up signal handling for graceful shutdown
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigCh
|
||||
|
||||
// Create a timeout context for graceful shutdown
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer shutdownCancel()
|
||||
|
||||
cancel()
|
||||
|
||||
if err := httpServer.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("HTTP server shutdown error: %v", err)
|
||||
} else {
|
||||
log.Println("HTTP server shutdown gracefully")
|
||||
}
|
||||
log.Println("Graceful shutdown completed")
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/credentials"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
pb "github.com/cilium/cilium/api/v1/flow"
|
||||
observer "github.com/cilium/cilium/api/v1/observer"
|
||||
"github.com/labring/sealos/service/hubble/datastore"
|
||||
"github.com/labring/sealos/service/hubble/pkg/constants"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
// Collector handles the collection of network flow data from Hubble
|
||||
type Collector struct {
|
||||
hubbleAddr string
|
||||
dataStore *datastore.DataStore
|
||||
k8sClient kubernetes.Interface
|
||||
tlsConfig *TLSConfig
|
||||
}
|
||||
|
||||
func NewCollector(hubbleAddr string, dataStore *datastore.DataStore, enableTLS bool) (*Collector, error) {
|
||||
var k8sClient kubernetes.Interface
|
||||
var tlsConfig *TLSConfig
|
||||
if enableTLS {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get in-cluster config: %v", err)
|
||||
}
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create kubernetes client: %v", err)
|
||||
}
|
||||
k8sClient = clientset
|
||||
tlsConfig = NewDefaultTLSConfig()
|
||||
}
|
||||
|
||||
return &Collector{
|
||||
hubbleAddr: hubbleAddr,
|
||||
dataStore: dataStore,
|
||||
k8sClient: k8sClient,
|
||||
tlsConfig: tlsConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type FlowEndpoints struct {
|
||||
SourceNamespace string
|
||||
SourceName string
|
||||
SourceType string
|
||||
DestNamespace string
|
||||
DestName string
|
||||
DestType string
|
||||
}
|
||||
|
||||
// Start begins collecting flow data from Hubble
|
||||
func (c *Collector) Start(ctx context.Context) {
|
||||
log.Printf("Loaded hubble address: %s", c.hubbleAddr)
|
||||
var creds credentials.TransportCredentials
|
||||
if c.tlsConfig != nil && c.k8sClient != nil {
|
||||
tlsCreds, err := LoadTLSCredentials(ctx, c.k8sClient, c.tlsConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load TLS credentials: %v", err)
|
||||
}
|
||||
creds = tlsCreds
|
||||
} else {
|
||||
creds = insecure.NewCredentials()
|
||||
}
|
||||
conn, err := grpc.NewClient(
|
||||
c.hubbleAddr,
|
||||
grpc.WithTransportCredentials(creds),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to Hubble: %v", err)
|
||||
}
|
||||
client := observer.NewObserverClient(conn)
|
||||
req := &observer.GetFlowsRequest{
|
||||
Follow: true,
|
||||
}
|
||||
|
||||
stream, err := client.GetFlows(ctx, req)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Fatalf("Failed to get flow data: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
resp, err := stream.Recv()
|
||||
if err != nil {
|
||||
log.Printf("Stream closed or error occurred: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
flow := resp.GetFlow()
|
||||
if flow == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
flowEndpoint, ok := extractFlowEndpoints(flow)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := c.updateFlowRelationships(ctx, flowEndpoint); err != nil {
|
||||
log.Printf("Error updating flow relationships: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var prefixToResourceType = map[string]string{
|
||||
constants.DBLabelPrefix: constants.DatabaseType,
|
||||
constants.OSSLabelPrefix: constants.OSSType,
|
||||
constants.AppLabelPrefix: constants.AppType,
|
||||
constants.DevboxLabelPrefix: constants.DevboxType,
|
||||
}
|
||||
|
||||
var prefixes = make([]string, 0, len(prefixToResourceType))
|
||||
|
||||
func init() {
|
||||
for prefix := range prefixToResourceType {
|
||||
prefixes = append(prefixes, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
func extractNameFromLabels(labels []string) (name, resourceType string, found bool) {
|
||||
for _, label := range labels {
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(label, prefix) {
|
||||
return label[len(prefix):], prefixToResourceType[prefix], true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
func extractFlowEndpoints(flow *pb.Flow) (*FlowEndpoints, bool) {
|
||||
if flow.GetSource() == nil || flow.GetDestination() == nil {
|
||||
return nil, false
|
||||
}
|
||||
source := flow.GetSource()
|
||||
dest := flow.GetDestination()
|
||||
// Skip flows with missing namespace or pod information
|
||||
// This ensures we only process complete flow data
|
||||
if source.GetNamespace() == "" || source.GetPodName() == "" || dest.GetNamespace() == "" ||
|
||||
dest.GetPodName() == "" {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Filter flows to only include those with at least one user namespace
|
||||
// User namespaces are identified by the "ns-" prefix
|
||||
// This helps focus on user traffic and exclude system-to-system communications
|
||||
if !strings.HasPrefix(source.GetNamespace(), "ns-") &&
|
||||
!strings.HasPrefix(dest.GetNamespace(), "ns-") {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if source.GetNamespace() == "kube-dns" || dest.GetNamespace() == "kube-dns" {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
srcName, srcType, srcFound := extractNameFromLabels(source.GetLabels())
|
||||
if !srcFound {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
dstName, dstType, dstFound := extractNameFromLabels(dest.GetLabels())
|
||||
if !dstFound {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &FlowEndpoints{
|
||||
SourceNamespace: source.GetNamespace(),
|
||||
SourceName: srcName,
|
||||
SourceType: srcType,
|
||||
DestNamespace: dest.GetNamespace(),
|
||||
DestName: dstName,
|
||||
DestType: dstType,
|
||||
}, true
|
||||
}
|
||||
|
||||
func (c *Collector) updateFlowRelationships(
|
||||
ctx context.Context,
|
||||
flowEndpoint *FlowEndpoints,
|
||||
) error {
|
||||
srcKey := fmt.Sprintf(
|
||||
"%s/%s/%s",
|
||||
flowEndpoint.SourceNamespace,
|
||||
flowEndpoint.SourceType,
|
||||
flowEndpoint.SourceName,
|
||||
)
|
||||
dstKey := fmt.Sprintf(
|
||||
"%s/%s/%s",
|
||||
flowEndpoint.DestNamespace,
|
||||
flowEndpoint.DestType,
|
||||
flowEndpoint.DestName,
|
||||
)
|
||||
// Filter out self-loop traffic (when source and destination are identical)
|
||||
// This typically represents internal pod communications within the same CR
|
||||
if srcKey == dstKey {
|
||||
return nil
|
||||
}
|
||||
if err := c.dataStore.AddToSet(ctx, srcKey, dstKey); err != nil {
|
||||
return fmt.Errorf("failed to update source-to-destination set: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/credentials"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
const (
|
||||
HubbleClientCertSecretName = "hubble-relay-client-certs"
|
||||
HubbleServerCertSecretName = "hubble-relay-server-certs"
|
||||
HubbleSecretNamespace = "kube-system"
|
||||
HubbleTLSServerName = "hubble.hubble-relay.cilium.io"
|
||||
CACertKey = "ca.crt"
|
||||
ClientCertKey = "tls.crt"
|
||||
ClientKeyKey = "tls.key"
|
||||
)
|
||||
|
||||
// TLSConfig holds TLS configuration parameters
|
||||
type TLSConfig struct {
|
||||
ClientSecretName string
|
||||
ServerSecretName string
|
||||
SecretNamespace string
|
||||
ServerName string
|
||||
}
|
||||
|
||||
// NewDefaultTLSConfig creates a TLS config with default values
|
||||
func NewDefaultTLSConfig() *TLSConfig {
|
||||
return &TLSConfig{
|
||||
ClientSecretName: HubbleClientCertSecretName,
|
||||
ServerSecretName: HubbleServerCertSecretName,
|
||||
SecretNamespace: HubbleSecretNamespace,
|
||||
ServerName: HubbleTLSServerName,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadTLSCredentials loads TLS credentials from Kubernetes Secrets
|
||||
func LoadTLSCredentials(ctx context.Context, k8sClient kubernetes.Interface, tlsConfig *TLSConfig) (credentials.TransportCredentials, error) {
|
||||
clientSecret, err := k8sClient.CoreV1().Secrets(tlsConfig.SecretNamespace).Get(ctx, tlsConfig.ClientSecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get client secret %s/%s: %v", tlsConfig.SecretNamespace, tlsConfig.ClientSecretName, err)
|
||||
}
|
||||
|
||||
clientCertData, ok := clientSecret.Data[ClientCertKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s not found in client secret", ClientCertKey)
|
||||
}
|
||||
|
||||
clientKeyData, ok := clientSecret.Data[ClientKeyKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s not found in client secret", ClientKeyKey)
|
||||
}
|
||||
serverSecret, err := k8sClient.CoreV1().Secrets(tlsConfig.SecretNamespace).Get(ctx, tlsConfig.ServerSecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get server secret %s/%s: %v", tlsConfig.SecretNamespace, tlsConfig.ServerSecretName, err)
|
||||
}
|
||||
|
||||
caCertData, ok := serverSecret.Data[CACertKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s not found in server secret", CACertKey)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCertData) {
|
||||
return nil, fmt.Errorf("failed to append CA certificate")
|
||||
}
|
||||
clientCert, err := tls.X509KeyPair(clientCertData, clientKeyData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load client certificate: %v", err)
|
||||
}
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{clientCert},
|
||||
RootCAs: caCertPool,
|
||||
ServerName: tlsConfig.ServerName,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
return credentials.NewTLS(config), nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
auth:
|
||||
whiteList:
|
||||
http:
|
||||
addr: ":8080"
|
||||
hubble:
|
||||
addr: "hubble-relay.kube-system.svc.cluster.local:80"
|
||||
redis:
|
||||
addr:
|
||||
username: "default"
|
||||
password:
|
||||
db: 10
|
||||
@@ -0,0 +1,41 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/labring/sealos/service/hubble/pkg/config"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func LoadConfig(configPath string) (*config.Config, error) {
|
||||
cfg := &config.Config{
|
||||
Auth: config.AuthConfig{
|
||||
WhiteList: "",
|
||||
},
|
||||
HTTP: config.HTTPConfig{
|
||||
Port: ":8080",
|
||||
},
|
||||
Hubble: config.HubbleConfig{
|
||||
Addr: "localhost:4245",
|
||||
},
|
||||
Redis: config.RedisConfig{
|
||||
Addr: "localhost:6379",
|
||||
Username: "default",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
},
|
||||
}
|
||||
if configPath == "" {
|
||||
return nil, errors.New("config path is required")
|
||||
}
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config file: %w", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultExpiration = 90 * 24 * time.Hour
|
||||
)
|
||||
|
||||
type DataStore struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewDataStore(client *redis.Client) *DataStore {
|
||||
return &DataStore{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DataStore) Set(ctx context.Context, key, value string) error {
|
||||
return ds.client.Set(ctx, key, value, DefaultExpiration).Err()
|
||||
}
|
||||
|
||||
func (ds *DataStore) Get(ctx context.Context, key string) (string, bool, error) {
|
||||
val, err := ds.client.Get(ctx, key).Result()
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return "", false, nil
|
||||
} else if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
return val, true, nil
|
||||
}
|
||||
|
||||
func (ds *DataStore) EnsureSetExpiration(ctx context.Context, key string) error {
|
||||
ttl, err := ds.client.TTL(ctx, key).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If TTL returns -1, it means the key exists but has no expiration time
|
||||
// If TTL returns -2, it means the key does not exist
|
||||
if ttl == -1 {
|
||||
// Key exists but has no expiration time, set default expiration
|
||||
return ds.client.Expire(ctx, key, DefaultExpiration).Err()
|
||||
}
|
||||
|
||||
// Key does not exist or already has an expiration time, no action needed
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddToSet adds members to a Redis set and refreshes its expiration time.
|
||||
// Each time new data is added, the set's TTL is reset to DefaultExpiration,
|
||||
// ensuring the set remains available as long as it's actively being updated.
|
||||
func (ds *DataStore) AddToSet(ctx context.Context, key string, members ...any) error {
|
||||
pipe := ds.client.Pipeline()
|
||||
pipe.SAdd(ctx, key, members...)
|
||||
pipe.Expire(ctx, key, DefaultExpiration)
|
||||
_, err := pipe.Exec(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ds *DataStore) GetSetMembers(ctx context.Context, key string) ([]string, error) {
|
||||
members, err := ds.client.SMembers(ctx, key).Result()
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return []string{}, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM scratch
|
||||
COPY registry registry
|
||||
COPY manifests manifests
|
||||
|
||||
CMD ["kubectl apply -f manifests/deploy.yaml"]
|
||||
@@ -0,0 +1,16 @@
|
||||
### docker image build and deploy
|
||||
```bash
|
||||
make docker-build IMG=$(YourImageName)
|
||||
# edit deploy/manifests/deploy.yaml and deploy
|
||||
kubectl apply -f deploy/manifests/depoly.yaml
|
||||
```
|
||||
|
||||
### cluster image build and deploy
|
||||
```bash
|
||||
```
|
||||
|
||||
### Hubble Server
|
||||
|
||||
In order to prevent performance degradation or abnormal behavior caused by excessive data size in Prometheus, VictoriaMetrics is utilized for data collection.
|
||||
|
||||
> By default, we use kb-prometheus-server for the data collection service.
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
app: service-hubble
|
||||
name: service-hubble-config
|
||||
data:
|
||||
config.yml: |
|
||||
auth:
|
||||
whiteList: ""
|
||||
http:
|
||||
port: ":8080"
|
||||
hubble:
|
||||
addr: "hubble-relay.kube-system.svc.cluster.local:443"
|
||||
redis:
|
||||
addr: "<redis-placeholder>"
|
||||
username: "default"
|
||||
password: "<redis-password-placeholder>"
|
||||
db: 0
|
||||
@@ -0,0 +1,99 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: service-hubble-sa
|
||||
namespace: hubble-service
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: service-hubble-role
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get"]
|
||||
resourceNames: ["hubble-relay-client-certs", "hubble-relay-server-certs"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: service-hubble-rolebinding
|
||||
namespace: hubble-service
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: service-hubble-sa
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: service-hubble-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: service-hubble
|
||||
name: service-hubble-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: service-hubble
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: service-hubble
|
||||
spec:
|
||||
serviceAccountName: service-hubble-sa
|
||||
containers:
|
||||
- args:
|
||||
- --config=/config/config.yml
|
||||
command:
|
||||
- /manager
|
||||
image: ghcr.io/labring/sealos-hubble-service:latest
|
||||
imagePullPolicy: Always
|
||||
name: service-collector
|
||||
ports:
|
||||
- containerPort: 8428
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 640Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
runAsNonRoot: true
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /config
|
||||
name: config-vol
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
name: service-hubble-config
|
||||
name: config-vol
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: service-hubble
|
||||
name: service-hubble
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8428
|
||||
protocol: TCP
|
||||
targetPort: 8428
|
||||
selector:
|
||||
app: service-hubble
|
||||
@@ -0,0 +1,102 @@
|
||||
apiVersion: apps.kubeblocks.io/v1alpha1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
finalizers:
|
||||
- cluster.kubeblocks.io/finalizer
|
||||
labels:
|
||||
clusterdefinition.kubeblocks.io/name: redis
|
||||
clusterversion.kubeblocks.io/name: redis-7.0.6
|
||||
sealos-db-provider-cr: hubble-redis
|
||||
annotations: {}
|
||||
name: hubble
|
||||
spec:
|
||||
affinity:
|
||||
nodeLabels: {}
|
||||
podAntiAffinity: Preferred
|
||||
tenancy: SharedNode
|
||||
topologyKeys:
|
||||
- kubernetes.io/hostname
|
||||
clusterDefinitionRef: redis
|
||||
clusterVersionRef: redis-7.0.6
|
||||
componentSpecs:
|
||||
- componentDefRef: redis
|
||||
monitor: true
|
||||
name: redis
|
||||
replicas: 3
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1024Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 102Mi
|
||||
serviceAccountName: hubble-redis
|
||||
switchPolicy:
|
||||
type: Noop
|
||||
volumeClaimTemplates:
|
||||
- name: data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
storageClassName: openebs-backup
|
||||
- componentDefRef: redis-sentinel
|
||||
monitor: true
|
||||
name: redis-sentinel
|
||||
replicas: 3
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
serviceAccountName: hubble-redis
|
||||
terminationPolicy: Delete
|
||||
tolerations: []
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
sealos-db-provider-cr: hubble-redis
|
||||
app.kubernetes.io/instance: hubble-redis
|
||||
app.kubernetes.io/managed-by: kbcli
|
||||
name: hubble-redis
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
labels:
|
||||
sealos-db-provider-cr: hubble-redis
|
||||
app.kubernetes.io/instance: hubble-redis
|
||||
app.kubernetes.io/managed-by: kbcli
|
||||
name: hubble-redis
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
sealos-db-provider-cr: hubble-redis
|
||||
app.kubernetes.io/instance: hubble-redis
|
||||
app.kubernetes.io/managed-by: kbcli
|
||||
name: hubble-redis
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: hubble-redis
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: hubble-redis
|
||||
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
REDIS_NAMESPACE="hubble-service"
|
||||
APP_NAMESPACE="hubble-service"
|
||||
REDIS_SECRET_NAME="hubble-conn-credential"
|
||||
|
||||
# Create namespace
|
||||
kubectl create ns $APP_NAMESPACE || true
|
||||
|
||||
# Function to wait for secret
|
||||
wait_for_secret() {
|
||||
local secret_name=$1
|
||||
local namespace=$2
|
||||
local retries=0
|
||||
echo "Waiting for secret ${secret_name} in namespace ${namespace}..."
|
||||
while ! kubectl get secret -n ${namespace} ${secret_name} >/dev/null 2>&1; do
|
||||
sleep 3
|
||||
retries=$((retries + 1))
|
||||
if [ $retries -ge 30 ]; then
|
||||
echo "Timeout waiting for secret ${secret_name}"
|
||||
exit 1
|
||||
fi
|
||||
echo "Retry ${retries}/30..."
|
||||
done
|
||||
echo "✓ Secret ${secret_name} found"
|
||||
}
|
||||
|
||||
# Function to get secret value
|
||||
get_secret_value() {
|
||||
local secret_name=$1
|
||||
local key=$2
|
||||
local namespace=$3
|
||||
|
||||
base64_value=$(kubectl get secret -n ${namespace} ${secret_name} -o jsonpath="{.data.${key}}") || return $?
|
||||
echo "$base64_value" | base64 -d
|
||||
}
|
||||
|
||||
# Function to build redis connection components
|
||||
build_redis_config() {
|
||||
local secret_name=$1
|
||||
local namespace=$2
|
||||
|
||||
echo "Getting Redis connection details from secret ${secret_name}..."
|
||||
|
||||
username=$(get_secret_value ${secret_name} "username" ${namespace}) || {
|
||||
echo "Failed to get Redis username"
|
||||
return 1
|
||||
}
|
||||
|
||||
password=$(get_secret_value ${secret_name} "password" ${namespace}) || {
|
||||
echo "Failed to get Redis password"
|
||||
return 1
|
||||
}
|
||||
|
||||
host=$(get_secret_value ${secret_name} "host" ${namespace}) || {
|
||||
echo "Failed to get Redis host"
|
||||
return 1
|
||||
}
|
||||
|
||||
port=$(get_secret_value ${secret_name} "port" ${namespace}) || {
|
||||
echo "Failed to get Redis port"
|
||||
return 1
|
||||
}
|
||||
|
||||
redis_addr="${host}:${port}"
|
||||
|
||||
echo "Updating Redis configuration..."
|
||||
sed -i "s|<redis-placeholder>|${redis_addr}|g" manifests/configmap.yaml
|
||||
sed -i "s|<redis-password-placeholder>|${password}|g" manifests/configmap.yaml
|
||||
|
||||
echo "✓ Redis config updated: ${redis_addr}"
|
||||
}
|
||||
|
||||
# Function to update API server whitelist
|
||||
update_whitelist() {
|
||||
echo "Getting API Server address..."
|
||||
|
||||
API_SERVER_HOST=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') || {
|
||||
echo "Failed to get API server host"
|
||||
return 1
|
||||
}
|
||||
|
||||
API_SERVER_PORT=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') || {
|
||||
echo "Failed to get API server port"
|
||||
return 1
|
||||
}
|
||||
|
||||
API_SERVER_ADDR="${API_SERVER_HOST}:${API_SERVER_PORT}"
|
||||
|
||||
echo "Updating whitelist with API Server address..."
|
||||
sed -i "s|whiteList: \"\"|whiteList: \"${API_SERVER_ADDR}\"|g" manifests/configmap.yaml
|
||||
|
||||
echo "✓ Whitelist updated: ${API_SERVER_ADDR}"
|
||||
}
|
||||
echo "Creating namespaces..."
|
||||
kubectl create ns ${APP_NAMESPACE} || true
|
||||
|
||||
echo "Deploying Redis..."
|
||||
kubectl apply -f manifests/redis.yaml -n ${REDIS_NAMESPACE}
|
||||
|
||||
echo "Waiting for Redis credentials..."
|
||||
wait_for_secret ${REDIS_SECRET_NAME} ${REDIS_NAMESPACE}
|
||||
|
||||
echo "Updating Redis config..."
|
||||
build_redis_config ${REDIS_SECRET_NAME} ${REDIS_NAMESPACE}
|
||||
|
||||
echo "Updating API server whitelist..."
|
||||
update_whitelist
|
||||
|
||||
echo "Deploying Hubble application..."
|
||||
kubectl apply -f manifests/configmap.yaml -n ${APP_NAMESPACE}
|
||||
kubectl apply -f manifests/deploy.yaml -n ${APP_NAMESPACE}
|
||||
echo "✓ Deployment completed successfully!"
|
||||
@@ -0,0 +1,77 @@
|
||||
module github.com/labring/sealos/service/hubble
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/cilium/cilium v1.17.6
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
google.golang.org/grpc v1.73.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.32.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
k8s.io/client-go v0.32.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/oauth2 v0.28.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,143 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
authorizationapi "k8s.io/api/authorization/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
whiteListHosts []string
|
||||
}
|
||||
|
||||
func NewAuth(whiteList string) *Auth {
|
||||
whiteListHosts := strings.Split(whiteList, ",")
|
||||
return &Auth{
|
||||
whiteListHosts: whiteListHosts,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Auth) isWhitelistedHost(host string) bool {
|
||||
for _, h := range a.whiteListHosts {
|
||||
if h != "" && h == host {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func extractNamespaceFromKubeConfig(kubeConfigData string) (string, error) {
|
||||
config, err := clientcmd.Load([]byte(kubeConfigData))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to load kubeconfig: %w", err)
|
||||
}
|
||||
|
||||
currentContext := config.CurrentContext
|
||||
if currentContext == "" {
|
||||
return "", errors.New("no current-context found in kubeconfig")
|
||||
}
|
||||
|
||||
context, exists := config.Contexts[currentContext]
|
||||
if !exists {
|
||||
return "", fmt.Errorf("current-context '%s' not found in kubeconfig", currentContext)
|
||||
}
|
||||
|
||||
namespace := context.Namespace
|
||||
if namespace == "" {
|
||||
return "", errors.New("no namespace found in kubeconfig")
|
||||
}
|
||||
|
||||
return namespace, nil
|
||||
}
|
||||
|
||||
func (a *Auth) Authenticate(ctx context.Context, ns, kc string) (string, error) {
|
||||
if ns == "" {
|
||||
var err error
|
||||
ns, err = extractNamespaceFromKubeConfig(kc)
|
||||
if err != nil {
|
||||
return "", ErrNoNamespace
|
||||
}
|
||||
}
|
||||
|
||||
config, err := clientcmd.RESTConfigFromKubeConfig([]byte(kc))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("kubeconfig failed: %w", err)
|
||||
}
|
||||
|
||||
if !a.isWhitelistedHost(config.Host) {
|
||||
if k8shost := getKubernetesHostFromEnv(); k8shost != "" {
|
||||
config.Host = k8shost
|
||||
} else {
|
||||
log.Printf("k8s host not found (%s)\n", config.Host)
|
||||
return "", ErrNoSealosHost
|
||||
}
|
||||
}
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create discovery client: %w", err)
|
||||
}
|
||||
res, err := discoveryClient.RESTClient().Get().AbsPath("/readyz").DoRaw(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("API server health check failed: %w", err)
|
||||
}
|
||||
if string(res) != "ok" {
|
||||
return "", fmt.Errorf("API server not ready: %s", string(res))
|
||||
}
|
||||
if err := checkResourceAccess(ctx, client, ns, "get", "pods"); err != nil {
|
||||
return "", fmt.Errorf("resource access check failed: %w", err)
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func getKubernetesHostFromEnv() string {
|
||||
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||
if len(host) == 0 || len(port) == 0 {
|
||||
return ""
|
||||
}
|
||||
return "https://" + net.JoinHostPort(host, port)
|
||||
}
|
||||
|
||||
func checkResourceAccess(
|
||||
ctx context.Context,
|
||||
client *kubernetes.Clientset,
|
||||
namespace, verb, resource string,
|
||||
) error {
|
||||
review := &authorizationapi.SelfSubjectAccessReview{
|
||||
Spec: authorizationapi.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
Namespace: namespace,
|
||||
Verb: verb,
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: resource,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.AuthorizationV1().
|
||||
SelfSubjectAccessReviews().
|
||||
Create(ctx, review, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Status.Allowed {
|
||||
return ErrNoAuth
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/labring/sealos/service/hubble/pkg/cache"
|
||||
)
|
||||
|
||||
type CacheAuth struct {
|
||||
auth *Auth
|
||||
cache cache.Cache
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
cacheEntryTTL = 5 * time.Minute
|
||||
cleanupInterval = 10 * time.Minute
|
||||
)
|
||||
|
||||
func NewCacheAuth(whiteList string) *CacheAuth {
|
||||
return &CacheAuth{
|
||||
auth: NewAuth(whiteList),
|
||||
cache: cache.NewMemoryCache(cleanupInterval),
|
||||
ttl: cacheEntryTTL,
|
||||
}
|
||||
}
|
||||
|
||||
func getCacheKey(namespace, kubeconfig string) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(kubeconfig))
|
||||
return fmt.Sprintf("auth:%s:%x", namespace, h.Sum(nil))
|
||||
}
|
||||
|
||||
func (ca *CacheAuth) Authenticate(ctx context.Context, ns, kc string) (string, error) {
|
||||
var err error
|
||||
if ns == "" {
|
||||
ns, err = extractNamespaceFromKubeConfig(kc)
|
||||
if err != nil {
|
||||
return "", ErrNoNamespace
|
||||
}
|
||||
}
|
||||
|
||||
cacheKey := getCacheKey(ns, kc)
|
||||
if cachedValue, found := ca.cache.Get(cacheKey); found {
|
||||
if cachedErr, ok := cachedValue.(error); ok {
|
||||
return "", cachedErr
|
||||
}
|
||||
|
||||
if cachedBool, ok := cachedValue.(bool); ok && cachedBool {
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
return ns, ErrNoAuth
|
||||
}
|
||||
ns, err = ca.auth.Authenticate(ctx, ns, kc)
|
||||
if err == nil {
|
||||
ca.cache.Set(cacheKey, true, ca.ttl)
|
||||
} else {
|
||||
ca.cache.Set(cacheKey, err, ca.ttl)
|
||||
}
|
||||
return ns, err
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoAuth = errors.New("no permission for this namespace")
|
||||
ErrNoSealosHost = errors.New("unable to get the sealos host")
|
||||
ErrNoNamespace = errors.New("no namespace specified or found in kubeconfig")
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Authenticator interface {
|
||||
Authenticate(ctx context.Context, namespace, kc string) (string, error)
|
||||
}
|
||||
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MemoryCache struct {
|
||||
data map[string]cacheItem
|
||||
mutex sync.RWMutex
|
||||
cleanupInterval time.Duration
|
||||
stopCleanup chan struct{}
|
||||
}
|
||||
|
||||
type cacheItem struct {
|
||||
value any
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
func NewMemoryCache(cleanupInterval time.Duration) *MemoryCache {
|
||||
cache := &MemoryCache{
|
||||
data: make(map[string]cacheItem),
|
||||
cleanupInterval: cleanupInterval,
|
||||
stopCleanup: make(chan struct{}),
|
||||
}
|
||||
|
||||
go cache.startCleanupTimer()
|
||||
return cache
|
||||
}
|
||||
|
||||
func (c *MemoryCache) startCleanupTimer() {
|
||||
ticker := time.NewTicker(c.cleanupInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
c.cleanup()
|
||||
case <-c.stopCleanup:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MemoryCache) cleanup() {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for key, item := range c.data {
|
||||
if item.expiry.Before(now) {
|
||||
delete(c.data, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Get(key string) (any, bool) {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
|
||||
item, found := c.data[key]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if time.Now().After(item.expiry) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return item.value, true
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Set(key string, value any, ttl time.Duration) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
c.data[key] = cacheItem{
|
||||
value: value,
|
||||
expiry: time.Now().Add(ttl),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Delete(key string) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
delete(c.data, key)
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Clear() {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
c.data = make(map[string]cacheItem)
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cache interface {
|
||||
Get(key string) (any, bool)
|
||||
Set(key string, value any, ttl time.Duration)
|
||||
Delete(key string)
|
||||
Clear()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package config
|
||||
|
||||
type AuthConfig struct {
|
||||
WhiteList string `yaml:"whiteList"`
|
||||
}
|
||||
|
||||
type HTTPConfig struct {
|
||||
Port string `yaml:"port"`
|
||||
}
|
||||
|
||||
type HubbleConfig struct {
|
||||
Addr string `yaml:"addr"`
|
||||
}
|
||||
|
||||
type RedisConfig struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
DB int `yaml:"db"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Auth AuthConfig `yaml:"auth"`
|
||||
HTTP HTTPConfig `yaml:"http"`
|
||||
Hubble HubbleConfig `yaml:"hubble"`
|
||||
Redis RedisConfig `yaml:"redis"`
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
APIBasePath = "/api/v1"
|
||||
FlowsPath = "/traffic"
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
KubeConfig = "Authorization"
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
DevboxLabelPrefix = "k8s:app.kubernetes.io/name="
|
||||
OSSLabelPrefix = "k8s:io.cilium.k8s.namespace.labels.app.kubernetes.io/created-by="
|
||||
DBLabelPrefix = "k8s:app.kubernetes.io/instance="
|
||||
AppLabelPrefix = "k8s:app="
|
||||
// TODO: AI PROXY Label
|
||||
)
|
||||
|
||||
const (
|
||||
DevboxType = "devbox"
|
||||
OSSType = "oss"
|
||||
DatabaseType = "database"
|
||||
AppType = "app"
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
MissingKCMsg = "kubernetes context (kc) parameter not provided"
|
||||
DecodingKCFailedMsg = "Failed to decode kubeconfig"
|
||||
GetFlowsSuccessMsg = "get flows success"
|
||||
InvalidRequestMsg = "invalid request parameters: %v"
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// FlowSetKeyPattern represents the format for flow set keys: "namespace/resourceType/name"
|
||||
FlowSetKeyPattern = "%s/%s/%s"
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package models
|
||||
|
||||
type TrafficRequest struct {
|
||||
Resources []Resource `json:"resources" binding:"required"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Type string `json:"type" binding:"required"`
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
type TrafficResponse struct {
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
type TrafficData struct {
|
||||
Resource Resource `json:"resource"`
|
||||
Flows []string `json:"flows"`
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/labring/sealos/service/hubble/datastore"
|
||||
"github.com/labring/sealos/service/hubble/pkg/auth"
|
||||
"github.com/labring/sealos/service/hubble/pkg/constants"
|
||||
"github.com/labring/sealos/service/hubble/pkg/models"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Router *gin.Engine
|
||||
auth auth.Authenticator
|
||||
dataStore *datastore.DataStore
|
||||
}
|
||||
|
||||
func NewServer(dataStore *datastore.DataStore, whiteList string) *Server {
|
||||
server := &Server{
|
||||
Router: gin.Default(),
|
||||
dataStore: dataStore,
|
||||
auth: auth.NewCacheAuth(whiteList),
|
||||
}
|
||||
server.setupRoutes()
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *Server) setupRoutes() {
|
||||
api := s.Router.Group(constants.APIBasePath)
|
||||
{
|
||||
api.POST(constants.FlowsPath, s.flowsHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) flowsHandler(c *gin.Context) {
|
||||
kc := c.GetHeader(constants.KubeConfig)
|
||||
if kc == "" {
|
||||
c.JSON(http.StatusBadRequest, models.TrafficResponse{
|
||||
Message: constants.MissingKCMsg,
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
kubeConfig, err := url.QueryUnescape(kc)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, models.TrafficResponse{
|
||||
Message: constants.DecodingKCFailedMsg,
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
ns, err := s.auth.Authenticate(context.Background(), "", kubeConfig)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, models.TrafficResponse{
|
||||
Message: err.Error(),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req models.TrafficRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, models.TrafficResponse{
|
||||
Message: fmt.Sprintf(constants.InvalidRequestMsg, err.Error()),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
res := make([]models.TrafficData, 0, len(req.Resources))
|
||||
for _, resource := range req.Resources {
|
||||
flows, err := s.collectFlowData(ns, resource)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.TrafficResponse{
|
||||
Message: err.Error(),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
res = append(res, models.TrafficData{Resource: resource, Flows: flows})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, models.TrafficResponse{
|
||||
Message: constants.GetFlowsSuccessMsg,
|
||||
Data: res,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) collectFlowData(namespace string, resource models.Resource) ([]string, error) {
|
||||
flowKey := fmt.Sprintf(constants.FlowSetKeyPattern, namespace, resource.Type, resource.Name)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
flows, err := s.dataStore.GetSetMembers(ctx, flowKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get outbound flows: %w", err)
|
||||
}
|
||||
return flows, nil
|
||||
}
|
||||
Reference in New Issue
Block a user