mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
zero: resource bundle reconciler
This commit is contained in:
parent
0affd9268b
commit
48c248657d
13 changed files with 1246 additions and 30 deletions
41
go.mod
41
go.mod
|
@ -19,7 +19,7 @@ require (
|
|||
github.com/client9/misspell v0.3.4
|
||||
github.com/cloudflare/circl v1.3.3
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/docker/docker v24.0.2+incompatible
|
||||
github.com/docker/docker v24.0.4+incompatible
|
||||
github.com/envoyproxy/go-control-plane v0.11.1
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
|
@ -52,6 +52,7 @@ require (
|
|||
github.com/pomerium/csrf v1.7.0
|
||||
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524
|
||||
github.com/pomerium/webauthn v0.0.0-20221118023040-00a9c430578b
|
||||
github.com/pomerium/zero-sdk v0.0.0-20230808010614-1d63e8b3e1e9
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
github.com/prometheus/common v0.44.0
|
||||
|
@ -67,10 +68,11 @@ require (
|
|||
go.opencensus.io v0.24.0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.11.0
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
|
||||
golang.org/x/net v0.12.0
|
||||
golang.org/x/oauth2 v0.10.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/api v0.134.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230720185612-659f7aaaa771
|
||||
google.golang.org/grpc v1.57.0
|
||||
|
@ -85,13 +87,14 @@ require (
|
|||
cloud.google.com/go/compute v1.20.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/DataDog/datadog-go v3.5.0+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 // indirect
|
||||
|
@ -107,27 +110,38 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 // indirect
|
||||
github.com/aws/smithy-go v1.14.0 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
|
||||
github.com/containerd/continuity v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.13.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/docker/cli v20.10.21+incompatible // indirect
|
||||
github.com/docker/cli v24.0.4+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // 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.14.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
|
@ -146,21 +160,23 @@ require (
|
|||
github.com/jackc/puddle/v2 v2.2.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/labstack/echo/v4 v4.11.1 // indirect
|
||||
github.com/labstack/gommon v0.4.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lib/pq v1.10.7 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lyft/protoc-gen-star/v2 v2.0.3 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/onsi/gomega v1.26.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
|
||||
|
@ -185,7 +201,11 @@ require (
|
|||
github.com/tinylib/msgp v1.1.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
|
@ -200,11 +220,12 @@ require (
|
|||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/tools v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||
|
|
98
go.sum
98
go.sum
|
@ -52,8 +52,8 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9
|
|||
contrib.go.opencensus.io/exporter/zipkin v0.1.2 h1:YqE293IZrKtqPnpwDPH/lOqTWD/s3Iwabycam74JV3g=
|
||||
contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CAFxX/httpcompression v0.0.8 h1:UBWojERnpCS6X7whJkGGZeCC3ruZBRwkwkcnfGfb0ko=
|
||||
|
@ -69,6 +69,7 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
|
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
|
@ -83,9 +84,12 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -125,12 +129,17 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 h1:pAOJj+80tC8sPVgSDHzMYD6KLWsa
|
|||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI=
|
||||
github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io=
|
||||
github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/caddyserver/certmagic v0.19.1 h1:4jyOYm2DHvQI8YM0sk6qm62Gl5XznHxiMBMWjMTlQkw=
|
||||
github.com/caddyserver/certmagic v0.19.1/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
|
@ -145,6 +154,9 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -183,6 +195,8 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepmap/oapi-codegen v1.13.2 h1:I/REY+90rmcheXdR5rCg9j+7wAI134UwBk44AYt5QAY=
|
||||
github.com/deepmap/oapi-codegen v1.13.2/go.mod h1:eXAuxgJu9XC+dZECAw9cF4qtmL0qwGy0ZAvV6A2j1oA=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
|
@ -191,12 +205,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU=
|
||||
github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v24.0.4+incompatible h1:Y3bYF9ekNTm2VFz5U/0BlMdJy73D+Y1iAAZ8l63Ydzw=
|
||||
github.com/docker/cli v24.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg=
|
||||
github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI=
|
||||
github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
|
@ -230,8 +244,14 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
|
|||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
|
||||
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -259,6 +279,13 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
|
@ -266,6 +293,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
|
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
|
@ -428,6 +457,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
|
@ -437,6 +467,7 @@ github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
|
|||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
|
@ -451,6 +482,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
|
||||
github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
|
||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||
|
@ -465,13 +502,14 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
|
|||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/martinlindhe/base36 v1.1.1 h1:1F1MZ5MGghBXDZ2KJ3QfxmiydlWOGB8HCEtkap5NkVg=
|
||||
github.com/martinlindhe/base36 v1.1.1/go.mod h1:vMS8PaZ5e/jV9LwFKlm0YLnXl/hpOihiBxKkIoc3g08=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
|
@ -492,8 +530,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
|||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
||||
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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -502,7 +540,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
|
@ -556,6 +593,8 @@ github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524 h1:3YQY1sb5
|
|||
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524/go.mod h1:7fGbUYJnU8RcxZJvUvhukOIBv1G7LWDAHMfDxAf5+Y0=
|
||||
github.com/pomerium/webauthn v0.0.0-20221118023040-00a9c430578b h1:oll/aOfJudnqFAwCvoXK9+WN2zVjTzHVPLXCggHQmHk=
|
||||
github.com/pomerium/webauthn v0.0.0-20221118023040-00a9c430578b/go.mod h1:KswTenBBh4y1pmhU2dpm8VgJQCgSErCg7OOFTeebrNc=
|
||||
github.com/pomerium/zero-sdk v0.0.0-20230808010614-1d63e8b3e1e9 h1:eYIwJ8uVa22cmanDP0pTLEY9hHIw3180w+HUeaz8KLk=
|
||||
github.com/pomerium/zero-sdk v0.0.0-20230808010614-1d63e8b3e1e9/go.mod h1:cAyfEGM8blUzchYhOWrufuj/6lOF277meB4c/TjMS28=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
|
@ -602,7 +641,7 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn
|
|||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
|
||||
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
|
@ -647,6 +686,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
|||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
|
||||
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -662,6 +702,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
|
@ -680,11 +721,20 @@ github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ
|
|||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f h1:C43EMGXFtvYf/zunHR6ivZV7Z6ytg73t0GXwYyicXMQ=
|
||||
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f/go.mod h1:N+sR0vLSCTtI6o06PMWsjMB4TVqqDttKNq4iC9wvxVY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U=
|
||||
github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/gozstd v1.11.0 h1:VV6qQFt+4sBBj9OJ7eKVvsFAMy59Urcs9Lgd+o5FOw0=
|
||||
github.com/valyala/gozstd v1.11.0/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9zoYiIPQ=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
|
@ -755,6 +805,9 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -779,8 +832,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -808,8 +861,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -942,6 +995,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -954,6 +1008,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -973,6 +1028,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -1025,8 +1081,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
|
||||
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -1172,6 +1228,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -1186,6 +1243,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
|||
namespacelabs.dev/go-filenotify v0.0.0-20220511192020-53ea11be7eaa h1:jj2kjs0Hvufj40wuhMAzoZUOwrwMDFg1gHZ49RiIv9w=
|
||||
namespacelabs.dev/go-filenotify v0.0.0-20220511192020-53ea11be7eaa/go.mod h1:e8NJRaInXRRm1+KPA6EkGEzdLJAgEvVSIKiLzpP97nI=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
|
|
134
internal/zero/reconciler/bundles.go
Normal file
134
internal/zero/reconciler/bundles.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package reconciler
|
||||
|
||||
/*
|
||||
* Bundle is a representation of a bundle resource
|
||||
*
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type bundle struct {
|
||||
id string
|
||||
synced bool
|
||||
}
|
||||
|
||||
// Bundles is a list of bundles to sync
|
||||
type Bundles struct {
|
||||
sync.Mutex
|
||||
bundles []bundle
|
||||
}
|
||||
|
||||
// Set sets the list of bundles to sync.
|
||||
// bundles would be synced in the order they are provided.
|
||||
func (b *Bundles) Set(bundles []string) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
b.bundles = make([]bundle, len(bundles))
|
||||
for i, id := range bundles {
|
||||
b.bundles[i] = bundle{id: id, synced: false}
|
||||
}
|
||||
}
|
||||
|
||||
// MarkForSync marks the bundle with the given ID for synchronization
|
||||
// if bundle does not exist, it is added to the end of the list as we do not know its relative priority.
|
||||
// we will have just a handful of bundles, so it is not a big deal to scan the list on each (infrequent) update.
|
||||
func (b *Bundles) MarkForSync(id string) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
for i := range b.bundles {
|
||||
if b.bundles[i].id == id {
|
||||
b.bundles[i].synced = false
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
b.bundles = append(b.bundles, bundle{id: id, synced: false})
|
||||
}
|
||||
|
||||
// GetNextBundleToSync returns the next bundle to sync.
|
||||
// If there is no bundle to sync, it returns false.
|
||||
func (b *Bundles) GetNextBundleToSync() (string, bool) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
for i, bundle := range b.bundles {
|
||||
if !bundle.synced {
|
||||
b.bundles[i].synced = true
|
||||
return bundle.id, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// GetBundles returns the list of bundles that have to be present in the cluster.
|
||||
func (c *service) RefreshBundleList(ctx context.Context) error {
|
||||
resp, err := c.config.clusterAPI.GetClusterResourceBundlesWithResponse(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get bundles: %w", err)
|
||||
}
|
||||
if resp.JSON200 == nil {
|
||||
return fmt.Errorf("get bundles: unexpected response: %d/%s", resp.StatusCode(), resp.Status())
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(resp.JSON200.Bundles))
|
||||
for _, v := range resp.JSON200.Bundles {
|
||||
ids = append(ids, v.Id)
|
||||
}
|
||||
|
||||
c.bundles.Set(ids)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBundleDownloadURL returns the up to date download URL for the given bundle.
|
||||
func (c *service) GetBundleDownloadURL(ctx context.Context, key string) (*url.URL, error) {
|
||||
entry, ok := c.downloadURLCache[key]
|
||||
if ok && entry.ExpiresAt.After(time.Now().Add(c.config.minDownloadTTL)) {
|
||||
return &entry.URL, nil
|
||||
}
|
||||
|
||||
delete(c.downloadURLCache, key)
|
||||
|
||||
p, err := c.getBundleDownloadURLFromAPI(ctx, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get bundle download url (from api): %w", err)
|
||||
}
|
||||
|
||||
c.downloadURLCache[key] = *p
|
||||
return &p.URL, nil
|
||||
}
|
||||
|
||||
func (c *service) getBundleDownloadURLFromAPI(ctx context.Context, key string) (*urlEntry, error) {
|
||||
now := time.Now()
|
||||
|
||||
resp, err := c.config.clusterAPI.DownloadClusterResourceBundleWithResponse(ctx, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("api: %w", err)
|
||||
}
|
||||
if resp.JSON200 == nil {
|
||||
return nil, fmt.Errorf("unexpected api response: %d/%s", resp.StatusCode(), resp.Status())
|
||||
}
|
||||
|
||||
expiresSeconds, err := strconv.ParseInt(resp.JSON200.ExpiresInSeconds, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse expiration: %w", err)
|
||||
}
|
||||
|
||||
u, err := url.Parse(resp.JSON200.Url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse url: %w", err)
|
||||
}
|
||||
|
||||
return &urlEntry{
|
||||
URL: *u,
|
||||
ExpiresAt: now.Add(time.Duration(expiresSeconds) * time.Second),
|
||||
}, nil
|
||||
}
|
43
internal/zero/reconciler/bundles_format.go
Normal file
43
internal/zero/reconciler/bundles_format.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package reconciler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protodelim"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
)
|
||||
|
||||
var unmarshalOpts = protodelim.UnmarshalOptions{}
|
||||
|
||||
// ReadBundleRecords reads records in a protobuf wire format from src.
|
||||
// Each record is expected to be a databroker.Record.
|
||||
func ReadBundleRecords(src io.Reader) (RecordSetBundle[DatabrokerRecord], error) {
|
||||
// start reading
|
||||
|
||||
r := bufio.NewReader(src)
|
||||
rsb := make(RecordSetBundle[DatabrokerRecord])
|
||||
for {
|
||||
record := new(databroker.Record)
|
||||
err := unmarshalOpts.UnmarshalFrom(r, record)
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading protobuf record: %w", err)
|
||||
}
|
||||
|
||||
data, err := protojson.Marshal(record)
|
||||
if err == nil {
|
||||
fmt.Printf("record: %s\n", string(data))
|
||||
}
|
||||
|
||||
rsb.Add(DatabrokerRecord{record})
|
||||
}
|
||||
|
||||
return rsb, nil
|
||||
}
|
64
internal/zero/reconciler/bundles_format_test.go
Normal file
64
internal/zero/reconciler/bundles_format_test.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package reconciler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/encoding/protodelim"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/pomerium/pomerium/pkg/grpc/config"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/pomerium/pkg/protoutil"
|
||||
)
|
||||
|
||||
func TestReadRecords(t *testing.T) {
|
||||
|
||||
dir := t.TempDir()
|
||||
fd, err := os.CreateTemp(dir, "config")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { _ = fd.Close() })
|
||||
|
||||
err = writeSampleRecords(fd)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = fd.Seek(0, io.SeekStart)
|
||||
require.NoError(t, err)
|
||||
|
||||
records, err := ReadBundleRecords(fd)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, records, 1)
|
||||
}
|
||||
|
||||
func writeSampleRecords(dst io.Writer) error {
|
||||
var marshalOpts = protodelim.MarshalOptions{
|
||||
MarshalOptions: proto.MarshalOptions{
|
||||
AllowPartial: false,
|
||||
Deterministic: true,
|
||||
UseCachedSize: false,
|
||||
},
|
||||
}
|
||||
|
||||
cfg := protoutil.NewAny(&config.Config{
|
||||
Routes: []*config.Route{
|
||||
{
|
||||
From: "https://from.example.com",
|
||||
To: []string{"https://to.example.com"},
|
||||
},
|
||||
},
|
||||
})
|
||||
rec := &databroker.Record{
|
||||
Id: "config",
|
||||
Type: cfg.GetTypeUrl(),
|
||||
Data: cfg,
|
||||
}
|
||||
_, err := marshalOpts.MarshalTo(dst, rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
120
internal/zero/reconciler/config.go
Normal file
120
internal/zero/reconciler/config.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Package reconciler syncs the state of resource bundles between the cloud and the databroker.
|
||||
package reconciler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/zero-sdk/cluster"
|
||||
connect_mux "github.com/pomerium/zero-sdk/connect-mux"
|
||||
)
|
||||
|
||||
// reconcilerConfig contains the configuration for the resource bundles reconciler.
|
||||
type reconcilerConfig struct {
|
||||
clusterAPI cluster.ClientWithResponsesInterface
|
||||
connectMux *connect_mux.Mux
|
||||
|
||||
databrokerClient databroker.DataBrokerServiceClient
|
||||
databrokerRPS int
|
||||
|
||||
tmpDir string
|
||||
|
||||
minDownloadTTL time.Duration
|
||||
|
||||
httpClient *http.Client
|
||||
|
||||
checkForUpdateIntervalWhenDisconnected time.Duration
|
||||
checkForUpdateIntervalWhenConnected time.Duration
|
||||
}
|
||||
|
||||
// Option configures the resource bundles reconciler
|
||||
type Option func(*reconcilerConfig)
|
||||
|
||||
// WithTemporaryDirectory configures the resource bundles client to use a temporary directory for
|
||||
// downloading files.
|
||||
func WithTemporaryDirectory(path string) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.tmpDir = path
|
||||
}
|
||||
}
|
||||
|
||||
// WithClusterAPIClient configures the cluster api client.
|
||||
func WithClusterAPIClient(client cluster.ClientWithResponsesInterface) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.clusterAPI = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithConnectMux configures the connect mux.
|
||||
func WithConnectMux(client *connect_mux.Mux) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.connectMux = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithDataBrokerClient configures the databroker client.
|
||||
func WithDataBrokerClient(client databroker.DataBrokerServiceClient) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.databrokerClient = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithMinDownloadTTL configures the download URL validity in cache,
|
||||
// before it would be requested again from the cloud (that also sets it's own TTL to the signed URL).
|
||||
func WithMinDownloadTTL(ttl time.Duration) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.minDownloadTTL = ttl
|
||||
}
|
||||
}
|
||||
|
||||
// WithDownloadHTTPClient configures the http client used for downloading files.
|
||||
func WithDownloadHTTPClient(client *http.Client) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.httpClient = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithDatabrokerRPSLimit configures the maximum number of requests per second to the databroker.
|
||||
func WithDatabrokerRPSLimit(rps int) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.databrokerRPS = rps
|
||||
}
|
||||
}
|
||||
|
||||
// WithCheckForUpdateIntervalWhenDisconnected configures the interval at which the reconciler will check
|
||||
// for updates when disconnected from the cloud.
|
||||
func WithCheckForUpdateIntervalWhenDisconnected(interval time.Duration) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.checkForUpdateIntervalWhenDisconnected = interval
|
||||
}
|
||||
}
|
||||
|
||||
// WithCheckForUpdateIntervalWhenConnected configures the interval at which the reconciler will check
|
||||
// for updates when connected to the cloud.
|
||||
func WithCheckForUpdateIntervalWhenConnected(interval time.Duration) Option {
|
||||
return func(cfg *reconcilerConfig) {
|
||||
cfg.checkForUpdateIntervalWhenConnected = interval
|
||||
}
|
||||
}
|
||||
|
||||
func newConfig(opts ...Option) *reconcilerConfig {
|
||||
cfg := &reconcilerConfig{}
|
||||
for _, opt := range []Option{
|
||||
WithTemporaryDirectory(os.TempDir()),
|
||||
WithMinDownloadTTL(5 * time.Minute),
|
||||
WithDownloadHTTPClient(http.DefaultClient),
|
||||
WithDatabrokerRPSLimit(1_000),
|
||||
WithCheckForUpdateIntervalWhenDisconnected(time.Minute * 5),
|
||||
WithCheckForUpdateIntervalWhenConnected(time.Hour),
|
||||
} {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
137
internal/zero/reconciler/databroker.go
Normal file
137
internal/zero/reconciler/databroker.go
Normal file
|
@ -0,0 +1,137 @@
|
|||
package reconciler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
)
|
||||
|
||||
// DatabrokerRecord is a wrapper around a databroker record.
|
||||
type DatabrokerRecord struct {
|
||||
V *databroker.Record
|
||||
}
|
||||
|
||||
var _ Record[DatabrokerRecord] = DatabrokerRecord{}
|
||||
|
||||
// GetID returns the databroker record's ID.
|
||||
func (r DatabrokerRecord) GetID() string {
|
||||
return r.V.GetId()
|
||||
}
|
||||
|
||||
// GetType returns the databroker record's type.
|
||||
func (r DatabrokerRecord) GetType() string {
|
||||
return r.V.GetType()
|
||||
}
|
||||
|
||||
// Equal returns true if the databroker records are equal.
|
||||
func (r DatabrokerRecord) Equal(other DatabrokerRecord) bool {
|
||||
return r.V.Type == other.V.Type &&
|
||||
r.V.Id == other.V.Id &&
|
||||
proto.Equal(r.V.Data, other.V.Data)
|
||||
}
|
||||
|
||||
// GetDataBrokerRecords gets all databroker records of the given types.
|
||||
func (c *service) GetDatabrokerRecords(
|
||||
ctx context.Context,
|
||||
types []string,
|
||||
) (RecordSetBundle[DatabrokerRecord], error) {
|
||||
rsb := make(RecordSetBundle[DatabrokerRecord])
|
||||
|
||||
for _, typ := range types {
|
||||
recs, err := c.getDatabrokerRecords(ctx, typ)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get databroker records for type %s: %w", typ, err)
|
||||
}
|
||||
rsb[typ] = recs
|
||||
}
|
||||
|
||||
return rsb, nil
|
||||
}
|
||||
|
||||
func (c *service) getDatabrokerRecords(ctx context.Context, typ string) (RecordSet[DatabrokerRecord], error) {
|
||||
stream, err := c.config.databrokerClient.SyncLatest(ctx, &databroker.SyncLatestRequest{
|
||||
Type: typ,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sync latest databroker: %w", err)
|
||||
}
|
||||
|
||||
recordSet := make(RecordSet[DatabrokerRecord])
|
||||
for {
|
||||
err = c.databrokerRateLimit.Wait(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wait for databroker rate limit: %w", err)
|
||||
}
|
||||
|
||||
res, err := stream.Recv()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("receive databroker record: %w", err)
|
||||
}
|
||||
|
||||
if record := res.GetRecord(); record != nil {
|
||||
recordSet[record.GetId()] = DatabrokerRecord{record}
|
||||
}
|
||||
}
|
||||
return recordSet, nil
|
||||
}
|
||||
|
||||
// DatabrokerChangeSet is a set of databroker changes.
|
||||
type DatabrokerChangeSet struct {
|
||||
now *timestamppb.Timestamp
|
||||
updates []*databroker.Record
|
||||
}
|
||||
|
||||
// NewDatabrokerChangeSet creates a new databroker change set.
|
||||
func NewDatabrokerChangeSet() *DatabrokerChangeSet {
|
||||
return &DatabrokerChangeSet{
|
||||
now: timestamppb.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Remove adds a record to the change set.
|
||||
func (cs *DatabrokerChangeSet) Remove(typ string, id string) {
|
||||
cs.updates = append(cs.updates, &databroker.Record{
|
||||
Type: typ,
|
||||
Id: id,
|
||||
DeletedAt: cs.now,
|
||||
})
|
||||
}
|
||||
|
||||
// Upsert adds a record to the change set.
|
||||
func (cs *DatabrokerChangeSet) Upsert(record *databroker.Record) {
|
||||
cs.updates = append(cs.updates, &databroker.Record{
|
||||
Type: record.Type,
|
||||
Id: record.Id,
|
||||
Data: record.Data,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *service) ApplyChanges(ctx context.Context, changes *DatabrokerChangeSet) error {
|
||||
updates := databroker.OptimumPutRequestsFromRecords(changes.updates)
|
||||
for _, req := range updates {
|
||||
err := c.databrokerRateLimit.Wait(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("wait for databroker rate limit: %w", err)
|
||||
}
|
||||
_, err = c.config.databrokerClient.Put(ctx, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("put databroker record: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PurgeRecordsNotInList removes databroker records that existed in
|
||||
// the bundles, and were applied to the databroker, but no longer present in the bundle list.
|
||||
func (c *service) PurgeRecordsNotInList(_ context.Context) error {
|
||||
// TODO: implement
|
||||
return nil
|
||||
}
|
132
internal/zero/reconciler/download.go
Normal file
132
internal/zero/reconciler/download.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package reconciler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type downloadOptions struct {
|
||||
requestCacheEntry *BundleCacheEntry
|
||||
responseCacheEntry *BundleCacheEntry
|
||||
}
|
||||
|
||||
// DownloadOption is an option for downloading a bundle
|
||||
type DownloadOption func(*downloadOptions)
|
||||
|
||||
// WithCacheEntry sets the cache entry to use for the request.
|
||||
func WithCacheEntry(entry BundleCacheEntry) DownloadOption {
|
||||
return func(opts *downloadOptions) {
|
||||
opts.requestCacheEntry = &entry
|
||||
}
|
||||
}
|
||||
|
||||
// WithUpdateCacheEntry updates the cache entry with the values from the response.
|
||||
func WithUpdateCacheEntry(dst *BundleCacheEntry) DownloadOption {
|
||||
return func(opts *downloadOptions) {
|
||||
opts.responseCacheEntry = dst
|
||||
}
|
||||
}
|
||||
|
||||
func getDownloadOptions(opts ...DownloadOption) downloadOptions {
|
||||
var options downloadOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func (opt *downloadOptions) updateRequest(req *http.Request) {
|
||||
if opt.requestCacheEntry != nil {
|
||||
req.Header.Set("If-None-Match", opt.requestCacheEntry.ETag)
|
||||
req.Header.Set("If-Modified-Since", opt.requestCacheEntry.LastModified.Format(http.TimeFormat))
|
||||
}
|
||||
}
|
||||
|
||||
func (opt *downloadOptions) updateFromResponse(resp *http.Response) error {
|
||||
if opt.responseCacheEntry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotModified && opt.requestCacheEntry != nil {
|
||||
*opt.responseCacheEntry = *opt.requestCacheEntry
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil
|
||||
}
|
||||
|
||||
return updateBundleCacheEntryFromResponse(opt.responseCacheEntry, resp.Header)
|
||||
}
|
||||
|
||||
// DownloadBundleIfChanged downloads the bundle if it has changed.
|
||||
func (c *service) DownloadBundleIfChanged(
|
||||
ctx context.Context,
|
||||
dst io.Writer,
|
||||
bundleKey string,
|
||||
opts ...DownloadOption,
|
||||
) error {
|
||||
options := getDownloadOptions(opts...)
|
||||
|
||||
url, err := c.GetBundleDownloadURL(ctx, bundleKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get download url: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new request: %w", err)
|
||||
}
|
||||
options.updateRequest(req)
|
||||
|
||||
resp, err := c.config.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("do request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = options.updateFromResponse(resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotModified {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected response: %d/%s", resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
_, err = io.Copy(dst, resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("write file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateBundleCacheEntryFromResponse(dst *BundleCacheEntry, headers http.Header) error {
|
||||
txt := headers.Get("Last-Modified")
|
||||
if txt == "" {
|
||||
return fmt.Errorf("missing last-modified header")
|
||||
}
|
||||
|
||||
lastModified, err := time.Parse(http.TimeFormat, txt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse last modified: %w", err)
|
||||
}
|
||||
|
||||
etag := headers.Get("ETag")
|
||||
if etag == "" {
|
||||
return fmt.Errorf("missing etag header")
|
||||
}
|
||||
|
||||
dst.LastModified = lastModified
|
||||
dst.ETag = etag
|
||||
|
||||
return nil
|
||||
}
|
44
internal/zero/reconciler/download_cache.go
Normal file
44
internal/zero/reconciler/download_cache.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package reconciler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BundleCacheEntry is a cache entry for a bundle
|
||||
// that is kept in the databroker to avoid downloading
|
||||
// the same bundle multiple times.
|
||||
//
|
||||
// by using the ETag and LastModified headers, we do not need to
|
||||
// keep caches of the bundles themselves, which can be large.
|
||||
//
|
||||
// also it works in case of multiple instances, as it uses
|
||||
// the databroker database as a shared cache.
|
||||
type BundleCacheEntry struct {
|
||||
ETag string
|
||||
LastModified time.Time
|
||||
RecordTypes []string
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrBundleCacheEntryNotFound is returned when a bundle cache entry is not found
|
||||
ErrBundleCacheEntryNotFound = errors.New("bundle cache entry not found")
|
||||
)
|
||||
|
||||
// Equals returns true if the two cache entries are equal
|
||||
func (c *BundleCacheEntry) Equals(other BundleCacheEntry) bool {
|
||||
return c.ETag == other.ETag && c.LastModified.Equal(other.LastModified)
|
||||
}
|
||||
|
||||
// GetBundleCacheEntry gets a bundle cache entry from the databroker
|
||||
func (c *service) GetBundleCacheEntry(_ context.Context, _ string, _ *BundleCacheEntry) error {
|
||||
// TODO: implement
|
||||
return ErrBundleCacheEntryNotFound
|
||||
}
|
||||
|
||||
// SetBundleCacheEntry sets a bundle cache entry in the databroker
|
||||
func (c *service) SetBundleCacheEntry(_ context.Context, _ string, _ BundleCacheEntry) error {
|
||||
// TODO: implement
|
||||
return nil
|
||||
}
|
122
internal/zero/reconciler/records.go
Normal file
122
internal/zero/reconciler/records.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package reconciler
|
||||
|
||||
// RecordSetBundle is an index of databroker records by type
|
||||
type RecordSetBundle[T Record[T]] map[string]RecordSet[T]
|
||||
|
||||
// RecordSet is an index of databroker records by their id.
|
||||
type RecordSet[T Record[T]] map[string]T
|
||||
|
||||
// Record is a record
|
||||
type Record[T any] interface {
|
||||
GetID() string
|
||||
GetType() string
|
||||
Equal(other T) bool
|
||||
}
|
||||
|
||||
// RecordTypes returns the types of records in the bundle.
|
||||
func (rsb RecordSetBundle[T]) RecordTypes() []string {
|
||||
types := make([]string, 0, len(rsb))
|
||||
for typ := range rsb {
|
||||
types = append(types, typ)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
// Add adds a record to the bundle.
|
||||
func (rsb RecordSetBundle[T]) Add(record T) {
|
||||
rs, ok := rsb[record.GetType()]
|
||||
if !ok {
|
||||
rs = make(RecordSet[T])
|
||||
rsb[record.GetType()] = rs
|
||||
}
|
||||
rs[record.GetID()] = record
|
||||
}
|
||||
|
||||
// GetAdded returns the records that are in other but not in rsb.
|
||||
func (rsb RecordSetBundle[T]) GetAdded(other RecordSetBundle[T]) RecordSetBundle[T] {
|
||||
added := make(RecordSetBundle[T])
|
||||
for otherType, otherRS := range other {
|
||||
rs, ok := rsb[otherType]
|
||||
if !ok {
|
||||
added[otherType] = otherRS
|
||||
continue
|
||||
}
|
||||
rss := rs.GetAdded(other[otherType])
|
||||
if len(rss) > 0 {
|
||||
added[otherType] = rss
|
||||
}
|
||||
}
|
||||
return added
|
||||
}
|
||||
|
||||
// GetRemoved returns the records that are in rs but not in other.
|
||||
func (rsb RecordSetBundle[T]) GetRemoved(other RecordSetBundle[T]) RecordSetBundle[T] {
|
||||
return other.GetAdded(rsb)
|
||||
}
|
||||
|
||||
// GetModified returns the records that are in both rs and other but have different data.
|
||||
func (rsb RecordSetBundle[T]) GetModified(other RecordSetBundle[T]) RecordSetBundle[T] {
|
||||
modified := make(RecordSetBundle[T])
|
||||
for otherType, otherRS := range other {
|
||||
rs, ok := rsb[otherType]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
m := rs.GetModified(otherRS)
|
||||
if len(m) > 0 {
|
||||
modified[otherType] = m
|
||||
}
|
||||
}
|
||||
return modified
|
||||
}
|
||||
|
||||
// GetAdded returns the records that are in other but not in rs.
|
||||
func (rs RecordSet[T]) GetAdded(other RecordSet[T]) RecordSet[T] {
|
||||
added := make(RecordSet[T])
|
||||
for id, record := range other {
|
||||
if _, ok := rs[id]; !ok {
|
||||
added[id] = record
|
||||
}
|
||||
}
|
||||
return added
|
||||
}
|
||||
|
||||
// GetRemoved returns the records that are in rs but not in other.
|
||||
func (rs RecordSet[T]) GetRemoved(other RecordSet[T]) RecordSet[T] {
|
||||
return other.GetAdded(rs)
|
||||
}
|
||||
|
||||
// GetModified returns the records that are in both rs and other but have different data.
|
||||
// by comparing the protobuf bytes of the payload.
|
||||
func (rs RecordSet[T]) GetModified(other RecordSet[T]) RecordSet[T] {
|
||||
modified := make(RecordSet[T])
|
||||
for id, record := range other {
|
||||
otherRecord, ok := rs[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !record.Equal(otherRecord) {
|
||||
modified[id] = record
|
||||
}
|
||||
}
|
||||
return modified
|
||||
}
|
||||
|
||||
// Flatten returns all records in the set.
|
||||
func (rs RecordSet[T]) Flatten() []T {
|
||||
records := make([]T, 0, len(rs))
|
||||
for _, record := range rs {
|
||||
records = append(records, record)
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
// Flatten returns all records in the bundle.
|
||||
func (rsb RecordSetBundle[T]) Flatten() []T {
|
||||
records := make([]T, 0)
|
||||
for _, rs := range rsb {
|
||||
records = append(records, rs.Flatten()...)
|
||||
}
|
||||
return records
|
||||
}
|
77
internal/zero/reconciler/records_test.go
Normal file
77
internal/zero/reconciler/records_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package reconciler_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/zero/reconciler"
|
||||
)
|
||||
|
||||
type testRecord struct {
|
||||
ID string
|
||||
Type string
|
||||
Val string
|
||||
}
|
||||
|
||||
func (r testRecord) GetID() string {
|
||||
return r.ID
|
||||
}
|
||||
|
||||
func (r testRecord) GetType() string {
|
||||
return r.Type
|
||||
}
|
||||
|
||||
func (r testRecord) Equal(other testRecord) bool {
|
||||
return r.ID == other.ID && r.Type == other.Type && r.Val == other.Val
|
||||
}
|
||||
|
||||
func TestRecords(t *testing.T) {
|
||||
initial := make(reconciler.RecordSetBundle[testRecord])
|
||||
initial.Add(testRecord{ID: "1", Type: "a", Val: "a-1"})
|
||||
initial.Add(testRecord{ID: "2", Type: "a", Val: "a-2"})
|
||||
initial.Add(testRecord{ID: "1", Type: "b", Val: "b-1"})
|
||||
|
||||
// test record types
|
||||
assert.ElementsMatch(t, []string{"a", "b"}, initial.RecordTypes())
|
||||
|
||||
// test added, deleted and modified
|
||||
updated := make(reconciler.RecordSetBundle[testRecord])
|
||||
updated.Add(testRecord{ID: "1", Type: "a", Val: "a-1-1"})
|
||||
updated.Add(testRecord{ID: "3", Type: "a", Val: "a-3"})
|
||||
updated.Add(testRecord{ID: "1", Type: "b", Val: "b-1"})
|
||||
updated.Add(testRecord{ID: "2", Type: "b", Val: "b-2"})
|
||||
updated.Add(testRecord{ID: "1", Type: "c", Val: "c-1"})
|
||||
|
||||
assert.ElementsMatch(t, []string{"a", "b", "c"}, updated.RecordTypes())
|
||||
|
||||
added := initial.GetAdded(updated)
|
||||
assert.Equal(t,
|
||||
reconciler.RecordSetBundle[testRecord]{
|
||||
"a": reconciler.RecordSet[testRecord]{
|
||||
"3": {ID: "3", Type: "a", Val: "a-3"},
|
||||
},
|
||||
"b": reconciler.RecordSet[testRecord]{
|
||||
"2": {ID: "2", Type: "b", Val: "b-2"},
|
||||
},
|
||||
"c": reconciler.RecordSet[testRecord]{
|
||||
"1": {ID: "1", Type: "c", Val: "c-1"},
|
||||
},
|
||||
}, added)
|
||||
|
||||
removed := initial.GetRemoved(updated)
|
||||
assert.Equal(t,
|
||||
reconciler.RecordSetBundle[testRecord]{
|
||||
"a": reconciler.RecordSet[testRecord]{
|
||||
"2": {ID: "2", Type: "a", Val: "a-2"},
|
||||
},
|
||||
}, removed)
|
||||
|
||||
modified := initial.GetModified(updated)
|
||||
assert.Equal(t,
|
||||
reconciler.RecordSetBundle[testRecord]{
|
||||
"a": reconciler.RecordSet[testRecord]{
|
||||
"1": {ID: "1", Type: "a", Val: "a-1-1"},
|
||||
},
|
||||
}, modified)
|
||||
}
|
148
internal/zero/reconciler/service.go
Normal file
148
internal/zero/reconciler/service.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
package reconciler
|
||||
|
||||
/*
|
||||
* This is a main control loop for the reconciler service.
|
||||
*
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/atomicutil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
connect_mux "github.com/pomerium/zero-sdk/connect-mux"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
config *reconcilerConfig
|
||||
|
||||
databrokerRateLimit *rate.Limiter
|
||||
downloadURLCache map[string]urlEntry
|
||||
|
||||
bundles Bundles
|
||||
|
||||
fullUpdateRequest chan struct{}
|
||||
bundleUpdatedRequest chan struct{}
|
||||
updateInterval atomicutil.Value[time.Duration]
|
||||
}
|
||||
|
||||
type urlEntry struct {
|
||||
URL url.URL
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
// Run creates a new bundle updater client
|
||||
// that runs until the context is canceled or a fatal error occurs.
|
||||
func Run(ctx context.Context, opts ...Option) error {
|
||||
config := newConfig(opts...)
|
||||
|
||||
c := &service{
|
||||
config: config,
|
||||
databrokerRateLimit: rate.NewLimiter(rate.Limit(config.databrokerRPS), 1),
|
||||
downloadURLCache: make(map[string]urlEntry),
|
||||
fullUpdateRequest: make(chan struct{}, 1),
|
||||
bundleUpdatedRequest: make(chan struct{}, 1),
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
eg.Go(func() error { return c.watchUpdates(ctx) })
|
||||
eg.Go(func() error { return c.updateLoop(ctx) })
|
||||
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (c *service) updateLoop(ctx context.Context) error {
|
||||
ticker := time.NewTicker(time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
next, ok := c.bundles.GetNextBundleToSync()
|
||||
if ok {
|
||||
err := c.SyncBundle(ctx, next)
|
||||
if err != nil {
|
||||
log.Error(ctx).Err(err).Str("bundle", next).Msg("reconciler: failed to sync bundle")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-c.fullUpdateRequest:
|
||||
c.fullUpdate(ctx)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-c.fullUpdateRequest:
|
||||
c.fullUpdate(ctx)
|
||||
case <-ticker.C:
|
||||
c.fullUpdate(ctx)
|
||||
case <-c.bundleUpdatedRequest:
|
||||
}
|
||||
|
||||
ticker.Reset(c.updateInterval.Load())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *service) fullUpdate(ctx context.Context) {
|
||||
err := c.RefreshBundleList(ctx)
|
||||
if err != nil {
|
||||
log.Error(ctx).Err(err).Msg("reconciler: failed to refresh bundle list")
|
||||
return
|
||||
}
|
||||
|
||||
err = c.PurgeRecordsNotInList(ctx)
|
||||
if err != nil {
|
||||
log.Error(ctx).Err(err).Msg("reconciler: failed to purge records not in list")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// run is a main control loop.
|
||||
// it is very simple and sequential download and reconcile.
|
||||
// it may be later optimized by splitting between download and reconciliation process,
|
||||
// as we would get more resource bundles beyond the config.
|
||||
func (c *service) watchUpdates(ctx context.Context) error {
|
||||
return c.config.connectMux.Watch(ctx,
|
||||
connect_mux.WithOnConnected(func(ctx context.Context) {
|
||||
c.triggerFullUpdate(true)
|
||||
}),
|
||||
connect_mux.WithOnDisconnected(func(_ context.Context) {
|
||||
c.triggerFullUpdate(false)
|
||||
}),
|
||||
connect_mux.WithOnBundleUpdated(func(_ context.Context, key string) {
|
||||
c.triggerBundleUpdate(key)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *service) triggerBundleUpdate(id string) {
|
||||
c.updateInterval.Store(c.config.checkForUpdateIntervalWhenConnected)
|
||||
c.bundles.MarkForSync(id)
|
||||
|
||||
select {
|
||||
case c.bundleUpdatedRequest <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (c *service) triggerFullUpdate(connected bool) {
|
||||
timeout := c.config.checkForUpdateIntervalWhenDisconnected
|
||||
if connected {
|
||||
timeout = c.config.checkForUpdateIntervalWhenConnected
|
||||
}
|
||||
c.updateInterval.Store(timeout)
|
||||
|
||||
select {
|
||||
case c.fullUpdateRequest <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
116
internal/zero/reconciler/sync.go
Normal file
116
internal/zero/reconciler/sync.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
package reconciler
|
||||
|
||||
/*
|
||||
* Sync syncs the bundles between their cloud source and the databroker.
|
||||
*
|
||||
* FullSync performs a full sync of the bundles by calling the API,
|
||||
* and walking the list of bundles, and calling SyncBundle on each.
|
||||
* It also removes any records in the databroker that are not in the list of bundles.
|
||||
*
|
||||
* WatchAndSync watches the API for changes, and calls SyncBundle on each change.
|
||||
*
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
)
|
||||
|
||||
// SyncBundle syncs the bundle to the databroker.
|
||||
// Databroker holds last synced bundle state in form of a (etag, last-modified) tuple.
|
||||
// This is only persisted in the databroker after all records are successfully synced.
|
||||
// That allows us to ignore any changes based on the same bundle state, without need to re-check all records between bundle and databroker.
|
||||
func (c *service) SyncBundle(ctx context.Context, key string) error {
|
||||
var cached, changed BundleCacheEntry
|
||||
opts := []DownloadOption{
|
||||
WithUpdateCacheEntry(&changed),
|
||||
}
|
||||
|
||||
err := c.GetBundleCacheEntry(ctx, key, &cached)
|
||||
if err == nil {
|
||||
opts = append(opts, WithCacheEntry(cached))
|
||||
} else if err != nil && !errors.Is(err, ErrBundleCacheEntryNotFound) {
|
||||
return fmt.Errorf("get bundle cache entry: %w", err)
|
||||
}
|
||||
|
||||
// download is much faster compared to databroker sync,
|
||||
// so we don't use pipe but rather download to a temp file and then sync it to databroker
|
||||
|
||||
fd, err := os.CreateTemp(c.config.tmpDir, fmt.Sprintf("pomerium-bundle-%s", key))
|
||||
if err != nil {
|
||||
return fmt.Errorf("create temp file: %w", err)
|
||||
}
|
||||
defer fd.Close()
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
err = c.DownloadBundleIfChanged(ctx, fd, key, opts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("download bundle: %w", err)
|
||||
}
|
||||
|
||||
if changed.Equals(cached) {
|
||||
log.Ctx(ctx).Info().Str("bundle", key).Msg("bundle not changed")
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = fd.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return fmt.Errorf("seek to start: %w", err)
|
||||
}
|
||||
|
||||
bundleRecordTypes, err := c.syncBundleToDatabroker(ctx, fd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("apply bundle to databroker: %w", err)
|
||||
}
|
||||
changed.RecordTypes = bundleRecordTypes
|
||||
|
||||
log.Ctx(ctx).Info().
|
||||
Str("bundle", key).
|
||||
Strs("record_types", bundleRecordTypes).
|
||||
Str("etag", changed.ETag).
|
||||
Time("last_modified", changed.LastModified).
|
||||
Msg("bundle synced")
|
||||
|
||||
err = c.SetBundleCacheEntry(ctx, key, changed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("set bundle cache entry: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *service) syncBundleToDatabroker(ctx context.Context, src io.Reader) ([]string, error) {
|
||||
bundleRecords, err := ReadBundleRecords(src)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read bundle records: %w", err)
|
||||
}
|
||||
|
||||
databrokerRecords, err := c.GetDatabrokerRecords(ctx, bundleRecords.RecordTypes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get databroker records: %w", err)
|
||||
}
|
||||
|
||||
updates := NewDatabrokerChangeSet()
|
||||
|
||||
for _, rec := range databrokerRecords.GetRemoved(bundleRecords).Flatten() {
|
||||
updates.Remove(rec.GetType(), rec.GetID())
|
||||
}
|
||||
for _, rec := range databrokerRecords.GetModified(bundleRecords).Flatten() {
|
||||
updates.Upsert(rec.V)
|
||||
}
|
||||
for _, rec := range databrokerRecords.GetAdded(bundleRecords).Flatten() {
|
||||
updates.Upsert(rec.V)
|
||||
}
|
||||
|
||||
err = c.ApplyChanges(ctx, updates)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("apply databroker changes: %w", err)
|
||||
}
|
||||
|
||||
return bundleRecords.RecordTypes(), nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue