diff --git a/README.md b/README.md index 0bd6fcbc0..8a7cfdefa 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ This now provides an accessible http or [https](#https) endpoint for flag evalua Command: ```sh -curl -X POST "localhost:8013/flags/myBoolFlag/resolve/boolean" +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"myBoolFlag","context":{}}' -H "Content-Type: application/json" ``` Result: @@ -52,7 +52,7 @@ Result: Command: ```sh -curl -X POST "localhost:8013/flags/myStringFlag/resolve/string" +curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"myStringFlag","context":{}}' -H "Content-Type: application/json" ``` Result: @@ -68,7 +68,7 @@ Result: Command: ```sh -curl -X POST "localhost:8013/flags/myIntFlag/resolve/int" +curl -X POST "localhost:8013/schema.v1.Service/ResolveInt" -d '{"flagKey":"myIntFlag","context":{}}' -H "Content-Type: application/json" ``` Result: @@ -86,7 +86,7 @@ Result: Command: ```sh -curl -X POST "localhost:8013/flags/myFloatFlag/resolve/float" +curl -X POST "localhost:8013/schema.v1.Service/ResolveFloat" -d '{"flagKey":"myFloatFlag","context":{}}' -H "Content-Type: application/json" ``` Result: @@ -102,7 +102,7 @@ Result: Command: ```sh -curl -X POST "localhost:8013/flags/myObjectFlag/resolve/object" +curl -X POST "localhost:8013/schema.v1.Service/ResolveObject" -d '{"flagKey":"myObjectFlag","context":{}}' -H "Content-Type: application/json" ``` Result: @@ -118,7 +118,7 @@ Result: Command: ```sh -curl -X POST "localhost:8013/flags/isColorYellow/resolve/boolean" -d '{"color": "yellow"}' +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"isColorYellow","context":{"color":"yellow"}}' -H "Content-Type: application/json" ``` Result: @@ -136,13 +136,13 @@ A type mismatch error is returned when the resolved value of a flag does not mat Command: ```sh -curl -X POST "localhost:8013/flags/myBoolFlag/resolve/string" +curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"myBoolFlag","context":{}}' -H "Content-Type: application/json" ``` Result: ```sh -{"error_code":"TYPE_MISMATCH","reason":"ERROR"} +{"code":"invalid_argument","message":"TYPE_MISMATCH"} ```
@@ -154,13 +154,13 @@ The flag not found error is returned when flag key in the request doesn't match Command: ```sh -curl -X POST "localhost:8013/flags/aMissingFlag/resolve/string" +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"aMissingFlag","context":{}}' -H "Content-Type: application/json" ``` Result: ```sh -{"error_code":"FLAG_NOT_FOUND","reason":"ERROR"} +{"code":"not_found","message":"FLAG_NOT_FOUND"} ``` ### https @@ -172,7 +172,7 @@ When it is desired to use TLS for increased security, flagD can be started with This enables you to use an upgraded connection for the previous example requests, such as the following: ``` -curl -X POST "https://localhost:8013/flags/myBoolFlag/resolve/boolean" +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"myBoolFlag","context":{}}' -H "Content-Type: application/json" // {"value":true,"reason":"DEFAULT","variant":"on"} ``` @@ -231,7 +231,7 @@ A flag is defined as such: The rule provided returns `"on"` if `var color == "yellow"` and `"off"` otherwise: ```shell -curl -X POST "localhost:8013/flags/isColorYellow/resolve/boolean" -d '{"color": "yellow"}' +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"isColorYellow","context":{"color":"yellow"}}' -H "Content-Type: application/json" ``` returns @@ -243,7 +243,7 @@ returns whereas ```shell -curl -X POST "localhost:8013/flags/isColorYellow/resolve/boolean" -d '{"color": "white"}' +curl -X POST "localhost:8013/schema.v1.Service/ResolveBoolean" -d '{"flagKey":"isColorYellow","context":{"color":"white"}}' -H "Content-Type: application/json" ``` returns diff --git a/cmd/start.go b/cmd/start.go index f129d2975..e17d4a3d8 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -11,16 +11,16 @@ import ( ) const ( - portFlagName = "port" - serviceProviderFlagName = "service-provider" - socketPathFlagName = "socket-path" - syncProviderFlagName = "sync-provider" - providerArgsFlagName = "sync-provider-args" - evaluatorFlagName = "evaluator" - serverCertPathFlagName = "server-cert-path" - serverKeyPathFlagName = "server-key-path" - uriFlagName = "uri" - bearerTokenFlagName = "bearer-token" + portFlagName = "port" + socketPathFlagName = "socket-path" + syncProviderFlagName = "sync-provider" + providerArgsFlagName = "sync-provider-args" + evaluatorFlagName = "evaluator" + serverCertPathFlagName = "server-cert-path" + serverKeyPathFlagName = "server-key-path" + uriFlagName = "uri" + bearerTokenFlagName = "bearer-token" + corsFlagName = "cors-origin" ) func init() { @@ -34,7 +34,6 @@ func init() { flags.StringP(socketPathFlagName, "d", "", "Flagd socket path. "+ "With grpc the service will become available on this address. "+ "With http(s) the grpc-gateway proxy will use this address internally.") - flags.StringP(serviceProviderFlagName, "s", "http", "Set a service provider e.g. http or grpc") flags.StringP( syncProviderFlagName, "y", "filepath", "Set a sync provider e.g. filepath or remote", ) @@ -49,10 +48,10 @@ func init() { "flags with the same key, the later will be used.") flags.StringP( bearerTokenFlagName, "b", "", "Set a bearer token to use for remote sync") + flags.StringSliceP(corsFlagName, "C", []string{}, "CORS allowed origins, * will allow all origins") _ = viper.BindPFlag(portFlagName, flags.Lookup(portFlagName)) _ = viper.BindPFlag(socketPathFlagName, flags.Lookup(socketPathFlagName)) - _ = viper.BindPFlag(serviceProviderFlagName, flags.Lookup(serviceProviderFlagName)) _ = viper.BindPFlag(syncProviderFlagName, flags.Lookup(syncProviderFlagName)) _ = viper.BindPFlag(providerArgsFlagName, flags.Lookup(providerArgsFlagName)) _ = viper.BindPFlag(evaluatorFlagName, flags.Lookup(evaluatorFlagName)) @@ -60,6 +59,7 @@ func init() { _ = viper.BindPFlag(serverKeyPathFlagName, flags.Lookup(serverKeyPathFlagName)) _ = viper.BindPFlag(uriFlagName, flags.Lookup(uriFlagName)) _ = viper.BindPFlag(bearerTokenFlagName, flags.Lookup(bearerTokenFlagName)) + _ = viper.BindPFlag(corsFlagName, flags.Lookup(corsFlagName)) } // startCmd represents the start command @@ -78,7 +78,6 @@ var startCmd = &cobra.Command{ } // Build Runtime ----------------------------------------------------------- rt, err := runtime.FromConfig(runtime.Config{ - ServiceProvider: viper.GetString(serviceProviderFlagName), ServicePort: viper.GetInt32(portFlagName), ServiceSocketPath: viper.GetString(socketPathFlagName), ServiceCertPath: viper.GetString(serverCertPathFlagName), @@ -90,6 +89,8 @@ var startCmd = &cobra.Command{ SyncBearerToken: viper.GetString(bearerTokenFlagName), Evaluator: viper.GetString(evaluatorFlagName), + + CORS: viper.GetStringSlice(corsFlagName), }) if err != nil { log.Error(err) diff --git a/docs/configuration.md b/docs/configuration.md index 0d6057224..365c0d78b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -12,11 +12,11 @@ Supported flags are as follows (result of running `./flagd start --help`): -p, --port int32 Port to listen on (default 8013) -c, --server-cert-path string Server side tls certificate path -k, --server-key-path string Server side tls key path - -s, --service-provider string Set a service provider e.g. http or grpc (default "http") -a, --sync-provider-args Sync provider arguments as key values separated by = - -d, --socket-path string Set the flagd socket path. With grpc the service will become available on this address. With http(s) the grpc-gateway proxy will use this address internally + -d, --socket-path string Set the flagd socket path. -y, --sync-provider string Set a sync provider e.g. filepath or remote (default "filepath") -f, --uri strings Set a sync provider uri to read data from this can be a filepath or url. Using multiple providers is supported where collisions between flags with the same key, the later will be used. + -C, --cors-origin strings Set a CORS allow origin header, setting "*" will allow all origins (by default CORS headers are not set) ``` Environment variable keys are uppercased, prefixed with `FLAGD_` and all `-` are replaced with `_`. For example, diff --git a/docs/fractional_evaluation.md b/docs/fractional_evaluation.md index 58c11d0bb..75ec3d412 100644 --- a/docs/fractional_evaluation.md +++ b/docs/fractional_evaluation.md @@ -45,9 +45,9 @@ Flags defined as such: will return variant `red` 50% of the time, `blue` 20% of the time & `green` 30% of the time. ```shell -$ curl -X POST "localhost:8013/flags/headerColor/resolve/string" -d '{"email": "foo@bar.com"}' +$ curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d ''{"flagKey":"headerColor","context":{"email": "foo@bar.com"}}'' -H "Content-Type: application/json" {"value":"#0000FF","reason":"TARGETING_MATCH","variant":"blue"}% -$ curl -X POST "localhost:8013/flags/headerColor/resolve/string" -d '{"email": "foo@test.com"}' +$ curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d ''{"flagKey":"headerColor","context":{"email": "foo@test.com"}}'' -H "Content-Type: application/json" {"value":"#00FF00","reason":"TARGETING_MATCH","variant":"green"}% ``` diff --git a/docs/http_int_response.md b/docs/http_int_response.md index a77853879..8a0e7d53a 100644 --- a/docs/http_int_response.md +++ b/docs/http_int_response.md @@ -4,7 +4,7 @@ Why is my `int` response a `string`? Command: ```sh -curl -X POST "localhost:8013/flags/myIntFlag/resolve/int" +curl -X POST "localhost:8013/schema.v1.Service/ResolveInt" -d '{"flagKey":"myIntFlag","context":{}}' -H "Content-Type: application/json" ``` Result: ```sh @@ -14,7 +14,7 @@ When interacting directly with the flagD http(s) api and requesting an `int` the
Command: ```sh -curl -X POST "localhost:8013/flags/myIntFlag/resolve/float" +curl -X POST "localhost:8013/schema.v1.Service/ResolveFloat" -d '{"flagKey":"myIntFlag","context":{}}' -H "Content-Type: application/json" ``` Result: ```sh diff --git a/go.mod b/go.mod index ed8eeb59b..42e4e9c95 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,26 @@ module github.com/open-feature/flagd go 1.18 require ( + github.com/bufbuild/connect-go v0.4.0 github.com/deepmap/oapi-codegen v1.11.0 github.com/diegoholiveira/jsonlogic/v3 v3.2.3 github.com/dimiro1/banner v1.1.0 github.com/fsnotify/fsnotify v1.5.4 github.com/go-chi/chi/v5 v5.0.7 github.com/golang/mock v1.6.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1 github.com/mattn/go-colorable v0.1.12 github.com/open-feature/open-feature-operator v0.0.10-0.20220826061622-a6421d66936a github.com/open-feature/schemas v0.0.0-20220809125333-185e3bd77775 github.com/robfig/cron v1.2.0 + github.com/rs/cors v1.8.2 github.com/sirupsen/logrus v1.8.1 - github.com/soheilhy/cmux v0.1.5 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.7.4 github.com/xeipuuv/gojsonschema v1.2.0 github.com/zeebo/xxh3 v1.0.2 - go.buf.build/open-feature/flagd-server/open-feature/flagd v1.1.2 + go.buf.build/open-feature/flagd-connect/open-feature/flagd v1.1.3 + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.1 @@ -73,7 +74,6 @@ require ( github.com/subosito/gotenv v1.3.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect diff --git a/go.sum b/go.sum index 5863b52e4..91aed90dc 100644 --- a/go.sum +++ b/go.sum @@ -17,34 +17,14 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -55,20 +35,18 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/bufbuild/connect-go v0.4.0 h1:fIMyUYG8mXSTH+nnlOx9KmRUf3mBF0R2uKK+BQBoOHE= +github.com/bufbuild/connect-go v0.4.0/go.mod h1:ZEtBnQ7J/m7bvWOW+H8T/+hKQCzPVfhhhICuvtcnjlI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -79,8 +57,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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= @@ -109,9 +85,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= @@ -153,8 +126,6 @@ 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 v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -165,7 +136,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -183,10 +153,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -200,11 +168,9 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -213,7 +179,6 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -224,29 +189,15 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1 h1:/sDbPb60SusIXjiJGYLUoS/rAQurQmvGWmwn2bBPM9c= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1/go.mod h1:G+WkljZi4mflcqVxYSgvt8MNctRQHjEH8ubKtt1Ka3w= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -355,12 +306,11 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= @@ -409,15 +359,14 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.buf.build/open-feature/flagd-server/open-feature/flagd v1.1.2 h1:GbrVEHuAp/3a6JpfoV8cusP4/CveInar997DCCbXSAg= -go.buf.build/open-feature/flagd-server/open-feature/flagd v1.1.2/go.mod h1:1gOZbwcemK1/404A8u4kXmzIn4DIIT1xIe8JuowznT8= +go.buf.build/open-feature/flagd-connect/open-feature/flagd v1.1.3 h1:WdB8KPnlU7S+ux7euBKg6k4ZSrEiEHBJBJLnD5otxQM= +go.buf.build/open-feature/flagd-connect/open-feature/flagd v1.1.3/go.mod h1:ZaEOUjTu/oxTFHuwNjF2788REepgWYPsU4Ty6lPIMzc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -457,7 +406,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -499,27 +447,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-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-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/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= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -531,17 +465,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY= golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -592,41 +515,20 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/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-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= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -638,7 +540,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -698,18 +599,12 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -730,26 +625,6 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -795,50 +670,7 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 h1:d3fKQZK+1rWQMg3xLKQbPMirUCo29I/NRdI2WarSzTg= google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -859,22 +691,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/eval/ievaluator.go b/pkg/eval/ievaluator.go index a75118962..3be3cfb7b 100644 --- a/pkg/eval/ievaluator.go +++ b/pkg/eval/ievaluator.go @@ -8,7 +8,6 @@ import ( IEvaluator implementations store the state of the flags, do parsing and validation of the flag state and evaluate flags in response to handlers. */ - type IEvaluator interface { GetState() (string, error) SetState(state string) error diff --git a/pkg/model/reason.go b/pkg/model/reason.go index d6dbd899b..25382447c 100644 --- a/pkg/model/reason.go +++ b/pkg/model/reason.go @@ -1,5 +1,7 @@ package model +type EvaluationReason string + const ( TargetingMatchReason = "TARGETING_MATCH" SplitReason = "SPLIT" diff --git a/pkg/runtime/from_config.go b/pkg/runtime/from_config.go index ca97c67d0..af68258be 100644 --- a/pkg/runtime/from_config.go +++ b/pkg/runtime/from_config.go @@ -25,49 +25,23 @@ func FromConfig(config Config) (*Runtime, error) { if err := rt.setEvaluatorFromConfig(); err != nil { return nil, err } - if err := rt.setServiceFromConfig(); err != nil { - return nil, err - } if err := rt.setSyncImplFromConfig(); err != nil { return nil, err } + rt.setService() return &rt, nil } -func (r *Runtime) setServiceFromConfig() error { - switch r.config.ServiceProvider { - case "http": - r.Service = &service.HTTPService{ - HTTPServiceConfiguration: &service.HTTPServiceConfiguration{ - Port: r.config.ServicePort, - ServerKeyPath: r.config.ServiceKeyPath, - ServerCertPath: r.config.ServiceCertPath, - ServerSocketPath: r.config.ServiceSocketPath, - }, - GRPCService: &service.GRPCService{}, - Logger: log.WithFields(log.Fields{ - "service": "http", - "component": "service", - }), - } - case "grpc": - r.Service = &service.GRPCService{ - GRPCServiceConfiguration: &service.GRPCServiceConfiguration{ - Port: r.config.ServicePort, - ServerKeyPath: r.config.ServiceKeyPath, - ServerCertPath: r.config.ServiceCertPath, - ServerSocketPath: r.config.ServiceSocketPath, - }, - Logger: log.WithFields(log.Fields{ - "service": "grpc", - "component": "service", - }), - } - default: - return errors.New("no service-provider set") +func (r *Runtime) setService() { + r.Service = &service.ConnectService{ + ConnectServiceConfiguration: &service.ConnectServiceConfiguration{ + Port: r.config.ServicePort, + ServerKeyPath: r.config.ServiceKeyPath, + ServerCertPath: r.config.ServiceCertPath, + ServerSocketPath: r.config.ServiceSocketPath, + CORS: r.config.CORS, + }, } - log.Debugf("Using %s service-provider\n", r.config.ServiceProvider) - return nil } func (r *Runtime) setEvaluatorFromConfig() error { diff --git a/pkg/runtime/runtime.go b/pkg/runtime/runtime.go index e5346abb1..55ac5b607 100644 --- a/pkg/runtime/runtime.go +++ b/pkg/runtime/runtime.go @@ -22,7 +22,6 @@ type Runtime struct { } type Config struct { - ServiceProvider string ServicePort int32 ServiceSocketPath string ServiceCertPath string @@ -34,6 +33,7 @@ type Config struct { SyncBearerToken string Evaluator string + CORS []string } func (r *Runtime) startSyncer(ctx context.Context, syncr sync.ISync) error { diff --git a/pkg/service/connect_service.go b/pkg/service/connect_service.go new file mode 100644 index 000000000..5c7ee9f8e --- /dev/null +++ b/pkg/service/connect_service.go @@ -0,0 +1,238 @@ +package service + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "time" + + "github.com/bufbuild/connect-go" + "github.com/open-feature/flagd/pkg/eval" + "github.com/open-feature/flagd/pkg/model" + "github.com/rs/cors" + log "github.com/sirupsen/logrus" + schemaV1 "go.buf.build/open-feature/flagd-connect/open-feature/flagd/schema/v1" + schemaConnectV1 "go.buf.build/open-feature/flagd-connect/open-feature/flagd/schema/v1/schemav1connect" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + "google.golang.org/protobuf/types/known/structpb" +) + +const ErrorPrefix = "FlagdError:" + +type ConnectService struct { + Eval eval.IEvaluator + ConnectServiceConfiguration *ConnectServiceConfiguration + tls bool + server http.Server +} + +type ConnectServiceConfiguration struct { + Port int32 + ServerCertPath string + ServerKeyPath string + ServerSocketPath string + CORS []string +} + +func (s *ConnectService) Serve(ctx context.Context, eval eval.IEvaluator) error { + s.Eval = eval + + lis, err := s.setupServer() + if err != nil { + return err + } + + errChan := make(chan error, 1) + go func() { + if s.tls { + if err := s.server.ServeTLS( + lis, + s.ConnectServiceConfiguration.ServerCertPath, + s.ConnectServiceConfiguration.ServerKeyPath, + ); err != nil && !errors.Is(err, http.ErrServerClosed) { + errChan <- err + } + } else { + if err := s.server.Serve( + lis, + ); err != nil && !errors.Is(err, http.ErrServerClosed) { + errChan <- err + } + } + close(errChan) + }() + <-ctx.Done() + if err := s.server.Shutdown(ctx); err != nil { + return err + } + return <-errChan +} + +func (s *ConnectService) setupServer() (net.Listener, error) { + var lis net.Listener + var err error + mux := http.NewServeMux() + if s.ConnectServiceConfiguration.ServerSocketPath != "" { + lis, err = net.Listen("unix", s.ConnectServiceConfiguration.ServerSocketPath) + } else { + address := net.JoinHostPort("localhost", fmt.Sprintf("%d", s.ConnectServiceConfiguration.Port)) + lis, err = net.Listen("tcp", address) + } + if err != nil { + return nil, err + } + path, handler := schemaConnectV1.NewServiceHandler(s) + mux.Handle(path, handler) + if s.ConnectServiceConfiguration.ServerCertPath != "" && s.ConnectServiceConfiguration.ServerKeyPath != "" { + s.tls = true + handler = s.newCORS().Handler(mux) + } else { + handler = h2c.NewHandler( + s.newCORS().Handler(mux), + &http2.Server{}, + ) + } + s.server = http.Server{ + ReadTimeout: 2 * time.Second, + WriteTimeout: 4 * time.Second, + ReadHeaderTimeout: time.Second, + Handler: handler, + } + return lis, nil +} + +func (s *ConnectService) ResolveBoolean( + ctx context.Context, + req *connect.Request[schemaV1.ResolveBooleanRequest], +) (*connect.Response[schemaV1.ResolveBooleanResponse], error) { + res := connect.NewResponse(&schemaV1.ResolveBooleanResponse{}) + result, variant, reason, err := s.Eval.ResolveBooleanValue(req.Msg.GetFlagKey(), req.Msg.GetContext()) + if err != nil { + log.Error(err) + res.Msg.Reason = model.ErrorReason + return res, errFormat(err) + } + res.Msg.Reason = reason + res.Msg.Value = result + res.Msg.Variant = variant + return res, nil +} + +func (s *ConnectService) ResolveString( + ctx context.Context, + req *connect.Request[schemaV1.ResolveStringRequest], +) (*connect.Response[schemaV1.ResolveStringResponse], error) { + res := connect.NewResponse(&schemaV1.ResolveStringResponse{}) + result, variant, reason, err := s.Eval.ResolveStringValue(req.Msg.GetFlagKey(), req.Msg.GetContext()) + if err != nil { + log.Error(err) + res.Msg.Reason = model.ErrorReason + return res, errFormat(err) + } + res.Msg.Reason = reason + res.Msg.Value = result + res.Msg.Variant = variant + return res, nil +} + +func (s *ConnectService) ResolveInt( + ctx context.Context, + req *connect.Request[schemaV1.ResolveIntRequest], +) (*connect.Response[schemaV1.ResolveIntResponse], error) { + res := connect.NewResponse(&schemaV1.ResolveIntResponse{}) + result, variant, reason, err := s.Eval.ResolveIntValue(req.Msg.GetFlagKey(), req.Msg.GetContext()) + if err != nil { + log.Error(err) + res.Msg.Reason = model.ErrorReason + return res, errFormat(err) + } + res.Msg.Reason = reason + res.Msg.Value = result + res.Msg.Variant = variant + return res, nil +} + +func (s *ConnectService) ResolveFloat( + ctx context.Context, + req *connect.Request[schemaV1.ResolveFloatRequest], +) (*connect.Response[schemaV1.ResolveFloatResponse], error) { + res := connect.NewResponse(&schemaV1.ResolveFloatResponse{}) + result, variant, reason, err := s.Eval.ResolveFloatValue(req.Msg.GetFlagKey(), req.Msg.GetContext()) + if err != nil { + log.Error(err) + res.Msg.Reason = model.ErrorReason + return res, errFormat(err) + } + res.Msg.Reason = reason + res.Msg.Value = result + res.Msg.Variant = variant + return res, nil +} + +func (s *ConnectService) ResolveObject( + ctx context.Context, + req *connect.Request[schemaV1.ResolveObjectRequest], +) (*connect.Response[schemaV1.ResolveObjectResponse], error) { + res := connect.NewResponse(&schemaV1.ResolveObjectResponse{}) + result, variant, reason, err := s.Eval.ResolveObjectValue(req.Msg.GetFlagKey(), req.Msg.GetContext()) + if err != nil { + log.Error(err) + res.Msg.Reason = model.ErrorReason + return res, errFormat(err) + } + val, err := structpb.NewStruct(result) + if err != nil { + return res, err + } + res.Msg.Reason = reason + res.Msg.Value = val + res.Msg.Variant = variant + return res, nil +} + +func (s *ConnectService) newCORS() *cors.Cors { + return cors.New(cors.Options{ + AllowedMethods: []string{ + http.MethodHead, + http.MethodGet, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + }, + AllowedOrigins: s.ConnectServiceConfiguration.CORS, + AllowedHeaders: []string{"*"}, + ExposedHeaders: []string{ + // Content-Type is in the default safelist. + "Accept", + "Accept-Encoding", + "Accept-Post", + "Connect-Accept-Encoding", + "Connect-Content-Encoding", + "Content-Encoding", + "Grpc-Accept-Encoding", + "Grpc-Encoding", + "Grpc-Message", + "Grpc-Status", + "Grpc-Status-Details-Bin", + }, + }) +} + +func errFormat(err error) error { + switch err.Error() { + case model.FlagNotFoundErrorCode: + return connect.NewError(connect.CodeNotFound, fmt.Errorf("%s, %s", ErrorPrefix, err.Error())) + case model.TypeMismatchErrorCode: + return connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("%s, %s", ErrorPrefix, err.Error())) + case model.DisabledReason: + return connect.NewError(connect.CodeUnavailable, fmt.Errorf("%s, %s", ErrorPrefix, err.Error())) + case model.ParseErrorCode: + return connect.NewError(connect.CodeDataLoss, fmt.Errorf("%s, %s", ErrorPrefix, err.Error())) + } + + return err +} diff --git a/pkg/service/grpc_service_test.go b/pkg/service/connect_service_test.go similarity index 63% rename from pkg/service/grpc_service_test.go rename to pkg/service/connect_service_test.go index dd8436d4b..a4d3f500b 100644 --- a/pkg/service/grpc_service_test.go +++ b/pkg/service/connect_service_test.go @@ -8,11 +8,12 @@ import ( "testing" "time" + "github.com/bufbuild/connect-go" "github.com/golang/mock/gomock" "github.com/open-feature/flagd/pkg/model" service "github.com/open-feature/flagd/pkg/service" log "github.com/sirupsen/logrus" - gen "go.buf.build/open-feature/flagd-server/open-feature/flagd/schema/v1" + gen "go.buf.build/open-feature/flagd-connect/open-feature/flagd/schema/v1" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/protobuf/types/known/structpb" @@ -32,10 +33,9 @@ type resolveBooleanEvalFields struct { result bool variant string reason string - err error } -func TestGRPCService_UnixConnection(t *testing.T) { +func TestConnectService_UnixConnection(t *testing.T) { type evalFields struct { result bool variant string @@ -61,7 +61,7 @@ func TestGRPCService_UnixConnection(t *testing.T) { err: nil, }, req: &gen.ResolveBooleanRequest{ - FlagKey: "bool", + FlagKey: "myBoolFlag", Context: &structpb.Struct{}, }, want: &gen.ResolveBooleanResponse{ @@ -82,8 +82,8 @@ func TestGRPCService_UnixConnection(t *testing.T) { tt.evalFields.reason, tt.evalFields.err, ).AnyTimes() - service := service.GRPCService{ - GRPCServiceConfiguration: &service.GRPCServiceConfiguration{ + service := service.ConnectService{ + ConnectServiceConfiguration: &service.ConnectServiceConfiguration{ ServerSocketPath: tt.socketPath, }, } @@ -92,11 +92,11 @@ func TestGRPCService_UnixConnection(t *testing.T) { defer cancel() go func() { _ = service.Serve(ctx, eval) }() - conn, err := grpc.Dial( - fmt.Sprintf("passthrough:///unix://%s", tt.socketPath), + fmt.Sprintf("unix://%s", tt.socketPath), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock(), + grpc.WithTimeout(2*time.Second), ) if err != nil { log.Errorf("grpc - fail to dial: %v", err) @@ -107,32 +107,30 @@ func TestGRPCService_UnixConnection(t *testing.T) { ) res, err := client.ResolveBoolean(ctx, tt.req) if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveBoolean() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ConnectService.ResolveBoolean() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(res.Reason, tt.want.Reason) { - t.Errorf("GRPCService.ResolveBoolean() = %v, want %v", res, tt.want) + t.Errorf("ConnectService.ResolveBoolean() = %v, want %v", res, tt.want) } if !reflect.DeepEqual(res.Value, tt.want.Value) { - t.Errorf("GRPCService.ResolveBoolean() = %v, want %v", res, tt.want) + t.Errorf("ConnectService.ResolveBoolean() = %v, want %v", res, tt.want) } if !reflect.DeepEqual(res.Variant, tt.want.Variant) { - t.Errorf("GRPCService.ResolveBoolean() = %v, want %v", res, tt.want) + t.Errorf("ConnectService.ResolveBoolean() = %v, want %v", res, tt.want) } }) } } -func TestGRPCService_ResolveBoolean(t *testing.T) { +func TestConnectService_ResolveBoolean(t *testing.T) { ctrl := gomock.NewController(t) - grpcS := service.GRPCService{} tests := map[string]resolveBooleanArgs{ "happy path": { evalFields: resolveBooleanEvalFields{ result: true, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveBooleanFunctionArgs{ context.Background(), @@ -152,8 +150,7 @@ func TestGRPCService_ResolveBoolean(t *testing.T) { evalFields: resolveBooleanEvalFields{ result: true, variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), + reason: model.ErrorReason, }, functionArgs: resolveBooleanFunctionArgs{ context.Background(), @@ -162,8 +159,10 @@ func TestGRPCService_ResolveBoolean(t *testing.T) { Context: &structpb.Struct{}, }, }, - want: &gen.ResolveBooleanResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), + want: &gen.ResolveBooleanResponse{ + Reason: model.ErrorReason, + }, + wantErr: errors.New("eval interface error"), }, } for name, tt := range tests { @@ -173,33 +172,31 @@ func TestGRPCService_ResolveBoolean(t *testing.T) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } - got, err := s.ResolveBoolean(tt.functionArgs.ctx, tt.functionArgs.req) - if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveBoolean() error = %v, wantErr %v", err, tt.wantErr) + got, err := s.ResolveBoolean(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) + if err != nil && !errors.Is(err, tt.wantErr) { + t.Errorf("ConnectService.ResolveBoolean() error = %v, wantErr %v", err.Error(), tt.wantErr.Error()) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GRPCService.ResolveBoolean() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + t.Errorf("ConnectService.ResolveBoolean() = %v, want %v", got, tt.want) } }) } } -func BenchmarkGRPCService_ResolveBoolean(b *testing.B) { +func BenchmarkConnectService_ResolveBoolean(b *testing.B) { ctrl := gomock.NewController(b) - grpcS := service.GRPCService{} tests := map[string]resolveBooleanArgs{ "happy path": { evalFields: resolveBooleanEvalFields{ result: true, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveBooleanFunctionArgs{ context.Background(), @@ -215,23 +212,6 @@ func BenchmarkGRPCService_ResolveBoolean(b *testing.B) { }, wantErr: nil, }, - "eval returns error": { - evalFields: resolveBooleanEvalFields{ - result: true, - variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), - }, - functionArgs: resolveBooleanFunctionArgs{ - context.Background(), - &gen.ResolveBooleanRequest{ - FlagKey: "bool", - Context: &structpb.Struct{}, - }, - }, - want: &gen.ResolveBooleanResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), - }, } for name, tt := range tests { eval := NewMockIEvaluator(ctrl) @@ -239,20 +219,20 @@ func BenchmarkGRPCService_ResolveBoolean(b *testing.B) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - got, err := s.ResolveBoolean(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveBoolean(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - b.Errorf("GRPCService.ResolveBoolean() error = %v, wantErr %v", err, tt.wantErr) + b.Errorf("ConnectService.ResolveBoolean() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - b.Errorf("GRPCService.ResolveBoolean() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + b.Errorf("ConnectService.ResolveBoolean() = %v, want %v", got, tt.want) } } }) @@ -273,19 +253,16 @@ type resolveStringEvalFields struct { result string variant string reason string - err error } -func TestGRPCService_ResolveString(t *testing.T) { +func TestConnectService_ResolveString(t *testing.T) { ctrl := gomock.NewController(t) - grpcS := service.GRPCService{} tests := map[string]resolveStringArgs{ "happy path": { evalFields: resolveStringEvalFields{ result: "true", variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveStringFunctionArgs{ context.Background(), @@ -305,8 +282,7 @@ func TestGRPCService_ResolveString(t *testing.T) { evalFields: resolveStringEvalFields{ result: "true", variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), + reason: model.ErrorReason, }, functionArgs: resolveStringFunctionArgs{ context.Background(), @@ -315,8 +291,10 @@ func TestGRPCService_ResolveString(t *testing.T) { Context: &structpb.Struct{}, }, }, - want: &gen.ResolveStringResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), + want: &gen.ResolveStringResponse{ + Reason: model.ErrorReason, + }, + wantErr: errors.New("eval interface error"), }, } for name, tt := range tests { @@ -326,33 +304,31 @@ func TestGRPCService_ResolveString(t *testing.T) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ) - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } - got, err := s.ResolveString(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveString(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveString() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ConnectService.ResolveString() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GRPCService.ResolveString() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + t.Errorf("ConnectService.ResolveString() = %v, want %v", got, tt.want) } }) } } -func BenchmarkGRPCService_ResolveString(b *testing.B) { +func BenchmarkConnectService_ResolveString(b *testing.B) { ctrl := gomock.NewController(b) - grpcS := service.GRPCService{} tests := map[string]resolveStringArgs{ "happy path": { evalFields: resolveStringEvalFields{ result: "true", variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveStringFunctionArgs{ context.Background(), @@ -368,23 +344,6 @@ func BenchmarkGRPCService_ResolveString(b *testing.B) { }, wantErr: nil, }, - "eval returns error": { - evalFields: resolveStringEvalFields{ - result: "true", - variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), - }, - functionArgs: resolveStringFunctionArgs{ - context.Background(), - &gen.ResolveStringRequest{ - FlagKey: "string", - Context: &structpb.Struct{}, - }, - }, - want: &gen.ResolveStringResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), - }, } for name, tt := range tests { eval := NewMockIEvaluator(ctrl) @@ -392,20 +351,20 @@ func BenchmarkGRPCService_ResolveString(b *testing.B) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - got, err := s.ResolveString(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveString(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - b.Errorf("GRPCService.ResolveString() error = %v, wantErr %v", err, tt.wantErr) + b.Errorf("ConnectService.ResolveString() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - b.Errorf("GRPCService.ResolveString() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + b.Errorf("ConnectService.ResolveString() = %v, want %v", got, tt.want) } } }) @@ -426,19 +385,16 @@ type resolveFloatEvalFields struct { result float64 variant string reason string - err error } -func TestGRPCService_ResolveFloat(t *testing.T) { +func TestConnectService_ResolveFloat(t *testing.T) { ctrl := gomock.NewController(t) - grpcS := service.GRPCService{} tests := map[string]resolveFloatArgs{ "happy path": { evalFields: resolveFloatEvalFields{ result: 12, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveFloatFunctionArgs{ context.Background(), @@ -458,8 +414,7 @@ func TestGRPCService_ResolveFloat(t *testing.T) { evalFields: resolveFloatEvalFields{ result: 12, variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), + reason: model.ErrorReason, }, functionArgs: resolveFloatFunctionArgs{ context.Background(), @@ -468,8 +423,10 @@ func TestGRPCService_ResolveFloat(t *testing.T) { Context: &structpb.Struct{}, }, }, - want: &gen.ResolveFloatResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), + want: &gen.ResolveFloatResponse{ + Reason: model.ErrorReason, + }, + wantErr: errors.New("eval interface error"), }, } for name, tt := range tests { @@ -479,33 +436,31 @@ func TestGRPCService_ResolveFloat(t *testing.T) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } - got, err := s.ResolveFloat(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveFloat(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ConnectService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GRPCService.ResolveNumber() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + t.Errorf("ConnectService.ResolveNumber() = %v, want %v", got, tt.want) } }) } } -func BenchmarkGRPCService_ResolveFloat(b *testing.B) { +func BenchmarkConnectService_ResolveFloat(b *testing.B) { ctrl := gomock.NewController(b) - grpcS := service.GRPCService{} tests := map[string]resolveFloatArgs{ "happy path": { evalFields: resolveFloatEvalFields{ result: 12, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveFloatFunctionArgs{ context.Background(), @@ -521,23 +476,6 @@ func BenchmarkGRPCService_ResolveFloat(b *testing.B) { }, wantErr: nil, }, - "eval returns error": { - evalFields: resolveFloatEvalFields{ - result: 12, - variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), - }, - functionArgs: resolveFloatFunctionArgs{ - context.Background(), - &gen.ResolveFloatRequest{ - FlagKey: "float", - Context: &structpb.Struct{}, - }, - }, - want: &gen.ResolveFloatResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), - }, } for name, tt := range tests { eval := NewMockIEvaluator(ctrl) @@ -545,20 +483,20 @@ func BenchmarkGRPCService_ResolveFloat(b *testing.B) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - got, err := s.ResolveFloat(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveFloat(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - b.Errorf("GRPCService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) + b.Errorf("ConnectService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - b.Errorf("GRPCService.ResolveNumber() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + b.Errorf("ConnectService.ResolveNumber() = %v, want %v", got, tt.want) } } }) @@ -579,19 +517,16 @@ type resolveIntEvalFields struct { result int64 variant string reason string - err error } -func TestGRPCService_ResolveInt(t *testing.T) { +func TestConnectService_ResolveInt(t *testing.T) { ctrl := gomock.NewController(t) - grpcS := service.GRPCService{} tests := map[string]resolveIntArgs{ "happy path": { evalFields: resolveIntEvalFields{ result: 12, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveIntFunctionArgs{ context.Background(), @@ -611,8 +546,7 @@ func TestGRPCService_ResolveInt(t *testing.T) { evalFields: resolveIntEvalFields{ result: 12, variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), + reason: model.ErrorReason, }, functionArgs: resolveIntFunctionArgs{ context.Background(), @@ -621,8 +555,10 @@ func TestGRPCService_ResolveInt(t *testing.T) { Context: &structpb.Struct{}, }, }, - want: &gen.ResolveIntResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), + want: &gen.ResolveIntResponse{ + Reason: model.ErrorReason, + }, + wantErr: errors.New("eval interface error"), }, } for name, tt := range tests { @@ -632,33 +568,31 @@ func TestGRPCService_ResolveInt(t *testing.T) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } - got, err := s.ResolveInt(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveInt(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ConnectService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GRPCService.ResolveNumber() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + t.Errorf("ConnectService.ResolveNumber() = %v, want %v", got, tt.want) } }) } } -func BenchmarkGRPCService_ResolveInt(b *testing.B) { +func BenchmarkConnectService_ResolveInt(b *testing.B) { ctrl := gomock.NewController(b) - grpcS := service.GRPCService{} tests := map[string]resolveIntArgs{ "happy path": { evalFields: resolveIntEvalFields{ result: 12, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveIntFunctionArgs{ context.Background(), @@ -674,23 +608,6 @@ func BenchmarkGRPCService_ResolveInt(b *testing.B) { }, wantErr: nil, }, - "eval returns error": { - evalFields: resolveIntEvalFields{ - result: 12, - variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), - }, - functionArgs: resolveIntFunctionArgs{ - context.Background(), - &gen.ResolveIntRequest{ - FlagKey: "int", - Context: &structpb.Struct{}, - }, - }, - want: &gen.ResolveIntResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), - }, } for name, tt := range tests { eval := NewMockIEvaluator(ctrl) @@ -698,20 +615,20 @@ func BenchmarkGRPCService_ResolveInt(b *testing.B) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - got, err := s.ResolveInt(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveInt(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - b.Errorf("GRPCService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) + b.Errorf("ConnectService.ResolveNumber() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - b.Errorf("GRPCService.ResolveNumber() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg, tt.want) { + b.Errorf("ConnectService.ResolveNumber() = %v, want %v", got, tt.want) } } }) @@ -732,12 +649,10 @@ type resolveObjectEvalFields struct { result map[string]interface{} variant string reason string - err error } -func TestGRPCService_ResolveObject(t *testing.T) { +func TestConnectService_ResolveObject(t *testing.T) { ctrl := gomock.NewController(t) - grpcS := service.GRPCService{} tests := map[string]resolveObjectArgs{ "happy path": { evalFields: resolveObjectEvalFields{ @@ -746,7 +661,6 @@ func TestGRPCService_ResolveObject(t *testing.T) { }, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveObjectFunctionArgs{ context.Background(), @@ -768,8 +682,7 @@ func TestGRPCService_ResolveObject(t *testing.T) { "food": "bars", }, variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), + reason: model.ErrorReason, }, functionArgs: resolveObjectFunctionArgs{ context.Background(), @@ -778,8 +691,10 @@ func TestGRPCService_ResolveObject(t *testing.T) { Context: &structpb.Struct{}, }, }, - want: &gen.ResolveObjectResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), + want: &gen.ResolveObjectResponse{ + Reason: model.ErrorReason, + }, + wantErr: errors.New("eval interface error"), }, } for name, tt := range tests { @@ -789,9 +704,9 @@ func TestGRPCService_ResolveObject(t *testing.T) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } @@ -802,21 +717,20 @@ func TestGRPCService_ResolveObject(t *testing.T) { } tt.want.Value = outParsed } - got, err := s.ResolveObject(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveObject(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - t.Errorf("GRPCService.ResolveObject() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ConnectService.ResolveObject() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got.Value.AsMap(), tt.want.Value.AsMap()) { - t.Errorf("GRPCService.ResolveObject() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg.Value.AsMap(), tt.want.Value.AsMap()) { + t.Errorf("ConnectService.ResolveObject() = %v, want %v", got, tt.want) } }) } } -func BenchmarkGRPCService_ResolveObject(b *testing.B) { +func BenchmarkConnectService_ResolveObject(b *testing.B) { ctrl := gomock.NewController(b) - grpcS := service.GRPCService{} tests := map[string]resolveObjectArgs{ "happy path": { evalFields: resolveObjectEvalFields{ @@ -825,7 +739,6 @@ func BenchmarkGRPCService_ResolveObject(b *testing.B) { }, variant: "on", reason: model.DefaultReason, - err: nil, }, functionArgs: resolveObjectFunctionArgs{ context.Background(), @@ -841,25 +754,6 @@ func BenchmarkGRPCService_ResolveObject(b *testing.B) { }, wantErr: nil, }, - "eval returns error": { - evalFields: resolveObjectEvalFields{ - result: map[string]interface{}{ - "food": "bars", - }, - variant: ":(", - reason: "ERROR", - err: errors.New("eval interface error"), - }, - functionArgs: resolveObjectFunctionArgs{ - context.Background(), - &gen.ResolveObjectRequest{ - FlagKey: "object", - Context: &structpb.Struct{}, - }, - }, - want: &gen.ResolveObjectResponse{}, - wantErr: grpcS.HandleEvaluationError(errors.New("eval interface error"), "ERROR"), - }, } for name, tt := range tests { eval := NewMockIEvaluator(ctrl) @@ -867,9 +761,9 @@ func BenchmarkGRPCService_ResolveObject(b *testing.B) { tt.evalFields.result, tt.evalFields.variant, tt.evalFields.reason, - tt.evalFields.err, + tt.wantErr, ).AnyTimes() - s := service.GRPCService{ + s := service.ConnectService{ Eval: eval, } if name != "eval returns error" { @@ -881,13 +775,13 @@ func BenchmarkGRPCService_ResolveObject(b *testing.B) { } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - got, err := s.ResolveObject(tt.functionArgs.ctx, tt.functionArgs.req) + got, err := s.ResolveObject(tt.functionArgs.ctx, connect.NewRequest(tt.functionArgs.req)) if (err != nil) && !errors.Is(err, tt.wantErr) { - b.Errorf("GRPCService.ResolveObject() error = %v, wantErr %v", err, tt.wantErr) + b.Errorf("ConnectService.ResolveObject() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got.Value.AsMap(), tt.want.Value.AsMap()) { - b.Errorf("GRPCService.ResolveObject() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got.Msg.Value.AsMap(), tt.want.Value.AsMap()) { + b.Errorf("ConnectService.ResolveObject() = %v, want %v", got, tt.want) } } }) diff --git a/pkg/service/grpc_service.go b/pkg/service/grpc_service.go deleted file mode 100644 index 3adaa3190..000000000 --- a/pkg/service/grpc_service.go +++ /dev/null @@ -1,171 +0,0 @@ -package service - -import ( - "context" - "fmt" - "net" - - "github.com/open-feature/flagd/pkg/eval" - "github.com/open-feature/flagd/pkg/model" - log "github.com/sirupsen/logrus" - gen "go.buf.build/open-feature/flagd-server/open-feature/flagd/schema/v1" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/structpb" -) - -type GRPCServiceConfiguration struct { - Port int32 - ServerKeyPath string - ServerCertPath string - ServerSocketPath string -} - -type GRPCService struct { - GRPCServiceConfiguration *GRPCServiceConfiguration - Eval eval.IEvaluator - gen.UnimplementedServiceServer - Logger *log.Entry -} - -// Serve allows for the use of GRPC only without HTTP, where as HTTP service enables both -// GRPC and HTTP -func (s *GRPCService) Serve(ctx context.Context, eval eval.IEvaluator) error { - var lis net.Listener - var err error - g, gCtx := errgroup.WithContext(ctx) - s.Eval = eval - - // TLS - var serverOpts []grpc.ServerOption - if s.GRPCServiceConfiguration.ServerCertPath != "" && s.GRPCServiceConfiguration.ServerKeyPath != "" { - config, err := loadTLSConfig(s.GRPCServiceConfiguration.ServerCertPath, s.GRPCServiceConfiguration.ServerKeyPath) - if err != nil { - return err - } - serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(config))) - } - - grpcServer := grpc.NewServer(serverOpts...) - gen.RegisterServiceServer(grpcServer, s) - - if s.GRPCServiceConfiguration.ServerSocketPath != "" { - lis, err = net.Listen("unix", s.GRPCServiceConfiguration.ServerSocketPath) - } else { - lis, err = net.Listen("tcp", fmt.Sprintf(":%d", s.GRPCServiceConfiguration.Port)) - } - if err != nil { - return err - } - - g.Go(func() error { - return grpcServer.Serve(lis) - }) - <-gCtx.Done() - grpcServer.GracefulStop() - return nil -} - -// TODO: might be able to simplify some of this with generics. -func (s *GRPCService) ResolveBoolean( - ctx context.Context, - req *gen.ResolveBooleanRequest, -) (*gen.ResolveBooleanResponse, error) { - res := gen.ResolveBooleanResponse{} - result, variant, reason, err := s.Eval.ResolveBooleanValue(req.GetFlagKey(), req.GetContext()) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - res.Reason = reason - res.Value = result - res.Variant = variant - return &res, nil -} - -func (s *GRPCService) ResolveString( - ctx context.Context, - req *gen.ResolveStringRequest, -) (*gen.ResolveStringResponse, error) { - res := gen.ResolveStringResponse{} - result, variant, reason, err := s.Eval.ResolveStringValue(req.GetFlagKey(), req.GetContext()) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - res.Reason = reason - res.Value = result - res.Variant = variant - return &res, nil -} - -func (s *GRPCService) ResolveInt( - ctx context.Context, - req *gen.ResolveIntRequest, -) (*gen.ResolveIntResponse, error) { - res := gen.ResolveIntResponse{} - result, variant, reason, err := s.Eval.ResolveIntValue(req.GetFlagKey(), req.GetContext()) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - res.Reason = reason - res.Value = result - res.Variant = variant - return &res, nil -} - -func (s *GRPCService) ResolveFloat( - ctx context.Context, - req *gen.ResolveFloatRequest, -) (*gen.ResolveFloatResponse, error) { - res := gen.ResolveFloatResponse{} - result, variant, reason, err := s.Eval.ResolveFloatValue(req.GetFlagKey(), req.GetContext()) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - res.Reason = reason - res.Value = result - res.Variant = variant - return &res, nil -} - -func (s *GRPCService) ResolveObject( - ctx context.Context, - req *gen.ResolveObjectRequest, -) (*gen.ResolveObjectResponse, error) { - res := gen.ResolveObjectResponse{} - result, variant, reason, err := s.Eval.ResolveObjectValue(req.GetFlagKey(), req.GetContext()) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - val, err := structpb.NewStruct(result) - if err != nil { - return &res, s.HandleEvaluationError(err, reason) - } - res.Reason = reason - res.Value = val - res.Variant = variant - return &res, nil -} - -func (s *GRPCService) HandleEvaluationError(err error, reason string) error { - statusCode := codes.Internal - message := err.Error() - switch message { - case model.FlagNotFoundErrorCode: - statusCode = codes.NotFound - case model.TypeMismatchErrorCode: - statusCode = codes.InvalidArgument - } - st := status.New(statusCode, message) - stWD, err := st.WithDetails(&gen.ErrorResponse{ - ErrorCode: message, - Reason: "ERROR", - }) - if err != nil { - s.Logger.Error(err) - return st.Err() - } - return stWD.Err() -} diff --git a/pkg/service/http_service.go b/pkg/service/http_service.go deleted file mode 100644 index c12d89ca5..000000000 --- a/pkg/service/http_service.go +++ /dev/null @@ -1,194 +0,0 @@ -package service - -import ( - "context" - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "net" - "net/http" - "time" - - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/open-feature/flagd/pkg/eval" - log "github.com/sirupsen/logrus" - "github.com/soheilhy/cmux" - gen "go.buf.build/open-feature/flagd-server/open-feature/flagd/schema/v1" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" -) - -type HTTPServiceConfiguration struct { - Port int32 - ServerCertPath string - ServerKeyPath string - ServerSocketPath string -} - -type HTTPService struct { - HTTPServiceConfiguration *HTTPServiceConfiguration - GRPCService *GRPCService - Logger *log.Entry -} - -func (s *HTTPService) tlsListener(l net.Listener) net.Listener { - // Load TLS config - config, err := loadTLSConfig(s.HTTPServiceConfiguration.ServerCertPath, - s.HTTPServiceConfiguration.ServerKeyPath) - if err != nil { - log.Fatal(err) - } - - tlsl := tls.NewListener(l, config) - return tlsl -} - -func (s *HTTPService) ServerGRPC(ctx context.Context, mux *runtime.ServeMux) *grpc.Server { - var address string - var dialOpts []grpc.DialOption - var err error - // handle cert - if s.HTTPServiceConfiguration.ServerCertPath != "" && s.HTTPServiceConfiguration.ServerKeyPath != "" { - tlsCreds, err := loadTLSCredentials(s.HTTPServiceConfiguration.ServerCertPath, - s.HTTPServiceConfiguration.ServerKeyPath) - if err != nil { - log.Fatal(err) - } - dialOpts = append(dialOpts, grpc.WithTransportCredentials(tlsCreds)) - } else { - dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) - } - // handle unix socket - if s.HTTPServiceConfiguration.ServerSocketPath != "" { - address = s.HTTPServiceConfiguration.ServerSocketPath - dialOpts = append(dialOpts, grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) { - return net.Dial("unix", addr) - })) - } else { - address = net.JoinHostPort("localhost", fmt.Sprintf("%d", s.HTTPServiceConfiguration.Port)) - } - grpcServer := grpc.NewServer() - gen.RegisterServiceServer(grpcServer, s.GRPCService) - err = gen.RegisterServiceHandlerFromEndpoint( - ctx, - mux, - address, - dialOpts, - ) - if err != nil { - log.Fatal(err) - } - return grpcServer -} - -func (s *HTTPService) ServeHTTP(mux *runtime.ServeMux) *http.Server { - server := &http.Server{ - Handler: mux, - ReadHeaderTimeout: 60 * time.Second, - } - - return server -} - -func (s *HTTPService) Serve(ctx context.Context, eval eval.IEvaluator) error { - s.GRPCService.Eval = eval - g, gCtx := errgroup.WithContext(ctx) - // Mux Setup - mux := runtime.NewServeMux( - runtime.WithErrorHandler(s.HTTPErrorHandler), - ) - // GRPC Setup - grpcServer := s.ServerGRPC(ctx, mux) - // HTTP Setup - httpServer := s.ServeHTTP(mux) - // Net listener - l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.HTTPServiceConfiguration.Port)) - if err != nil { - return err - } - tcpm := cmux.New(l) - // We first match on HTTP 1.1 methods. - httpl := tcpm.Match(cmux.HTTP1Fast()) - // If not matched, we assume that its TLS. - tlsl := tcpm.Match(cmux.Any()) - if s.HTTPServiceConfiguration.ServerCertPath != "" && s.HTTPServiceConfiguration.ServerKeyPath != "" { - tlsl = s.tlsListener(tlsl) - } - // Now, we build another mux recursively to match HTTPS and GoRPC. - tlsm := cmux.New(tlsl) - httpsl := tlsm.Match(cmux.HTTP1Fast()) - var gorpcl net.Listener - if s.HTTPServiceConfiguration.ServerSocketPath != "" { - gorpcl, err = net.Listen("unix", s.HTTPServiceConfiguration.ServerSocketPath) - if err != nil { - return err - } - } else { - gorpcl = tlsm.Match(cmux.Any()) - } - g.Go(func() error { - return httpServer.Serve(httpl) // HTTP - }) - g.Go(func() error { - return httpServer.Serve(httpsl) // HTTPS - }) - g.Go(func() error { - return grpcServer.Serve(gorpcl) // GRPC - }) - g.Go(func() error { - return tlsm.Serve() - }) - g.Go(func() error { - return tcpm.Serve() - }) - <-gCtx.Done() - grpcServer.GracefulStop() - if err = httpServer.Shutdown(context.Background()); err != nil { - return err - } - err = g.Wait() - if err != nil && !errors.Is(err, grpc.ErrServerStopped) && !errors.Is(err, http.ErrServerClosed) { - return err - } - return nil -} - -func (s HTTPService) HTTPErrorHandler( - ctx context.Context, - m *runtime.ServeMux, - ma runtime.Marshaler, - w http.ResponseWriter, - r *http.Request, - err error, -) { - st := status.Convert(err) - switch { - case st.Code() == codes.Unknown: - w.WriteHeader(http.StatusInternalServerError) - case st.Code() == codes.InvalidArgument: - w.WriteHeader(http.StatusBadRequest) - case st.Code() == codes.NotFound: - w.WriteHeader(http.StatusNotFound) - default: - w.WriteHeader(http.StatusInternalServerError) - } - details := st.Details() - if len(details) != 1 { - log.Error(err) - log.Errorf("malformed error received by error handler, details received: %d - %v", len(details), details) - return - } - var res []byte - if res, err = json.Marshal(details[0]); err != nil { - log.Error(err) - return - } - if _, err = w.Write(res); err != nil { - log.Error(err) - return - } -} diff --git a/pkg/service/utils.go b/pkg/service/utils.go deleted file mode 100644 index 78b956ed5..000000000 --- a/pkg/service/utils.go +++ /dev/null @@ -1,34 +0,0 @@ -package service - -import ( - "crypto/rand" - "crypto/tls" - - "google.golang.org/grpc/credentials" -) - -func loadTLSCredentials(serverCertPath string, serverKeyPath string) (credentials.TransportCredentials, error) { - // Load server's certificate and private key - creds, err := credentials.NewServerTLSFromFile(serverCertPath, serverKeyPath) - if err != nil { - return nil, err - } - - return creds, nil -} - -func loadTLSConfig(certPath, keyPath string) (*tls.Config, error) { - certificate, err := tls.LoadX509KeyPair(certPath, - keyPath) - if err != nil { - return nil, err - } - - config := &tls.Config{ - Certificates: []tls.Certificate{certificate}, - Rand: rand.Reader, - MinVersion: tls.VersionTLS12, - } - - return config, nil -}