diff --git a/cmd/applications-rp/cmd/root.go b/cmd/applications-rp/cmd/root.go index 7df3495907..6e891b9f66 100644 --- a/cmd/applications-rp/cmd/root.go +++ b/cmd/applications-rp/cmd/root.go @@ -22,7 +22,6 @@ import ( "github.com/go-logr/logr" "github.com/spf13/cobra" - etcdclient "go.etcd.io/etcd/client/v3" runtimelog "sigs.k8s.io/controller-runtime/pkg/log" "github.com/radius-project/radius/pkg/armrpc/builder" @@ -33,8 +32,6 @@ import ( "github.com/radius-project/radius/pkg/server" "github.com/radius-project/radius/pkg/trace" - "github.com/radius-project/radius/pkg/components/database/databaseprovider" - "github.com/radius-project/radius/pkg/ucp/data" "github.com/radius-project/radius/pkg/ucp/hosting" "github.com/radius-project/radius/pkg/ucp/ucplog" @@ -79,19 +76,6 @@ var rootCmd = &cobra.Command{ // Must set the logger before using controller-runtime. runtimelog.SetLogger(logger) - if options.Config.DatabaseProvider.Provider == databaseprovider.TypeETCD && - options.Config.DatabaseProvider.ETCD.InMemory { - // For in-memory etcd we need to register another service to manage its lifecycle. - // - // The client will be initialized asynchronously. - logger.Info("Enabled in-memory etcd") - client := hosting.NewAsyncValue[etcdclient.Client]() - options.Config.DatabaseProvider.ETCD.Client = client - options.Config.SecretProvider.ETCD.Client = client - - hostingSvc = append(hostingSvc, data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: client})) - } - builders, err := builders(options) if err != nil { return err diff --git a/cmd/ucpd/cmd/root.go b/cmd/ucpd/cmd/root.go index d99e885800..1face5384c 100644 --- a/cmd/ucpd/cmd/root.go +++ b/cmd/ucpd/cmd/root.go @@ -23,11 +23,9 @@ import ( "github.com/go-logr/logr" "github.com/spf13/cobra" - etcdclient "go.etcd.io/etcd/client/v3" runtimelog "sigs.k8s.io/controller-runtime/pkg/log" "github.com/radius-project/radius/pkg/armrpc/hostoptions" - "github.com/radius-project/radius/pkg/components/database/databaseprovider" "github.com/radius-project/radius/pkg/ucp" "github.com/radius-project/radius/pkg/ucp/hosting" "github.com/radius-project/radius/pkg/ucp/server" @@ -65,16 +63,6 @@ var rootCmd = &cobra.Command{ // Must set the logger before using controller-runtime. runtimelog.SetLogger(logger) - if options.Config.Database.Provider == databaseprovider.TypeETCD && - options.Config.Database.ETCD.InMemory { - // For in-memory etcd we need to register another service to manage its lifecycle. - // - // The client will be initialized asynchronously. - clientconfigSource := hosting.NewAsyncValue[etcdclient.Client]() - options.Config.Database.ETCD.Client = clientconfigSource - options.Config.Secrets.ETCD.Client = clientconfigSource - } - host, err := server.NewServer(options) if err != nil { return err diff --git a/go.mod b/go.mod index deb3f77454..894cfd1269 100644 --- a/go.mod +++ b/go.mod @@ -67,8 +67,6 @@ require ( github.com/stern/stern v1.31.0 github.com/stretchr/testify v1.10.0 github.com/wI2L/jsondiff v0.6.1 - go.etcd.io/etcd/client/v3 v3.5.17 - go.etcd.io/etcd/server/v3 v3.5.17 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0 go.opentelemetry.io/otel v1.33.0 @@ -185,13 +183,10 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.3 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/containerd/containerd v1.7.24 - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.3.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc @@ -201,7 +196,6 @@ require ( github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect @@ -218,7 +212,6 @@ require ( github.com/go-openapi/validate v0.24.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -227,10 +220,6 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.6 @@ -243,7 +232,6 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmoiron/sqlx v1.4.0 // indirect - github.com/jonboulle/clockwork v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.10 // indirect @@ -288,27 +276,15 @@ require ( github.com/sahilm/fuzzy v0.1.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/soheilhy/cmux v0.1.5 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/zclconf/go-cty v1.15.1 // indirect - go.etcd.io/bbolt v1.3.11 // indirect - go.etcd.io/etcd/api/v3 v3.5.17 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect - go.etcd.io/etcd/client/v2 v2.305.17 // indirect - go.etcd.io/etcd/pkg/v3 v3.5.17 // indirect - go.etcd.io/etcd/raft/v3 v3.5.17 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 @@ -325,7 +301,6 @@ require ( google.golang.org/protobuf v1.35.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect k8s.io/apiserver v0.32.0 // indirect k8s.io/component-base v0.32.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect diff --git a/go.sum b/go.sum index 1aec1ae6f9..519a2cdf86 100644 --- a/go.sum +++ b/go.sum @@ -321,7 +321,6 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -338,8 +337,6 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -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/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -377,8 +374,6 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= @@ -392,10 +387,6 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= -github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= @@ -432,8 +423,6 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= @@ -494,10 +483,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -545,14 +532,11 @@ 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-yaml v1.15.10 h1:9exV2CDYm/FWHPptIIgcDiPQS+X/4uTR+HEl+GF9xJU= github.com/goccy/go-yaml v1.15.10/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -671,7 +655,6 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uilive v0.0.4 h1:hUEBpQDj8D8jXgtCdBu7sWsy5sbW/5GhuO8KBwJ2jyY= @@ -680,14 +663,7 @@ github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= 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.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -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/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -744,8 +720,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= -github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -863,7 +837,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= @@ -877,7 +850,6 @@ github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFz github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -930,15 +902,11 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -985,8 +953,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -1003,8 +969,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -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/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1023,22 +987,6 @@ github.com/zclconf/go-cty v1.15.1 h1:RgQYm4j2EvoBRXOPxhUvxPzRrGDo1eCOhHXuGfrj5S0 github.com/zclconf/go-cty v1.15.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= -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.17 h1:cQB8eb8bxwuxOilBpMJAEo8fAONyrdXTHUNcMd8yT1w= -go.etcd.io/etcd/api/v3 v3.5.17/go.mod h1:d1hvkRuXkts6PmaYk2Vrgqbv7H4ADfAKhyJqHNLJCB4= -go.etcd.io/etcd/client/pkg/v3 v3.5.17 h1:XxnDXAWq2pnxqx76ljWwiQ9jylbpC4rvkAeRVOUKKVw= -go.etcd.io/etcd/client/pkg/v3 v3.5.17/go.mod h1:4DqK1TKacp/86nJk4FLQqo6Mn2vvQFBmruW3pP14H/w= -go.etcd.io/etcd/client/v2 v2.305.17 h1:ajFukQfI//xY5VuSeuUw4TJ4WnNR2kAFfV/P0pDdPMs= -go.etcd.io/etcd/client/v2 v2.305.17/go.mod h1:EttKgEgvwikmXN+b7pkEWxDZr6sEaYsqCiS3k4fa/Vg= -go.etcd.io/etcd/client/v3 v3.5.17 h1:o48sINNeWz5+pjy/Z0+HKpj/xSnBkuVhVvXkjEXbqZY= -go.etcd.io/etcd/client/v3 v3.5.17/go.mod h1:j2d4eXTHWkT2ClBgnnEPm/Wuu7jsqku41v9DZ3OtjQo= -go.etcd.io/etcd/pkg/v3 v3.5.17 h1:1k2wZ+oDp41jrk3F9o15o8o7K3/qliBo0mXqxo1PKaE= -go.etcd.io/etcd/pkg/v3 v3.5.17/go.mod h1:FrztuSuaJG0c7RXCOzT08w+PCugh2kCQXmruNYCpCGA= -go.etcd.io/etcd/raft/v3 v3.5.17 h1:wHPW/b1oFBw/+HjDAQ9vfr17OIInejTIsmwMZpK1dNo= -go.etcd.io/etcd/raft/v3 v3.5.17/go.mod h1:uapEfOMPaJ45CqBYIraLO5+fqyIY2d57nFfxzFwy4D4= -go.etcd.io/etcd/server/v3 v3.5.17 h1:xykBwLZk9IdDsB8z8rMdCCPRvhrG+fwvARaGA0TRiyc= -go.etcd.io/etcd/server/v3 v3.5.17/go.mod h1:40sqgtGt6ZJNKm8nk8x6LexZakPu+NDl/DCgZTZ69Cc= go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1060,10 +1008,6 @@ go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0 h1:GrcF8ABgnBHQFgp4z go.opentelemetry.io/contrib/instrumentation/runtime v0.58.0/go.mod h1:+kxR5prZLoFAJVXJWZKWO2e4PY2dYyXIRNklBuOyzpM= go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -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.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/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/RSDb+xRFx46GjkrL3VUZo= go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= go.opentelemetry.io/otel/exporters/zipkin v1.33.0 h1:aFexjEJIw5kVz6vQwnsqCG/nTV/UpsZh7MtQwGmH1eI= @@ -1077,20 +1021,14 @@ go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1174,7 +1112,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -1182,7 +1119,6 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1246,7 +1182,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1293,7 +1228,6 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/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-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1353,7 +1287,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1485,7 +1418,6 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1641,8 +1573,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1652,7 +1582,6 @@ gopkg.in/yaml.v2 v2.2.8/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= diff --git a/pkg/components/database/databaseprovider/factory.go b/pkg/components/database/databaseprovider/factory.go index 50c9bae764..c0b3555014 100644 --- a/pkg/components/database/databaseprovider/factory.go +++ b/pkg/components/database/databaseprovider/factory.go @@ -26,7 +26,6 @@ import ( store "github.com/radius-project/radius/pkg/components/database" "github.com/radius-project/radius/pkg/components/database/apiserverstore" ucpv1alpha1 "github.com/radius-project/radius/pkg/components/database/apiserverstore/api/ucp.dev/v1alpha1" - "github.com/radius-project/radius/pkg/components/database/etcdstore" "github.com/radius-project/radius/pkg/components/database/inmemory" "github.com/radius-project/radius/pkg/components/database/postgres" "github.com/radius-project/radius/pkg/kubeutil" @@ -40,7 +39,6 @@ type databaseClientFactoryFunc func(ctx context.Context, options Options) (store var databaseClientFactory = map[DatabaseProviderType]databaseClientFactoryFunc{ TypeAPIServer: initAPIServerClient, - TypeETCD: InitETCDClient, TypeInMemory: initInMemoryClient, TypePostgreSQL: initPostgreSQLClient, } @@ -81,26 +79,6 @@ func initAPIServerClient(ctx context.Context, opt Options) (store.Client, error) return client, nil } -// InitETCDClient checks if the ETCD client is in memory and if the client is not nil, then it initializes the database -// client and returns an ETCDClient. If either of these conditions are not met, an error is returned. -func InitETCDClient(ctx context.Context, opt Options) (store.Client, error) { - if !opt.ETCD.InMemory { - return nil, errors.New("failed to initialize etcd client: inmemory is the only supported mode for now") - } - if opt.ETCD.Client == nil { - return nil, errors.New("failed to initialize etcd client: ETCDOptions.Client is nil, this is a bug") - } - - // Initialize the database client once the etcd service has started - client, err := opt.ETCD.Client.Get(ctx) - if err != nil { - return nil, fmt.Errorf("failed to initialize etcd client: %w", err) - } - - etcdClient := etcdstore.NewETCDClient(client) - return etcdClient, nil -} - // initInMemoryClient creates a new in-memory store client. func initInMemoryClient(ctx context.Context, opt Options) (store.Client, error) { return inmemory.NewClient(), nil diff --git a/pkg/components/database/databaseprovider/options.go b/pkg/components/database/databaseprovider/options.go index 249e1b6447..c04f62f619 100644 --- a/pkg/components/database/databaseprovider/options.go +++ b/pkg/components/database/databaseprovider/options.go @@ -16,11 +16,6 @@ limitations under the License. package databaseprovider -import ( - "github.com/radius-project/radius/pkg/ucp/hosting" - etcdclient "go.etcd.io/etcd/client/v3" -) - // Options represents the database provider options. type Options struct { // Provider configures the database provider. @@ -29,9 +24,6 @@ type Options struct { // APIServer configures options for the Kubernetes APIServer store. Will be ignored if another store is configured. APIServer APIServerOptions `yaml:"apiserver,omitempty"` - // ETCD configures options for the etcd store. Will be ignored if another store is configured. - ETCD ETCDOptions `yaml:"etcd,omitempty"` - // InMemory configures options for the in-memory store. Will be ignored if another store is configured. InMemory InMemoryOptions `yaml:"inmemory,omitempty"` @@ -49,18 +41,6 @@ type APIServerOptions struct { Namespace string `yaml:"namespace"` } -// ETCDOptions represents options for the configuring the etcd store. -type ETCDOptions struct { - // InMemory configures the etcd store to run in-memory with the resource provider. This is not suitable for production use. - InMemory bool `yaml:"inmemory"` - - // Client is used to access the etcd client when running in memory. - // - // NOTE: when we run etcd in memory it will be registered as its own hosting.Service with its own startup/shutdown lifecyle. - // We need a way to share state between the etcd service and the things that want to consume it. This is that. - Client *hosting.AsyncValue[etcdclient.Client] `yaml:"-"` -} - // InMemoryOptions represents options for the in-memory store. type InMemoryOptions struct{} diff --git a/pkg/components/database/databaseprovider/types.go b/pkg/components/database/databaseprovider/types.go index 3a17486c72..3d3fc78f19 100644 --- a/pkg/components/database/databaseprovider/types.go +++ b/pkg/components/database/databaseprovider/types.go @@ -23,9 +23,6 @@ const ( // TypeAPIServer represents the Kubernetes APIServer provider. TypeAPIServer DatabaseProviderType = "apiserver" - // TypeETCD represents the etcd provider. - TypeETCD DatabaseProviderType = "etcd" - // TypeInMemory represents the in-memory provider. TypeInMemory DatabaseProviderType = "inmemory" diff --git a/pkg/components/database/etcdstore/etcdclient.go b/pkg/components/database/etcdstore/etcdclient.go deleted file mode 100644 index 96a7e1d281..0000000000 --- a/pkg/components/database/etcdstore/etcdclient.go +++ /dev/null @@ -1,343 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -// Package etcdstore stores resources using etcd. Our usage for etcd is optimized for the kinds -// of hierarchical and type-based queries common in a resource provider. -// -// Our key prefix scheme builds a hierarchy using '|' as a separator as '|' is illegal in an -// UCP resource identifier. We take advantage of the natural usage of '/' in resource ids as -// a delimiter. -// -// The key of a resource can be mechanically constructed from its resource id by replacing 'providers' -// with the '|' separator (for a non-extension resource). We have no current support for extension resources. -// -// Keys are structured like the following example: -// -// scope|/planes/radius/local/|/resourceGroups/cool-group/ -// resource|/planes/radius/local/resourceGroups/cool-group/|/Applications.Core/applications/cool-app/ -// -// As a special case for scopes (like resource groups) we treat the last segment as the routing scope. -// -// The prefix (scope or resource) limits each query to either for scope or resources respectively. In our -// use cases for the store we never need to query scopes and resources at the same time. Separating these actions -// limits the number of results - we want to avoid cases where the query has to return a huge set of results. -// -// For example, the following query will be commonly executed and we don't want it to list all resources in the -// database: -// -// scope|/planes/ -// -// This scheme allows a variety of flexibility for querying/filtering with different scopes. We prefer -// query approaches that that involved client-side filtering to avoid the need for N+1 query strategies. -// Leading and trailing '/' characters are preserved on the key-segments to avoid ambiguity. -package etcdstore - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - - "github.com/radius-project/radius/pkg/components/database" - "github.com/radius-project/radius/pkg/components/database/databaseutil" - "github.com/radius-project/radius/pkg/ucp/resources" - "github.com/radius-project/radius/pkg/ucp/util/etag" - etcdclient "go.etcd.io/etcd/client/v3" -) - -const ( - SectionSeparator = "|" -) - -// NewETCDClient creates a new ETCDClient instance with the given etcdclient.Client. -func NewETCDClient(c *etcdclient.Client) *ETCDClient { - return &ETCDClient{client: c} -} - -var _ database.Client = (*ETCDClient)(nil) - -type ETCDClient struct { - client *etcdclient.Client -} - -// Query retrieves objects from the store that match the given query and filters, and returns them in a store.ObjectQueryResult. -func (c *ETCDClient) Query(ctx context.Context, query database.Query, options ...database.QueryOptions) (*database.ObjectQueryResult, error) { - if ctx == nil { - return nil, &database.ErrInvalid{Message: "invalid argument. 'ctx' is required"} - } - - err := query.Validate() - if err != nil { - return nil, &database.ErrInvalid{Message: fmt.Sprintf("invalid argument. Query is invalid: %s", err.Error())} - } - - key := keyFromQuery(query) - - // TODO: We don't place a limit/top value on the query right now so we get all - // results as a single page. This would be a nice future improvement - // - // https://stackoverflow.com/questions/44873514/etcd3-go-client-how-to-paginate-large-sets-of-keys - response, err := c.client.Get(ctx, key, etcdclient.WithPrefix()) - if err != nil { - return nil, err - } - - results := database.ObjectQueryResult{} - for _, kv := range response.Kvs { - if keyMatchesQuery(kv.Key, query) { - value := database.Object{} - err = json.Unmarshal(kv.Value, &value) - if err != nil { - return nil, err - } - - match, err := value.MatchesFilters(query.Filters) - if err != nil { - return nil, err - } else if !match { - continue - } - - value.ETag = etag.NewFromRevision(kv.ModRevision) - results.Items = append(results.Items, value) - } - } - - return &results, nil -} - -// Get checks if the provided context, id and options are valid, then retrieves the corresponding object from -// the store and returns it, or an error if the object is not found or an error occurs. -func (c *ETCDClient) Get(ctx context.Context, id string, options ...database.GetOptions) (*database.Object, error) { - if ctx == nil { - return nil, &database.ErrInvalid{Message: "invalid argument. 'ctx' is required"} - } - parsed, err := resources.Parse(id) - if err != nil { - return nil, &database.ErrInvalid{Message: "invalid argument. 'id' must be a valid resource id"} - } - if parsed.IsEmpty() { - return nil, &database.ErrInvalid{Message: "invalid argument. 'id' must not be empty"} - } - if parsed.IsResourceCollection() || parsed.IsScopeCollection() { - return nil, &database.ErrInvalid{Message: "invalid argument. 'id' must refer to a named resource, not a collection"} - } - - key := keyFromID(parsed) - response, err := c.client.Get(ctx, key) - if err != nil { - return nil, err - } - - if response.Count == 0 { - return nil, &database.ErrNotFound{ID: id} - } - - value := database.Object{} - err = json.Unmarshal(response.Kvs[0].Value, &value) - if err != nil { - return nil, err - } - - value.ETag = etag.NewFromRevision(response.Kvs[0].ModRevision) - - return &value, nil -} - -// Delete checks if the given resource ID is valid, and if so, deletes it from the store, returning an error if the -// resource does not exist or if an ETag is provided and does not match. -func (c *ETCDClient) Delete(ctx context.Context, id string, options ...database.DeleteOptions) error { - if ctx == nil { - return &database.ErrInvalid{Message: "invalid argument. 'ctx' is required"} - } - parsed, err := resources.Parse(id) - if err != nil { - return &database.ErrInvalid{Message: "invalid argument. 'id' must be a valid resource id"} - } - if parsed.IsEmpty() { - return &database.ErrInvalid{Message: "invalid argument. 'id' must not be empty"} - } - if parsed.IsResourceCollection() || parsed.IsScopeCollection() { - return &database.ErrInvalid{Message: "invalid argument. 'id' must refer to a named resource, not a collection"} - } - - key := keyFromID(parsed) - config := database.NewDeleteConfig(options...) - - // If we have an ETag then we do to execute a transaction. - if config.ETag != "" { - revision, err := etag.ParseRevision(config.ETag) - if err != nil { - // Treat an invalid ETag as a concurrency failure, since it will never match. - return &database.ErrConcurrency{} - } - - txn, err := c.client.Txn(ctx). - If(etcdclient.Compare(etcdclient.ModRevision(key), "=", revision)). - Then(etcdclient.OpDelete(key)). - Commit() - if err != nil { - return err - } - - if !txn.Succeeded { - return &database.ErrConcurrency{} - } - - response := txn.Responses[0].GetResponseDeleteRange() - if response.Deleted == 0 { - return &database.ErrNotFound{ID: id} - } else { - return nil - } - } - - // If we don't have an ETag then things are straightforward :) - response, err := c.client.Delete(ctx, key) - if err != nil { - return err - } - - if response.Deleted == 0 { - return &database.ErrNotFound{ID: id} - } - - return nil -} - -// Save checks the context and object parameters, parses the object ID, marshals the object into JSON, saves the object to -// the store, and sets the object's ETag. If an ETag is provided, a transaction is executed to ensure concurrency. -func (c *ETCDClient) Save(ctx context.Context, obj *database.Object, options ...database.SaveOptions) error { - if ctx == nil { - return &database.ErrInvalid{Message: "invalid argument. 'ctx' is required"} - } - if obj == nil { - return &database.ErrInvalid{Message: "invalid argument. 'obj' is required"} - } - - id := obj.Metadata.ID - parsed, err := resources.Parse(id) - if err != nil { - return err - } - - b, err := json.Marshal(obj) - if err != nil { - return err - } - - key := keyFromID(parsed) - config := database.NewSaveConfig(options...) - - // If we have an ETag then we do to execute a transaction. - if config.ETag != "" { - revision, err := etag.ParseRevision(config.ETag) - if err != nil { - // Treat an invalid ETag as a concurrency failure, since it will never match. - return &database.ErrConcurrency{} - } - - txn, err := c.client.Txn(ctx). - If(etcdclient.Compare(etcdclient.ModRevision(key), "=", revision)). - Then(etcdclient.OpPut(key, string(b))). - Commit() - if err != nil { - return err - } - - if !txn.Succeeded { - return &database.ErrConcurrency{} - } - - response := txn.Responses[0].GetResponsePut() - obj.ETag = etag.NewFromRevision(response.Header.Revision) - return nil - } - - // If we don't have an ETag then things are pretty straightforward. - response, err := c.client.Put(ctx, key, string(b)) - if err != nil { - return err - } - - obj.ETag = etag.NewFromRevision(response.Header.Revision) - - return nil -} - -// Client returns the etcdclient.Client instance stored in the ETCDClient struct. -func (c *ETCDClient) Client() *etcdclient.Client { - return c.client -} - -func idFromKey(key []byte) (resources.ID, error) { - parts := strings.Split(string(key), SectionSeparator) - // sample valid key: - // scope|/planes/radius/local/resourceGroups/cool-group/|/Applications.Core/applications/cool-app/ - if len(parts) != 3 { - return resources.ID{}, errors.New("the etcd key '%q' is invalid because it does not have 3 sections") - } - - switch parts[0] { - case databaseutil.ScopePrefix: - // The key might look like: - // scope|/planes/radius/local/|/resourceGroups/cool-group/ - return resources.Parse(parts[1] + strings.TrimPrefix(parts[2], resources.SegmentSeparator)) - - case databaseutil.ResourcePrefix: - // The key might look like: - // resource|/subscriptions/{guid}/resourceGroups/cool-group/|/Applications.Core/applications/cool-app/ - return resources.Parse(parts[1] + resources.ProvidersSegment + parts[2]) - - default: - return resources.ID{}, errors.New("the etcd key '%q' is invalid because it has the wrong prefix") - } -} - -// keyFromID returns the key to use for an ID. They key should be used as an exact match. -func keyFromID(id resources.ID) string { - prefix, rootScope, routingScope, _ := databaseutil.ExtractStorageParts(id) - return prefix + SectionSeparator + rootScope + SectionSeparator + routingScope -} - -// keyFromQuery returns the key to use for an for executing a query. The key should be used as a prefix. -func keyFromQuery(query database.Query) string { - // These patterns require a prefix match for us in ETCd. - // - // A recursive query will not be able to consider anything in the routing scope, so it - // always requires client-side filtering. - prefix := databaseutil.ResourcePrefix - if query.IsScopeQuery { - prefix = databaseutil.ScopePrefix - } - - if query.ScopeRecursive { - return prefix + SectionSeparator + databaseutil.NormalizePart(query.RootScope) - } else { - return prefix + SectionSeparator + databaseutil.NormalizePart(query.RootScope) + SectionSeparator + databaseutil.NormalizePart(query.RoutingScopePrefix) - } -} - -func keyMatchesQuery(key []byte, query database.Query) bool { - // Ignore invalid keys, we don't expect to find them. - id, err := idFromKey(key) - if err != nil { - return false - } - - return databaseutil.IDMatchesQuery(id, query) -} diff --git a/pkg/components/database/etcdstore/etcdclient_test.go b/pkg/components/database/etcdstore/etcdclient_test.go deleted file mode 100644 index 7fa57dd31f..0000000000 --- a/pkg/components/database/etcdstore/etcdclient_test.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package etcdstore - -import ( - "context" - "testing" - - "github.com/radius-project/radius/pkg/ucp/data" - "github.com/radius-project/radius/pkg/ucp/hosting" - "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v3" - - "github.com/radius-project/radius/test/testcontext" - shared "github.com/radius-project/radius/test/ucp/storetest" -) - -func Test_ETCDClient(t *testing.T) { - ctx, cancel := testcontext.NewWithCancel(t) - t.Cleanup(cancel) - - config := hosting.NewAsyncValue[etcdclient.Client]() - service := data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: config}) - - go func() { - // We can't pass the test logger into the etcd service because it is forbidden to log - // using the test logger after the test finishes. - // - // https://github.com/golang/go/issues/40343 - // - // If you need to see the logging output while you are testing, then comment out the next line - // and you'll be able to see the spam from etcd. - // - // This is caught by the race checker and will fail your pr if you do it. - ctx := context.Background() - _ = service.Run(ctx) - }() - - etcdc, err := config.Get(ctx) - require.NoError(t, err) - - client := NewETCDClient(etcdc) - - clear := func(t *testing.T) { - keys, err := etcdc.Get(ctx, "", etcdclient.WithKeysOnly(), etcdclient.WithPrefix()) - require.NoError(t, err) - - for _, kv := range keys.Kvs { - _, err = etcdc.Delete(ctx, string(kv.Key)) - require.NoError(t, err) - } - } - - // The actual test logic lives in a shared package, we're just doing the setup here. - shared.RunTest(t, client, clear) -} diff --git a/pkg/components/secret/etcd/client.go b/pkg/components/secret/etcd/client.go deleted file mode 100644 index 344cb0a4c4..0000000000 --- a/pkg/components/secret/etcd/client.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package etcd - -import ( - "context" - - "github.com/radius-project/radius/pkg/components/secret" - "github.com/radius-project/radius/pkg/ucp/util" - etcdclient "go.etcd.io/etcd/client/v3" -) - -const ( - secretResourcePrefix = "secret|" -) - -var _ secret.Client = (*Client)(nil) - -// Client represents radius secret client to manage radius secret. -type Client struct { - ETCDClient *etcdclient.Client -} - -// Save checks if the name and value of the secret are valid and saves the value in etcd, returning an error if unsuccessful. -func (c *Client) Save(ctx context.Context, name string, value []byte) error { - if name == "" { - return &secret.ErrInvalid{Message: "invalid argument. 'name' is required"} - } - - if value == nil { - return &secret.ErrInvalid{Message: "invalid argument. 'value' is required"} - } - secretName := generateSecretResourceName(name) - - // We don't care about response while save, only if the operation is successful or not - _, err := c.ETCDClient.Put(ctx, secretName, string(value)) - if err != nil { - return err - } - return nil -} - -// Delete deletes a secret from the etcd store and returns an error if the secret is not found. -func (c *Client) Delete(ctx context.Context, name string) error { - secretName := generateSecretResourceName(name) - resp, err := c.ETCDClient.Delete(ctx, secretName) - if err != nil { - return err - } - if resp.Deleted == 0 { - return &secret.ErrNotFound{} - } - return nil -} - -// Get retrieves a secret from etcd given a name and returns it as a byte slice, or returns an error if the secret is -// not found or an invalid argument is provided. -func (c *Client) Get(ctx context.Context, name string) ([]byte, error) { - if name == "" { - return nil, &secret.ErrInvalid{Message: "invalid argument. 'name' is required"} - } - secretName := generateSecretResourceName(name) - resp, err := c.ETCDClient.Get(ctx, secretName) - if err != nil { - return nil, err - } - if resp.Count == 0 { - return nil, &secret.ErrNotFound{} - } - return resp.Kvs[0].Value, nil -} - -func generateSecretResourceName(name string) string { - return secretResourcePrefix + util.NormalizeStringToLower(name) -} diff --git a/pkg/components/secret/etcd/client_test.go b/pkg/components/secret/etcd/client_test.go deleted file mode 100644 index 29219e2f16..0000000000 --- a/pkg/components/secret/etcd/client_test.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package etcd - -import ( - "context" - "encoding/json" - "strconv" - "testing" - - "github.com/radius-project/radius/pkg/components/secret" - "github.com/radius-project/radius/pkg/ucp/data" - "github.com/radius-project/radius/pkg/ucp/hosting" - "github.com/radius-project/radius/test/testcontext" - "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v3" -) - -const ( - testSecretName = "azure-azurecloud-default" -) - -func Test_ETCD(t *testing.T) { - config := hosting.NewAsyncValue[etcdclient.Client]() - service := data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: config}) - - ctx, cancel := testcontext.NewWithCancel(t) - t.Cleanup(cancel) - - go func() { - // We can't pass the test logger into the etcd service because it is forbidden to log - // using the test logger after the test finishes. - // - // https://github.com/golang/go/issues/40343 - // - // If you need to see the logging output while you are testing, then comment out the next line - // and you'll be able to see the spam from etcd. - // - // This is caught by the race checker and will fail your pr if you do it. - ctx := context.Background() - _ = service.Run(ctx) - }() - - etcdc, err := config.Get(ctx) - require.NoError(t, err) - - runSaveTests(t, etcdc) - -} - -func runSaveTests(t *testing.T, etcdClient *etcdclient.Client) { - ctx := context.Background() - client := Client{ - ETCDClient: etcdClient, - } - testSecret, err := json.Marshal("test_secret") - require.NoError(t, err) - tests := []struct { - testName string - secretName string - secret []byte - response []byte - save bool - get bool - delete bool - err error - }{ - {"save-get-delete-secret-success", testSecretName, testSecret, []byte("test_secret"), true, true, true, nil}, - {"save-secret-empty-name", "", testSecret, nil, true, false, false, &secret.ErrInvalid{Message: "invalid argument. 'name' is required"}}, - {"save-secret-empty-secret", testSecretName, nil, nil, true, false, false, &secret.ErrInvalid{Message: "invalid argument. 'value' is required"}}, - {"delete-secret-without-save", testSecretName, nil, nil, false, false, true, &secret.ErrNotFound{}}, - {"get-secret-without-save", testSecretName, nil, nil, false, true, false, &secret.ErrNotFound{}}, - {"get-secret-with-empty-name", "", nil, nil, false, true, false, &secret.ErrInvalid{Message: "invalid argument. 'name' is required"}}, - } - for _, tt := range tests { - t.Run(tt.testName, func(t *testing.T) { - if tt.save { - err := client.Save(ctx, tt.secretName, tt.secret) - if tt.err == nil { - require.NoError(t, err) - } else { - require.Equal(t, err, tt.err) - } - } - if tt.get { - response, err := client.Get(ctx, tt.secretName) - if tt.err == nil { - require.NoError(t, err) - value, err := strconv.Unquote(string(response)) - require.NoError(t, err) - require.Equal(t, string(value), string(tt.response)) - } else { - require.Equal(t, err, tt.err) - } - } - if tt.delete { - err := client.Delete(ctx, tt.secretName) - if tt.err == nil { - require.NoError(t, err) - } else { - require.Equal(t, err, tt.err) - } - } - }) - } -} diff --git a/pkg/components/secret/secretprovider/factory.go b/pkg/components/secret/secretprovider/factory.go index f9ca30572e..68737c45ee 100644 --- a/pkg/components/secret/secretprovider/factory.go +++ b/pkg/components/secret/secretprovider/factory.go @@ -18,12 +18,8 @@ package secretprovider import ( "context" - "errors" - "github.com/radius-project/radius/pkg/components/database/databaseprovider" - "github.com/radius-project/radius/pkg/components/database/etcdstore" "github.com/radius-project/radius/pkg/components/secret" - "github.com/radius-project/radius/pkg/components/secret/etcd" "github.com/radius-project/radius/pkg/components/secret/inmemory" kubernetes_client "github.com/radius-project/radius/pkg/components/secret/kubernetes" "github.com/radius-project/radius/pkg/kubeutil" @@ -34,27 +30,10 @@ import ( type secretFactoryFunc func(context.Context, SecretProviderOptions) (secret.Client, error) var secretClientFactory = map[SecretProviderType]secretFactoryFunc{ - TypeETCDSecret: initETCDSecretClient, TypeKubernetesSecret: initKubernetesSecretClient, TypeInMemorySecret: initInMemorySecretClient, } -func initETCDSecretClient(ctx context.Context, opts SecretProviderOptions) (secret.Client, error) { - // etcd is a separate process run for development storage. - // data provider already creates an etcd process which can be re-used instead of a new process for secret. - client, err := databaseprovider.InitETCDClient(ctx, databaseprovider.Options{ - ETCD: opts.ETCD, - }) - if err != nil { - return nil, err - } - secretClient, ok := client.(*etcdstore.ETCDClient) - if !ok { - return nil, errors.New("no etcd Client detected") - } - return &etcd.Client{ETCDClient: secretClient.Client()}, nil -} - func initKubernetesSecretClient(ctx context.Context, opt SecretProviderOptions) (secret.Client, error) { s := scheme.Scheme cfg, err := kubeutil.NewClientConfig(&kubeutil.ConfigOptions{ diff --git a/pkg/components/secret/secretprovider/options.go b/pkg/components/secret/secretprovider/options.go index 9820a91f8a..712c756211 100644 --- a/pkg/components/secret/secretprovider/options.go +++ b/pkg/components/secret/secretprovider/options.go @@ -16,16 +16,11 @@ limitations under the License. package secretprovider -import "github.com/radius-project/radius/pkg/components/database/databaseprovider" - // SecretProviderOptions contains provider information of the secret. type SecretProviderOptions struct { // Provider configures the secret provider. Provider SecretProviderType `yaml:"provider"` - // ETCD configures options for the etcd secret store. - ETCD databaseprovider.ETCDOptions `yaml:"etcd,omitempty"` - // InMemory configures options for the in-memory secret store. InMemory struct{} `yaml:"inmemory,omitempty"` } diff --git a/pkg/components/secret/secretprovider/types.go b/pkg/components/secret/secretprovider/types.go index 66a0c77ff6..2fbbe25cfa 100644 --- a/pkg/components/secret/secretprovider/types.go +++ b/pkg/components/secret/secretprovider/types.go @@ -20,9 +20,6 @@ package secretprovider type SecretProviderType string const ( - // TypeETCDSecret represents the ETCD secret provider. - TypeETCDSecret SecretProviderType = "etcd" - // TypeKubernetesSecret represents the Kubernetes secret provider. TypeKubernetesSecret SecretProviderType = "kubernetes" diff --git a/pkg/dynamicrp/server/server.go b/pkg/dynamicrp/server/server.go index ff3fc804b5..d6e2cc24c1 100644 --- a/pkg/dynamicrp/server/server.go +++ b/pkg/dynamicrp/server/server.go @@ -17,37 +17,19 @@ limitations under the License. package server import ( - "time" - - "github.com/radius-project/radius/pkg/components/database/databaseprovider" "github.com/radius-project/radius/pkg/dynamicrp" "github.com/radius-project/radius/pkg/dynamicrp/backend" "github.com/radius-project/radius/pkg/dynamicrp/frontend" metricsservice "github.com/radius-project/radius/pkg/metrics/service" profilerservice "github.com/radius-project/radius/pkg/profiler/service" "github.com/radius-project/radius/pkg/trace" - "github.com/radius-project/radius/pkg/ucp/data" "github.com/radius-project/radius/pkg/ucp/hosting" ) -const ( - HTTPServerStopTimeout = time.Second * 10 - ServiceName = "dynamic-rp" -) - -const UCPProviderName = "System.Resources" - -// NewServer creates a new hosting.Host instance with services for API, EmbeddedETCD, Metrics, Profiler and Backend (if -// enabled) based on the given Options. +// NewServer initializes a host for UCP based on the provided options. func NewServer(options *dynamicrp.Options) (*hosting.Host, error) { services := []hosting.Service{} - // In-memory ETCD requires a service running in the process. - if options.Config.Database.Provider == databaseprovider.TypeETCD && - options.Config.Database.ETCD.InMemory { - services = append(services, data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: options.Config.Database.ETCD.Client})) - } - // Metrics is provided via a service. if options.Config.Metrics.Prometheus.Enabled { services = append(services, metricsservice.NewService(metricsservice.HostOptions{ diff --git a/pkg/ucp/data/etcd.go b/pkg/ucp/data/etcd.go deleted file mode 100644 index 32c4095728..0000000000 --- a/pkg/ucp/data/etcd.go +++ /dev/null @@ -1,244 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package data - -import ( - "context" - "fmt" - "net" - "net/url" - "os" - "strings" - "time" - - "github.com/radius-project/radius/pkg/ucp/hosting" - "github.com/radius-project/radius/pkg/ucp/ucplog" - etcdclient "go.etcd.io/etcd/client/v3" - "go.etcd.io/etcd/server/v3/embed" -) - -const ( - ETCDStartTimeout = time.Second * 60 - ETCDStopTimeout = time.Second * 10 -) - -var _ hosting.Service = (*EmbeddedETCDService)(nil) - -type EmbeddedETCDServiceOptions struct { - ClientConfigSink *hosting.AsyncValue[etcdclient.Client] - - // AssignRandomPorts will choose random ports so that each instance of the etcd service - // is isolated. - AssignRandomPorts bool - - // Quiet will prevent etcd from logging to the console. - Quiet bool -} - -type EmbeddedETCDService struct { - options EmbeddedETCDServiceOptions - dirs []string -} - -// NewEmbeddedETCDService creates a new EmbeddedETCDService instance with the given options and returns a pointer to it. -func NewEmbeddedETCDService(options EmbeddedETCDServiceOptions) *EmbeddedETCDService { - return &EmbeddedETCDService{options: options} -} - -// Name returns a string "etcd" which is the name of the service. -func (s *EmbeddedETCDService) Name() string { - return "etcd" -} - -// "Run" creates a temporary directory for etcd to store data and wal files, assigns ports to avoid crosstalk when tests -// create multiple clusters, sets up logging, and starts an etcd server. If an error occurs, it will return an error. -func (s *EmbeddedETCDService) Run(ctx context.Context) error { - logger := ucplog.FromContextOrDiscard(ctx) - defer s.cleanup(ctx) - - config := embed.NewConfig() - - if s.options.AssignRandomPorts { - // We need to auto-assign ports to avoid crosstalk when tests create multiple clusters. ETCD uses - // hardcoded ports by default. - peerPort, clientPort, err := s.assignPorts() - if err != nil { - return fmt.Errorf("failed to assign listening ports for etcd: %w", err) - } - - logger.Info(fmt.Sprintf("etcd will listen on ports %d %d", *peerPort, *clientPort)) - - config.AdvertisePeerUrls = []url.URL{makeURL(*peerPort)} - config.ListenPeerUrls = []url.URL{makeURL(*peerPort)} - config.AdvertiseClientUrls = []url.URL{makeURL(*clientPort)} - config.ListenClientUrls = []url.URL{makeURL(*clientPort)} - - // Needs to be updated based on the ports that were chosen - config.ForceNewCluster = true - config.InitialCluster = config.InitialClusterFromName("default") - config.InitialClusterToken = fmt.Sprintf("cluster-%d", clientPort) - } - - // Using temp directories for storage - dataDir, err := os.MkdirTemp(os.TempDir(), "ucp-etcd-data-*") - if err != nil { - return fmt.Errorf("failed to create temporary data directory: %w", err) - } - s.dirs = append(s.dirs, dataDir) - - walDir, err := os.MkdirTemp(os.TempDir(), "ucp-etcd-wal-*") - if err != nil { - return fmt.Errorf("failed to create temporary wal directory: %w", err) - } - s.dirs = append(s.dirs, walDir) - - config.Dir = dataDir - config.WalDir = walDir - - // If we're using Zap we can just log to it directly. Otherwise send logging - // to the console. - zaplog := ucplog.Unwrap(logger) - if zaplog != nil { - config.ZapLoggerBuilder = embed.NewZapLoggerBuilder(zaplog.Named("etcd.server")) - } else if !s.options.Quiet { - config.LogLevel = "info" - config.LogOutputs = []string{"stdout"} - } else { - config.LogLevel = "fatal" - config.LogOutputs = []string{} - } - - // Use generated self-signed certs for authentication. - config.ClientAutoTLS = true - config.PeerAutoTLS = true - config.SelfSignedCertValidity = 1 // One year - - logger.Info("Starting etcd server") - server, err := embed.StartEtcd(config) - if err != nil { - if strings.HasPrefix(err.Error(), "listen tcp ") { - logger.Info("failed to start etcd server due to port conflict, assuming another instance of etcd is already running") - clientconfig := etcdclient.Config{ - Endpoints: []string{ - "http://localhost:2379", - }, - } - if zaplog != nil { - clientconfig.Logger = zaplog.Named("etcd.client") - } - - client, err := etcdclient.New(clientconfig) - if err != nil { - s.options.ClientConfigSink.PutErr(err) - } else { - s.options.ClientConfigSink.Put(client) - } - - <-ctx.Done() - } - - return err - } - logger.Info("Waiting for etcd server ready...") - - select { - case <-server.Server.ReadyNotify(): - logger.Info("Started etcd server") - break - case <-time.After(ETCDStartTimeout): - server.Server.Stop() // trigger a shutdown - s.cleanup(ctx) - return fmt.Errorf("etcd start timed out after %v", ETCDStartTimeout) - case err := <-server.Err(): - s.cleanup(ctx) - return fmt.Errorf("etcd start failed: %w", err) - } - - clientconfig := etcdclient.Config{ - Endpoints: server.Server.Cluster().ClientURLs(), - } - if zaplog != nil { - clientconfig.Logger = zaplog.Named("etcd.client") - } - - client, err := etcdclient.New(clientconfig) - if err != nil { - s.options.ClientConfigSink.PutErr(err) - } else { - s.options.ClientConfigSink.Put(client) - } - - <-ctx.Done() - - logger.Info("Stopping etcd...") - server.Close() - - select { - case <-server.Server.StopNotify(): - break - case <-time.After(ETCDStopTimeout): - server.Server.HardStop() - return fmt.Errorf("etcd stop timed out after %v", ETCDStopTimeout) - case err := <-server.Err(): - if err != nil { - return fmt.Errorf("etcd stop failed: %w", err) - } - } - - logger.Info("Stopped etcd") - return nil -} - -func (s *EmbeddedETCDService) cleanup(ctx context.Context) { - logger := ucplog.FromContextOrDiscard(ctx) - logger.Info("Cleaning up etcd directories") - for _, dir := range s.dirs { - err := os.RemoveAll(dir) - if err != nil { - logger.Error(err, "Failed to delete temp directory", "directory", dir) - } - } -} - -func makeURL(port int) url.URL { - u, err := url.Parse(fmt.Sprintf("http://localhost:%d", port)) - if err != nil { - // This should never happen. - panic(fmt.Sprintf("failed to parse URL: %v", err)) - } - - return *u -} - -func (s *EmbeddedETCDService) assignPorts() (*int, *int, error) { - listener1, err := net.Listen("tcp", ":0") - if err != nil { - return nil, nil, err - } - defer listener1.Close() - - listener2, err := net.Listen("tcp", ":0") - if err != nil { - return nil, nil, err - } - defer listener2.Close() - - port1 := listener1.Addr().(*net.TCPAddr).Port - port2 := listener2.Addr().(*net.TCPAddr).Port - - return &port1, &port2, nil -} diff --git a/pkg/ucp/hosting/asyncvalue.go b/pkg/ucp/hosting/asyncvalue.go deleted file mode 100644 index 675009f10e..0000000000 --- a/pkg/ucp/hosting/asyncvalue.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package hosting - -import ( - "context" - "fmt" - "sync" -) - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://golang.org/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} //nolint:golint,unused - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} //nolint:golint,unused -func (*noCopy) Unlock() {} //nolint:golint,unused - -type AsyncValue[T any] struct { - noCopy noCopy //nolint - - Cond *sync.Cond - Value *T - Err error -} - -type result[T any] struct { - Value *T - Err error -} - -// NewAsyncValue creates a new AsyncValue object with a condition variable and a mutex. -func NewAsyncValue[T any]() *AsyncValue[T] { - return &AsyncValue[T]{Cond: &sync.Cond{L: &sync.Mutex{}}} -} - -// Get is a function that attempts to retrieve a value from a given context, and returns the value or an -// error if the context is done or an error occurs. -func (a *AsyncValue[T]) Get(ctx context.Context) (*T, error) { - - initialized := make(chan result[T], 1) - go func() { - a.Cond.L.Lock() - - defer func() { - a.Cond.L.Unlock() - }() - - for { - if a.Value != nil || a.Err != nil { - break - } - - // Not ready to proceed, wait to be woken up - a.Cond.Wait() - } - - initialized <- result[T]{Value: a.Value, Err: a.Err} - close(initialized) - }() - - select { - case <-ctx.Done(): - close(initialized) - return nil, fmt.Errorf("failed to retrieve value: %w", ctx.Err()) - - case result := <-initialized: - if result.Err != nil { - return nil, result.Err - } - return result.Value, nil - } -} - -// Put takes in a pointer to a value and sets it as the value of the AsyncValue, then broadcasts the change to -// any waiting goroutines. -func (a *AsyncValue[T]) Put(value *T) { - a.Cond.L.Lock() - a.Value = value - a.Cond.L.Unlock() - a.Cond.Broadcast() -} - -// PutErr sets an error value on the AsyncValue struct and broadcasts the condition variable to notify any waiting goroutines. -func (a *AsyncValue[T]) PutErr(err error) { - a.Cond.L.Lock() - a.Err = err - a.Cond.L.Unlock() - a.Cond.Broadcast() -} diff --git a/pkg/ucp/hosting/asyncvalue_test.go b/pkg/ucp/hosting/asyncvalue_test.go deleted file mode 100644 index ec19d4fbe8..0000000000 --- a/pkg/ucp/hosting/asyncvalue_test.go +++ /dev/null @@ -1,211 +0,0 @@ -/* -Copyright 2023 The Radius Authors. - -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. -*/ - -package hosting - -import ( - "context" - "errors" - "sync" - "testing" - "time" - - "github.com/radius-project/radius/test/testcontext" - "github.com/stretchr/testify/require" -) - -const TestTimeout = time.Minute * 5 - -type testValue struct{} - -type testResult struct { - Value *testValue - Err error -} - -// Used to synchronize the test "workers" for our tests. -type synchronizer struct { - Value *AsyncValue[testValue] - - WorkerCount int - workersStarted *sync.WaitGroup - workersCompleted *sync.WaitGroup - - Done chan error - results chan testResult -} - -// NewSynchronizer creates a new synchronizer struct with a given worker count, initializes the waitgroups and results -// channel, and returns the synchronizer. -func NewSynchronizer(workerCount int) *synchronizer { - s := &synchronizer{ - Value: NewAsyncValue[testValue](), - WorkerCount: workerCount, - workersStarted: &sync.WaitGroup{}, - workersCompleted: &sync.WaitGroup{}, - results: make(chan testResult, workerCount), - } - - s.workersStarted.Add(workerCount) - s.workersCompleted.Add(workerCount) - - return s -} - -// Start launches a number of workers to get a value from a context and returns a test result with the value retrieved -// and any errors that occurred. If the test times out before the workers complete, an error is returned. -func (s *synchronizer) Start(ctx context.Context, t *testing.T) { - for i := 0; i < s.WorkerCount; i++ { - go func() { - s.workersStarted.Done() - - value, err := s.Value.Get(ctx) - s.results <- testResult{Value: value, Err: err} - s.workersCompleted.Done() - }() - } - - started := make(chan struct{}) - - go func() { - s.workersStarted.Wait() - started <- struct{}{} - close(started) - }() - - select { - case <-started: - return - case <-ctx.Done(): - require.Fail(t, "test timed out without completing") - return - } -} - -// WaitForWorkersCompleted creates a channel to wait for workers to complete and returns a channel of test -// results or an error if the test times out. -func (s *synchronizer) WaitForWorkersCompleted(ctx context.Context, t *testing.T) <-chan testResult { - completed := make(chan struct{}) - - go func() { - s.workersCompleted.Wait() - completed <- struct{}{} - close(completed) - - // TRICKY: this is the best place to close the results channel. - close(s.results) - }() - - select { - case <-completed: - return s.results - case <-ctx.Done(): - require.Fail(t, "test timed out without completing") - return nil - } -} - -func Test_Get_NoBlockingWhenValueSet_Value(t *testing.T) { - ctx, cancel := testcontext.NewWithDeadline(t, TestTimeout) - t.Cleanup(cancel) - - asyncValue := NewAsyncValue[testValue]() - - value := &testValue{} - asyncValue.Put(value) - - got, err := asyncValue.Get(ctx) - require.Equal(t, value, got) - require.NoError(t, err) -} - -func Test_Get_NoBlockingWhenValueSet_Err(t *testing.T) { - ctx, cancel := testcontext.NewWithDeadline(t, TestTimeout) - t.Cleanup(cancel) - - asyncValue := NewAsyncValue[testValue]() - - err := errors.New("OH noes...") - asyncValue.PutErr(err) - - got, goterr := asyncValue.Get(ctx) - require.Nil(t, got) - require.ErrorIs(t, err, goterr) -} - -func Test_Get_BlocksUntil_ValueSet(t *testing.T) { - ctx, cancel := testcontext.NewWithDeadline(t, TestTimeout) - t.Cleanup(cancel) - - s := NewSynchronizer(10) - s.Start(ctx, t) - - value := &testValue{} - s.Value.Put(value) - - results := s.WaitForWorkersCompleted(ctx, t) - - // Verify results - count := 0 - for result := range results { - count++ - require.Equal(t, testResult{Value: value}, result) - } - require.Equal(t, s.WorkerCount, count) -} - -func Test_Get_BlocksUntil_ErrSet(t *testing.T) { - ctx, cancel := testcontext.NewWithDeadline(t, TestTimeout) - t.Cleanup(cancel) - - s := NewSynchronizer(10) - s.Start(ctx, t) - - err := errors.New("OH noes...") - s.Value.PutErr(err) - - results := s.WaitForWorkersCompleted(ctx, t) - - // Verify results - count := 0 - for result := range results { - count++ - require.Equal(t, testResult{Err: err}, result) - } - require.Equal(t, s.WorkerCount, count) -} - -func Test_Get_BlocksUntil_Canceled(t *testing.T) { - // We need two contexts. We want to cancel the work done by the workers. - workerContext, workerCancel := testcontext.NewWithCancel(t) - ctx, cancel := testcontext.NewWithDeadline(t, TestTimeout) - t.Cleanup(cancel) - - s := NewSynchronizer(10) - s.Start(workerContext, t) - - workerCancel() - - results := s.WaitForWorkersCompleted(ctx, t) - - // Verify results - count := 0 - for result := range results { - count++ - require.Error(t, result.Err) // Workers see a wrapped error, not the exact error from the context. - } - require.Equal(t, s.WorkerCount, count) -} diff --git a/pkg/ucp/server/server.go b/pkg/ucp/server/server.go index a656330a4a..b7d3edc03f 100644 --- a/pkg/ucp/server/server.go +++ b/pkg/ucp/server/server.go @@ -17,30 +17,22 @@ limitations under the License. package server import ( - "github.com/radius-project/radius/pkg/components/database/databaseprovider" metricsservice "github.com/radius-project/radius/pkg/metrics/service" profilerservice "github.com/radius-project/radius/pkg/profiler/service" "github.com/radius-project/radius/pkg/trace" "github.com/radius-project/radius/pkg/ucp" "github.com/radius-project/radius/pkg/ucp/backend" - "github.com/radius-project/radius/pkg/ucp/data" "github.com/radius-project/radius/pkg/ucp/frontend/api" "github.com/radius-project/radius/pkg/ucp/hosting" ) -// NewServer creates a new hosting.Host instance with services for API, EmbeddedETCD, Metrics, Profiler and Backend (if -// enabled) based on the given Options. +// NewServer initializes a host for UCP based on the provided options. func NewServer(options *ucp.Options) (*hosting.Host, error) { hostingServices := []hosting.Service{ api.NewService(options), backend.NewService(options), } - if options.Config.Database.Provider == databaseprovider.TypeETCD && - options.Config.Database.ETCD.InMemory { - hostingServices = append(hostingServices, data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: options.Config.Database.ETCD.Client})) - } - if options.Config.Metrics.Prometheus.Enabled { metricOptions := metricsservice.HostOptions{ Config: &options.Config.Metrics,