diff --git a/.dockerignore b/.dockerignore index c76491c113..c5a20b6996 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,9 +10,9 @@ *.out *.test +.devcontainer/ .github/ .vscode/ -.licenses/ .task/ Dockerfile LICENSE diff --git a/.github/actions/integration-test/action.yml b/.github/actions/integration-test/action.yml index b034aa2e50..72562123e5 100644 --- a/.github/actions/integration-test/action.yml +++ b/.github/actions/integration-test/action.yml @@ -2,11 +2,15 @@ name: "Flipt IT Tests" description: "Container for running Flipt ITs" inputs: - args: # id of input - description: args to pass to container' + script: # id of input + description: "script to run in the container" required: true + config: # id of input + description: "optional config file" + required: false runs: using: "docker" image: "docker://ghcr.io/flipt-io/flipt-integration-test" args: - - ${{ inputs.args }} + - ${{ inputs.script }} + - ${{ inputs.config }} diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index d974b6e834..42aec2b396 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -21,8 +21,8 @@ on: workflow_dispatch: jobs: - test: - name: Test + build: + name: Build runs-on: ubuntu-latest timeout-minutes: 20 @@ -32,7 +32,16 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: "1.17.x" + go-version: "1.17" + check-latest: true + cache: true + + - uses: actions/cache@v3 + with: + path: _tools/ + key: ${{ runner.os }}-go-tools${{ hashFiles('_tools/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-tools- - uses: actions/setup-node@v3 with: @@ -42,30 +51,124 @@ jobs: - uses: arduino/setup-task@v1 - - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Build the binary run: | task - - name: Test API + - name: Upload the binary + uses: actions/upload-artifact@v3 + with: + name: flipt + path: bin/flipt + if-no-files-found: error + retention-days: 1 + + api: + needs: build + name: Test API + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v3 + id: download + with: + name: flipt + path: bin/ + + - run: chmod +x flipt + working-directory: bin/ + + - name: Run API tests + uses: ./.github/actions/integration-test + with: + script: ./test/api.sh + + - name: Upload the log + uses: actions/upload-artifact@v3 + with: + name: api.log + path: out.log + retention-days: 5 + + redis: + needs: build + name: Test Redis + runs-on: ubuntu-latest + + services: + redis: + image: redis + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v3 + id: download + with: + name: flipt + path: bin/ + + - run: chmod +x flipt + working-directory: bin/ + + - name: Run API tests uses: ./.github/actions/integration-test with: - args: ./test/api.sh + script: ./test/api.sh + config: "redis.yml" - - name: Test CLI + - name: Upload the log + uses: actions/upload-artifact@v3 + with: + name: redis.log + path: out.log + retention-days: 5 + + cli: + needs: build + name: Test CLI + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v3 + with: + name: flipt + path: bin/ + + - run: chmod +x flipt + working-directory: bin/ + + - name: Run CLI tests uses: ./.github/actions/integration-test with: - args: ./test/cli.bats + script: ./test/cli.bats + + ui: + needs: build + name: Test UI + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v3 + with: + name: flipt + path: bin/ + + - run: chmod +x flipt + working-directory: bin/ - - name: Test UI + - name: Run UI tests uses: ./.github/actions/integration-test with: - args: ./test/ui.sh + script: ./test/ui.sh diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 25682d059f..6252b40883 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -21,24 +21,6 @@ on: workflow_dispatch: jobs: - sleuth: - name: Nancy - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - uses: actions/setup-go@v3 - with: - go-version: "1.17.x" - - - run: go list -json -m all > go.list - - - name: Nancy - uses: sonatype-nexus-community/nancy-github-action@main - gitleaks: name: Gitleaks runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 16adc88c66..91aee376a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,9 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: "1.17.x" + go-version: "1.17" + check-latest: true + cache: true - name: golangci-lint uses: golangci/golangci-lint-action@v3.2.0 @@ -37,21 +39,12 @@ jobs: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. version: v1.44 - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true - test: name: Test runs-on: ubuntu-latest strategy: matrix: - go: ["1.17.x", "1.18.x"] + go: ["1.17", "1.18"] steps: - uses: actions/checkout@v3 @@ -59,15 +52,8 @@ jobs: - uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - - - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + check-latest: true + cache: true - name: Unit Test (SQLite) run: go test -race -covermode=atomic -coverprofile=coverage.txt -count=1 ./... diff --git a/.gitignore b/.gitignore index a9843a5ce4..ec09ed9a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ _test !**/**/testdata/**/*.pem bin +pkg benchmark coverage.txt dist @@ -36,4 +37,4 @@ __debug_bin Brewfile.lock.json *.key -.task/ +.task/ \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index 3e5c0102c6..e984406fd8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -47,6 +47,7 @@ linters: - unparam - varcheck disable: + - contextcheck - exhaustive - rowserrcheck enable-all: false @@ -61,17 +62,6 @@ issues: # excluded by default patterns execute `golangci-lint run --help` exclude: - "composite literal uses unkeyed fields" - exclude-rules: - # Exclude some staticcheck messages - - linters: - - staticcheck - text: "SA1019: package github.com/golang/protobuf" - - linters: - - staticcheck - text: "SA1019: ptypes." - - linters: - - staticcheck - text: "SA1019: proto." linters-settings: depguard: @@ -79,3 +69,11 @@ linters-settings: include-go-root: false packages: - github.com/pkg/errors + staticcheck: + checks: + - all + - "-SA1019" # exclude staticcheck messages from github.com/golang/protobuf + gosec: + excludes: # exclude gosec messages about weak crypto + - "G501" + - "G401" diff --git a/Brewfile b/Brewfile index b65bb020df..3c8107dd2a 100644 --- a/Brewfile +++ b/Brewfile @@ -1,15 +1,12 @@ -tap 'filosottile/musl-cross' tap 'goreleaser/tap' +tap 'go-task/tap' tap 'anchore/syft' -brew 'cmake' brew 'cosign' brew 'go' brew 'goreleaser' +brew 'go-task' brew 'hadolint' -brew 'minikube' -brew 'musl-cross' -brew 'pkg-config' brew 'protobuf' brew 'sqlite' brew 'syft' \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d82db5c089..df9bcb9c8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Redis cache support :tada: [https://github.com/markphelps/flipt/issues/633](https://github.com/markphelps/flipt/issues/633) +- Support for pretty printing JSON responses from API (via ?pretty=true or setting `Accept: application/json+pretty` header) +- Configuration warnings/deprecations are displayed in console at startup + +### Changed + +- Ping database on startup to check if it's alive +- Default cache TTL is 1m. Previously there was no TTL for the in memory cache. + +### Deprecated + +- `cache.memory.enabled` config value is deprecated. See [Deprecations](DEPRECATIONS.md) for more info +- `cache.memory.expiration` config value is deprecated. See [Deprecations](DEPRECATIONS.md) for more info + ### Fixed - Build date was incorrect and always showed current date/time diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md new file mode 100644 index 0000000000..db9cbf7f6a --- /dev/null +++ b/DEPRECATIONS.md @@ -0,0 +1,80 @@ +# Deprecation Notices + +This page is used to list deprecation notices for Flipt. + +Deprecated configuration options will be removed after ~6 months from the time they were deprecated. + +## Active Deprecations + + + +### cache.memory.enabled + +> since [v1.10.0](https://github.com/markphelps/flipt/releases/tag/v1.10.0) + +Enabling in-memory cache via `cache.memory` is deprecated in favor of setting the `cache.backend` to `memory` and `cache.enabled` to `true`. + +=== Before + + ``` yaml + cache: + memory: + enabled: true + ``` + +=== After + + ``` yaml + cache: + enabled: true + backend: memory + ``` + +### cache.memory.expiration + +> since [v1.10.0](https://github.com/markphelps/flipt/releases/tag/v1.10.0) + +Setting cache expiration via `cache.memory` is deprecated in favor of setting the `cache.backend` to `memory` and `cache.ttl` to the desired duration. + +=== Before + + ``` yaml + cache: + memory: + expiration: 1m + ``` + +=== After + + ``` yaml + cache: + enabled: true + backend: memory + ttl: 1m + ``` + +## Expired Deprecation Notices + +The following options were deprecated in the past and were already removed. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 59f5874dbe..9955e39d56 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -11,6 +11,7 @@ Before starting, make sure you have the following installed: - [Go 1.17+](https://golang.org/doc/install) - [NodeJS >= 18](https://nodejs.org/en/) - [Task](https://taskfile.dev/#/) +- [Docker](https://docs.docker.com/install/) (for running tests) ## Setup @@ -33,9 +34,7 @@ The `bootstrap` task will install all of the necessary tools used for developmen Configuration for running when developing Flipt can be found at `./config/local.yml`. To run Flipt with this configuration, run: -```shell -task server -``` +`task server` or `task dev` ## Changes @@ -61,11 +60,11 @@ The [ui/README.md](https://github.com/flipt-io/flipt/tree/main/ui/README.md) has ## Building/Running -**Run `script/server` from the project root.** +**Run `task dev` from the project root.** Vite will rebuild the UI assets when applicable files in the `ui` folder change. See [ui/README.md](https://github.com/flipt-io/flipt/tree/main/ui/README.md) for more info. -You'll need to stop and re-run `script/server` for any changes in the server (Go) code :exclamation: +You'll need to stop and re-run for any changes in the server (Go) code :exclamation: ### Ports diff --git a/Taskfile.yml b/Taskfile.yml index 0095fee40a..b4a6c86636 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -11,8 +11,9 @@ tasks: desc: Build the binary deps: [prep] cmds: - - go build -trimpath -tags assets -ldflags "-X main.commit={{.GIT_COMMIT}} -X main.date={{.BUILD_DATE}}" --o ./bin/{{.PROJECT}} ./cmd/{{.PROJECT}}/. + - go build -trimpath -tags assets -ldflags "-X main.commit={{.GIT_COMMIT}} -X main.date={{.BUILD_DATE}}" -o {{.OUTPUT}}/{{.PROJECT}} ./cmd/{{.PROJECT}}/. vars: + OUTPUT: '{{default "./bin" .OUTPUT}}' GIT_COMMIT: sh: set -e && git rev-parse --verify HEAD || "" BUILD_DATE: @@ -25,6 +26,18 @@ tasks: - task: proto - task: assets + pkg: + desc: Package the binary + cmds: + - task: default + vars: { OUTPUT: "./pkg" } + - mkdir -p ./pkg/config/migrations + - cp -R ./config/migrations/ ./pkg/config/migrations/ + - cp ./config/*.yml ./pkg/config/ + vars: + GIT_COMMIT: + sh: set -e && git rev-parse --verify HEAD || "" + assets: desc: Build the UI deps: [assets:deps] @@ -74,7 +87,6 @@ tasks: build: desc: Run Go build - deps: [bootstrap] cmds: - go build -trimpath -tags assets -ldflags "-X main.commit={{.GIT_COMMIT}}" -o ./bin/{{.PROJECT}} ./cmd/{{.PROJECT}}/. vars: @@ -93,6 +105,11 @@ tasks: cmds: - buf generate + dev: + desc: Run the server and UI in development mode + cmds: + - script/server + server: desc: Start the server cmds: @@ -104,6 +121,8 @@ tasks: - go mod tidy - go clean -i {{.SOURCE_FILES}} - rm -rf dist/* + - rm -rf pkg/* + - rm -rf bin/* cover: desc: Run test coverage diff --git a/cmd/flipt/export.go b/cmd/flipt/export.go index 6d143d455b..d6e1a80df4 100644 --- a/cmd/flipt/export.go +++ b/cmd/flipt/export.go @@ -19,8 +19,7 @@ import ( var exportFilename string -func runExport(_ []string) error { - ctx := context.Background() +func runExport(ctx context.Context) error { ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/cmd/flipt/import.go b/cmd/flipt/import.go index 7fd601a7c9..8266b7c570 100644 --- a/cmd/flipt/import.go +++ b/cmd/flipt/import.go @@ -23,8 +23,7 @@ var ( importStdin bool ) -func runImport(args []string) error { - ctx := context.Background() +func runImport(ctx context.Context, args []string) error { ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/cmd/flipt/main.go b/cmd/flipt/main.go index ea295eb9fa..18e1f6e67c 100644 --- a/cmd/flipt/main.go +++ b/cmd/flipt/main.go @@ -36,9 +36,10 @@ import ( "go.flipt.io/flipt/internal/telemetry" pb "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/server" + "go.flipt.io/flipt/server/cache" + "go.flipt.io/flipt/server/cache/memory" + "go.flipt.io/flipt/server/cache/redis" "go.flipt.io/flipt/storage" - "go.flipt.io/flipt/storage/cache" - "go.flipt.io/flipt/storage/cache/memory" "go.flipt.io/flipt/storage/sql" "go.flipt.io/flipt/storage/sql/mysql" "go.flipt.io/flipt/storage/sql/postgres" @@ -50,6 +51,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/reflection" + "google.golang.org/protobuf/encoding/protojson" "gopkg.in/segmentio/analytics-go.v3" _ "github.com/golang-migrate/migrate/source/file" @@ -61,6 +63,8 @@ import ( grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" grpc_gateway "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + goredis_cache "github.com/go-redis/cache/v8" + goredis "github.com/go-redis/redis/v8" otgrpc "github.com/opentracing-contrib/go-grpc" "github.com/opentracing/opentracing-go" jaeger_config "github.com/uber/jaeger-client-go/config" @@ -89,8 +93,8 @@ func main() { Use: "flipt", Short: "Flipt is a modern feature flag solution", Version: version, - Run: func(cmd *cobra.Command, args []string) { - if err := run(args); err != nil { + Run: func(cmd *cobra.Command, _ []string) { + if err := run(cmd.Context()); err != nil { logrus.Error(err) logrus.Exit(1) } @@ -103,8 +107,8 @@ func main() { exportCmd = &cobra.Command{ Use: "export", Short: "Export flags/segments/rules to file/stdout", - Run: func(cmd *cobra.Command, args []string) { - if err := runExport(args); err != nil { + Run: func(cmd *cobra.Command, _ []string) { + if err := runExport(cmd.Context()); err != nil { logrus.Error(err) logrus.Exit(1) } @@ -115,7 +119,7 @@ func main() { Use: "import", Short: "Import flags/segments/rules from file", Run: func(cmd *cobra.Command, args []string) { - if err := runImport(args); err != nil { + if err := runImport(cmd.Context(), args); err != nil { logrus.Error(err) logrus.Exit(1) } @@ -125,7 +129,7 @@ func main() { migrateCmd = &cobra.Command{ Use: "migrate", Short: "Run pending database migrations", - Run: func(cmd *cobra.Command, args []string) { + Run: func(cmd *cobra.Command, _ []string) { migrator, err := sql.NewMigrator(*cfg, l) if err != nil { logrus.Error(err) @@ -218,11 +222,10 @@ func main() { logrus.Exit(0) } -func run(_ []string) error { +func run(ctx context.Context) error { color.Cyan(banner) fmt.Println() - ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -232,15 +235,15 @@ func run(_ []string) error { defer signal.Stop(interrupt) + shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer shutdownCancel() + var ( isRelease = isRelease() updateAvailable bool cv, lv semver.Version ) - shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer shutdownCancel() - if isRelease { var err error cv, err = semver.ParseTolerant(version) @@ -249,6 +252,11 @@ func run(_ []string) error { } } + // print out any warnings from config parsing + for _, warning := range cfg.Warnings { + l.Warn(warning) + } + if cfg.Meta.CheckForUpdates && isRelease { l.Debug("checking for updates...") @@ -308,7 +316,7 @@ func run(_ []string) error { defer ticker.Stop() - // start telemetry + // start telemetry if enabled g.Go(func() error { logger := l.WithField("component", "telemetry") @@ -355,6 +363,7 @@ func run(_ []string) error { httpServer *http.Server ) + // starts grpc server g.Go(func() error { logger := l.WithField("server", "grpc") @@ -387,6 +396,10 @@ func run(_ []string) error { defer db.Close() + if err := db.PingContext(ctx); err != nil { + return fmt.Errorf("pinging db: %w", err) + } + var store storage.Store switch driver { @@ -398,18 +411,7 @@ func run(_ []string) error { store = mysql.NewStore(db) } - if cfg.Cache.Memory.Enabled { - cacher := memory.NewCache(cfg.Cache.Memory.Expiration, cfg.Cache.Memory.EvictionInterval, logger) - if cfg.Cache.Memory.Expiration > 0 { - logger.Infof("in-memory cache enabled [expiration: %v, evictionInterval: %v]", cfg.Cache.Memory.Expiration, cfg.Cache.Memory.EvictionInterval) - } else { - logger.Info("in-memory cache enabled with no expiration") - } - - store = cache.NewStore(logger, cacher, store) - } - - logger = logger.WithField("store", store.String()) + logger.Debugf("store: %q enabled", store.String()) var tracer opentracing.Tracer = &opentracing.NoopTracer{} @@ -439,20 +441,52 @@ func run(_ []string) error { opentracing.SetGlobalTracer(tracer) - var ( - grpcOpts []grpc.ServerOption - srv = server.New(logger, store) - ) - - grpcOpts = append(grpcOpts, grpc_middleware.WithUnaryServerChain( + interceptors := []grpc.UnaryServerInterceptor{ grpc_recovery.UnaryServerInterceptor(), grpc_ctxtags.UnaryServerInterceptor(), grpc_logrus.UnaryServerInterceptor(logger), grpc_prometheus.UnaryServerInterceptor, otgrpc.OpenTracingServerInterceptor(tracer), - srv.ErrorUnaryInterceptor, - srv.ValidationUnaryInterceptor, - )) + server.ErrorUnaryInterceptor, + server.ValidationUnaryInterceptor, + server.EvaluationUnaryInterceptor, + } + + if cfg.Cache.Enabled { + var cacher cache.Cacher + + switch cfg.Cache.Backend { + case config.CacheMemory: + cacher = memory.NewCache(cfg.Cache) + case config.CacheRedis: + rdb := goredis.NewClient(&goredis.Options{ + Addr: fmt.Sprintf("%s:%d", cfg.Cache.Redis.Host, cfg.Cache.Redis.Port), + Password: cfg.Cache.Redis.Password, + DB: cfg.Cache.Redis.DB, + }) + + defer rdb.Shutdown(shutdownCtx) + + status := rdb.Ping(ctx) + if status == nil { + return errors.New("connecting to redis: no status") + } + + if status.Err() != nil { + return fmt.Errorf("connecting to redis: %w", status.Err()) + } + + cacher = redis.NewCache(cfg.Cache, goredis_cache.New(&goredis_cache.Options{ + Redis: rdb, + })) + } + + interceptors = append(interceptors, server.CacheUnaryInterceptor(cacher, logger)) + + logger.Debugf("cache: %q enabled", cacher.String()) + } + + grpcOpts := []grpc.ServerOption{grpc_middleware.WithUnaryServerChain(interceptors...)} if cfg.Server.Protocol == config.HTTPS { creds, err := credentials.NewServerTLSFromFile(cfg.Server.CertFile, cfg.Server.CertKey) @@ -463,7 +497,11 @@ func run(_ []string) error { grpcOpts = append(grpcOpts, grpc.Creds(creds)) } + // initialize server + srv := server.New(logger, store) + // initialize grpc server grpcServer = grpc.NewServer(grpcOpts...) + pb.RegisterFliptServer(grpcServer, srv) grpc_prometheus.EnableHandlingTimeHistogram() grpc_prometheus.Register(grpcServer) @@ -473,6 +511,7 @@ func run(_ []string) error { return grpcServer.Serve(lis) }) + // starts REST http(s) server g.Go(func() error { logger := l.WithField("server", cfg.Server.Protocol.String()) @@ -485,6 +524,15 @@ func run(_ []string) error { // See: https://github.com/flipt-io/flipt/issues/664 muxOpts = []grpc_gateway.ServeMuxOption{ grpc_gateway.WithMarshalerOption(grpc_gateway.MIMEWildcard, pb.NewV1toV2MarshallerAdapter()), + grpc_gateway.WithMarshalerOption("application/json+pretty", &grpc_gateway.JSONPb{ + MarshalOptions: protojson.MarshalOptions{ + Indent: " ", + Multiline: true, // Optional, implied by presence of "Indent". + }, + UnmarshalOptions: protojson.UnmarshalOptions{ + DiscardUnknown: true, + }, + }), } r = chi.NewRouter() @@ -536,6 +584,16 @@ func run(_ []string) error { r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Heartbeat("/health")) + r.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // checking Values as map[string][]string also catches ?pretty and ?pretty= + // r.URL.Query().Get("pretty") would not. + if _, ok := r.URL.Query()["pretty"]; ok { + r.Header.Set("Accept", "application/json+pretty") + } + h.ServeHTTP(w, r) + }) + }) r.Use(middleware.Compress(gzip.DefaultCompression)) r.Use(middleware.Recoverer) r.Mount("/metrics", promhttp.Handler()) diff --git a/config/config.go b/config/config.go index 7891373ba9..c1284089cd 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,11 @@ import ( jaeger "github.com/uber/jaeger-client-go" ) +const ( + deprecatedMsgMemoryEnabled = `'cache.memory.enabled' is deprecated and will be removed in a future version. Please use 'cache.backend' and 'cache.enabled' instead.` + deprecatedMsgMemoryExpiration = `'cache.memory.expiration' is deprecated and will be removed in a future version. Please use 'cache.ttl' instead.` +) + type Config struct { Log LogConfig `json:"log,omitempty"` UI UIConfig `json:"ui,omitempty"` @@ -23,6 +28,7 @@ type Config struct { Tracing TracingConfig `json:"tracing,omitempty"` Database DatabaseConfig `json:"database,omitempty"` Meta MetaConfig `json:"meta,omitempty"` + Warnings []string `json:"warnings,omitempty"` } type LogConfig struct { @@ -39,14 +45,50 @@ type CorsConfig struct { AllowedOrigins []string `json:"allowedOrigins,omitempty"` } +// CacheBackend is either memory or redis +type CacheBackend uint8 + +func (c CacheBackend) String() string { + return cacheBackendToString[c] +} + +const ( + _ CacheBackend = iota + // CacheMemory ... + CacheMemory + // CacheRedis ... + CacheRedis +) + +var ( + cacheBackendToString = map[CacheBackend]string{ + CacheMemory: "memory", + CacheRedis: "redis", + } + + stringToCacheBackend = map[string]CacheBackend{ + "memory": CacheMemory, + "redis": CacheRedis, + } +) + type MemoryCacheConfig struct { - Enabled bool `json:"enabled"` - Expiration time.Duration `json:"expiration,omitempty"` EvictionInterval time.Duration `json:"evictionInterval,omitempty"` } +type RedisCacheConfig struct { + Host string `json:"host,omitempty"` + Port int `json:"port,omitempty"` + Password string `json:"password,omitempty"` + DB int `json:"db,omitempty"` +} + type CacheConfig struct { - Memory MemoryCacheConfig `json:"memory,omitempty"` + Enabled bool `json:"enabled"` + TTL time.Duration `json:"ttl,omitempty"` + Backend CacheBackend `json:"backend,omitempty"` + Memory MemoryCacheConfig `json:"memory,omitempty"` + Redis RedisCacheConfig `json:"redis,omitempty"` } type ServerConfig struct { @@ -160,10 +202,17 @@ func Default() *Config { }, Cache: CacheConfig{ + Enabled: false, + Backend: CacheMemory, + TTL: 1 * time.Minute, Memory: MemoryCacheConfig{ - Enabled: false, - Expiration: -1, - EvictionInterval: 10 * time.Minute, + EvictionInterval: 5 * time.Minute, + }, + Redis: RedisCacheConfig{ + Host: "localhost", + Port: 6379, + Password: "", + DB: 0, }, }, @@ -210,9 +259,16 @@ const ( corsAllowedOrigins = "cors.allowed_origins" // Cache - cacheMemoryEnabled = "cache.memory.enabled" - cacheMemoryExpiration = "cache.memory.expiration" + cacheBackend = "cache.backend" + cacheEnabled = "cache.enabled" + cacheTTL = "cache.ttl" + cacheMemoryEnabled = "cache.memory.enabled" // deprecated in v1.10.0 + cacheMemoryExpiration = "cache.memory.expiration" // deprecated in v1.10.0 cacheMemoryEvictionInterval = "cache.memory.eviction_interval" + cacheRedisHost = "cache.redis.host" + cacheRedisPort = "cache.redis.port" + cacheRedisPassword = "cache.redis.password" + cacheRedisDB = "cache.redis.db" // Server serverHost = "server.host" @@ -284,14 +340,46 @@ func Load(path string) (*Config, error) { } // Cache - if viper.IsSet(cacheMemoryEnabled) { - cfg.Cache.Memory.Enabled = viper.GetBool(cacheMemoryEnabled) + if viper.GetBool(cacheMemoryEnabled) { // handle deprecated memory config + cfg.Cache.Backend = CacheMemory + cfg.Cache.Enabled = true + + cfg.Warnings = append(cfg.Warnings, deprecatedMsgMemoryEnabled) if viper.IsSet(cacheMemoryExpiration) { - cfg.Cache.Memory.Expiration = viper.GetDuration(cacheMemoryExpiration) + cfg.Cache.TTL = viper.GetDuration(cacheMemoryExpiration) + cfg.Warnings = append(cfg.Warnings, deprecatedMsgMemoryExpiration) + } + + } else if viper.IsSet(cacheEnabled) { + cfg.Cache.Enabled = viper.GetBool(cacheEnabled) + if viper.IsSet(cacheBackend) { + cfg.Cache.Backend = stringToCacheBackend[viper.GetString(cacheBackend)] } - if viper.IsSet(cacheMemoryEvictionInterval) { - cfg.Cache.Memory.EvictionInterval = viper.GetDuration(cacheMemoryEvictionInterval) + if viper.IsSet(cacheTTL) { + cfg.Cache.TTL = viper.GetDuration(cacheTTL) + } + } + + if cfg.Cache.Enabled { + switch cfg.Cache.Backend { + case CacheRedis: + if viper.IsSet(cacheRedisHost) { + cfg.Cache.Redis.Host = viper.GetString(cacheRedisHost) + } + if viper.IsSet(cacheRedisPort) { + cfg.Cache.Redis.Port = viper.GetInt(cacheRedisPort) + } + if viper.IsSet(cacheRedisPassword) { + cfg.Cache.Redis.Password = viper.GetString(cacheRedisPassword) + } + if viper.IsSet(cacheRedisDB) { + cfg.Cache.Redis.DB = viper.GetInt(cacheRedisDB) + } + case CacheMemory: + if viper.IsSet(cacheMemoryEvictionInterval) { + cfg.Cache.Memory.EvictionInterval = viper.GetDuration(cacheMemoryEvictionInterval) + } } } @@ -443,7 +531,17 @@ func (c *Config) validate() error { } func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) { - out, err := json.Marshal(c) + var ( + out []byte + err error + ) + + if r.Header.Get("Accept") == "application/json+pretty" { + out, err = json.MarshalIndent(c, "", " ") + } else { + out, err = json.Marshal(c) + } + if err != nil { w.WriteHeader(http.StatusInternalServerError) return diff --git a/config/config_test.go b/config/config_test.go index ab1a3fce1b..85ca2faa39 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - jaeger "github.com/uber/jaeger-client-go" ) func TestScheme(t *testing.T) { @@ -42,65 +41,144 @@ func TestScheme(t *testing.T) { } } +func TestCacheBackend(t *testing.T) { + tests := []struct { + name string + backend CacheBackend + want string + }{ + { + name: "memory", + backend: CacheMemory, + want: "memory", + }, + { + name: "redis", + backend: CacheRedis, + want: "redis", + }, + } + + for _, tt := range tests { + var ( + backend = tt.backend + want = tt.want + ) + + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, want, backend.String()) + }) + } +} + +func TestDatabaseProtocol(t *testing.T) { + tests := []struct { + name string + protocol DatabaseProtocol + want string + }{ + { + name: "postgres", + protocol: DatabasePostgres, + want: "postgres", + }, + { + name: "mysql", + protocol: DatabaseMySQL, + want: "mysql", + }, + { + name: "sqlite", + protocol: DatabaseSQLite, + want: "file", + }, + } + + for _, tt := range tests { + var ( + protocol = tt.protocol + want = tt.want + ) + + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, want, protocol.String()) + }) + } +} + func TestLoad(t *testing.T) { tests := []struct { name string path string wantErr bool - expected *Config + expected func() *Config }{ { name: "defaults", path: "./testdata/default.yml", - expected: Default(), + expected: Default, + }, + { + name: "deprecated - cache memory items defaults", + path: "./testdata/deprecated/cache_memory_items.yml", + expected: Default, + }, + { + name: "deprecated - cache memory enabled", + path: "./testdata/deprecated/cache_memory_enabled.yml", + expected: func() *Config { + cfg := Default() + cfg.Cache.Enabled = true + cfg.Cache.Backend = CacheMemory + cfg.Cache.TTL = -1 + cfg.Warnings = append(cfg.Warnings, deprecatedMsgMemoryEnabled, deprecatedMsgMemoryExpiration) + return cfg + }, + }, + { + name: "cache - no backend set", + path: "./testdata/cache/default.yml", + expected: func() *Config { + cfg := Default() + cfg.Cache.Enabled = true + cfg.Cache.Backend = CacheMemory + cfg.Cache.TTL = 30 * time.Minute + return cfg + }, }, { - name: "deprecated defaults", - path: "./testdata/deprecated.yml", - expected: Default(), + name: "cache - memory", + path: "./testdata/cache/memory.yml", + expected: func() *Config { + cfg := Default() + cfg.Cache.Enabled = true + cfg.Cache.Backend = CacheMemory + cfg.Cache.TTL = 5 * time.Minute + cfg.Cache.Memory.EvictionInterval = 10 * time.Minute + return cfg + }, + }, + { + name: "cache - redis", + path: "./testdata/cache/redis.yml", + expected: func() *Config { + cfg := Default() + cfg.Cache.Enabled = true + cfg.Cache.Backend = CacheRedis + cfg.Cache.TTL = time.Minute + cfg.Cache.Redis.Host = "localhost" + cfg.Cache.Redis.Port = 6378 + cfg.Cache.Redis.DB = 1 + cfg.Cache.Redis.Password = "s3cr3t!" + return cfg + }, }, { name: "database key/value", path: "./testdata/database.yml", - expected: &Config{ - Log: LogConfig{ - Level: "INFO", - }, - - UI: UIConfig{ - Enabled: true, - }, - - Cors: CorsConfig{ - Enabled: false, - AllowedOrigins: []string{"*"}, - }, - - Cache: CacheConfig{ - Memory: MemoryCacheConfig{ - Enabled: false, - Expiration: -1, - EvictionInterval: 10 * time.Minute, - }, - }, - - Server: ServerConfig{ - Host: "0.0.0.0", - Protocol: HTTP, - HTTPPort: 8080, - HTTPSPort: 443, - GRPCPort: 9000, - }, - - Tracing: TracingConfig{ - Jaeger: JaegerTracingConfig{ - Enabled: false, - Host: jaeger.DefaultUDPSpanServerHost, - Port: jaeger.DefaultUDPSpanServerPort, - }, - }, - - Database: DatabaseConfig{ + expected: func() *Config { + cfg := Default() + cfg.Database = DatabaseConfig{ Protocol: DatabaseMySQL, Host: "localhost", Port: 3306, @@ -109,37 +187,32 @@ func TestLoad(t *testing.T) { Name: "flipt", MigrationsPath: "/etc/flipt/config/migrations", MaxIdleConn: 2, - }, - - Meta: MetaConfig{ - CheckForUpdates: true, - TelemetryEnabled: true, - }, + } + return cfg }, }, { name: "advanced", path: "./testdata/advanced.yml", - expected: &Config{ - Log: LogConfig{ + expected: func() *Config { + cfg := Default() + cfg.Log = LogConfig{ Level: "WARN", File: "testLogFile.txt", - }, - UI: UIConfig{ + } + cfg.UI = UIConfig{ Enabled: false, - }, - Cors: CorsConfig{ + } + cfg.Cors = CorsConfig{ Enabled: true, AllowedOrigins: []string{"foo.com"}, - }, - Cache: CacheConfig{ - Memory: MemoryCacheConfig{ - Enabled: true, - Expiration: 5 * time.Minute, - EvictionInterval: 1 * time.Minute, - }, - }, - Server: ServerConfig{ + } + cfg.Cache.Enabled = true + cfg.Cache.Backend = CacheMemory + cfg.Cache.Memory = MemoryCacheConfig{ + EvictionInterval: 5 * time.Minute, + } + cfg.Server = ServerConfig{ Host: "127.0.0.1", Protocol: HTTPS, HTTPPort: 8081, @@ -147,25 +220,26 @@ func TestLoad(t *testing.T) { GRPCPort: 9001, CertFile: "./testdata/ssl_cert.pem", CertKey: "./testdata/ssl_key.pem", - }, - Tracing: TracingConfig{ + } + cfg.Tracing = TracingConfig{ Jaeger: JaegerTracingConfig{ Enabled: true, Host: "localhost", Port: 6831, }, - }, - Database: DatabaseConfig{ + } + cfg.Database = DatabaseConfig{ MigrationsPath: "./config/migrations", URL: "postgres://postgres@localhost:5432/flipt?sslmode=disable", MaxIdleConn: 10, MaxOpenConn: 50, ConnMaxLifetime: 30 * time.Minute, - }, - Meta: MetaConfig{ + } + cfg.Meta = MetaConfig{ CheckForUpdates: false, TelemetryEnabled: false, - }, + } + return cfg }, }, } @@ -174,7 +248,7 @@ func TestLoad(t *testing.T) { var ( path = tt.path wantErr = tt.wantErr - expected = tt.expected + expected = tt.expected() ) t.Run(tt.name, func(t *testing.T) { diff --git a/config/default.yml b/config/default.yml index aabb6e2c94..5b45fe039a 100644 --- a/config/default.yml +++ b/config/default.yml @@ -10,10 +10,14 @@ # allowed_origins: "*" # cache: +# enabled: false +# backend: memory +# ttl: 60s +# redis: +# host: localhost +# port: 6379 # memory: -# enabled: false -# expiration: -1 # Items Do Not Expire -# eviction_interval: 10m # Evict Expired Items Every 10m +# eviction_interval: 5m # Evict Expired Items Every 5m # server: # protocol: http diff --git a/config/local.yml b/config/local.yml index 9ccc20671f..6392ebd0dc 100644 --- a/config/local.yml +++ b/config/local.yml @@ -9,10 +9,14 @@ log: # allowed_origins: "*" # cache: +# enabled: false +# backend: memory +# ttl: 60s +# redis: +# host: localhost +# port: 6379 # memory: -# enabled: false -# expiration: -1 # Items Do Not Expire -# eviction_interval: 10m # Evict Expired Items Every 10m +# eviction_interval: 5m # evict expired items every 5m # server: # protocol: http diff --git a/config/testdata/advanced.yml b/config/testdata/advanced.yml index 9940698a81..933ab24eff 100644 --- a/config/testdata/advanced.yml +++ b/config/testdata/advanced.yml @@ -10,10 +10,11 @@ cors: allowed_origins: "foo.com" cache: + enabled: true + backend: memory + ttl: 60s memory: - enabled: true - expiration: 5m - eviction_interval: 1m + eviction_interval: 5m # Evict Expired Items Every 5m server: protocol: https diff --git a/config/testdata/cache/default.yml b/config/testdata/cache/default.yml new file mode 100644 index 0000000000..c3453c8302 --- /dev/null +++ b/config/testdata/cache/default.yml @@ -0,0 +1,3 @@ +cache: + enabled: true + ttl: 30m diff --git a/config/testdata/cache/memory.yml b/config/testdata/cache/memory.yml new file mode 100644 index 0000000000..2302e29651 --- /dev/null +++ b/config/testdata/cache/memory.yml @@ -0,0 +1,6 @@ +cache: + enabled: true + backend: memory + ttl: 5m + memory: + eviction_interval: 10m diff --git a/config/testdata/cache/redis.yml b/config/testdata/cache/redis.yml new file mode 100644 index 0000000000..bf07551160 --- /dev/null +++ b/config/testdata/cache/redis.yml @@ -0,0 +1,9 @@ +cache: + enabled: true + backend: redis + ttl: 60s + redis: + host: localhost + port: 6378 + db: 1 + password: "s3cr3t!" diff --git a/config/testdata/database.yml b/config/testdata/database.yml index e0fcf09307..ffa89eb406 100644 --- a/config/testdata/database.yml +++ b/config/testdata/database.yml @@ -9,10 +9,11 @@ # allowed_origins: "*" # cache: +# enabled: false +# backend: memory +# ttl: 60s # memory: -# enabled: false -# expiration: -1 # Items Do Not Expire -# eviction_interval: 10m # Evict Expired Items Every 10m +# eviction_interval: 5m # Evict Expired Items Every 5m # server: # protocol: http diff --git a/config/testdata/default.yml b/config/testdata/default.yml index 678c0291f6..cc8270c0df 100644 --- a/config/testdata/default.yml +++ b/config/testdata/default.yml @@ -9,10 +9,11 @@ # allowed_origins: "*" # cache: +# enabled: false +# backend: memory +# ttl: 60s # memory: -# enabled: false -# expiration: -1 # Items Do Not Expire -# eviction_interval: 10m # Evict Expired Items Every 10m +# eviction_interval: 5m # Evict Expired Items Every 5m # server: # protocol: http diff --git a/config/testdata/deprecated.yml b/config/testdata/deprecated.yml deleted file mode 100644 index eb12cfb2d5..0000000000 --- a/config/testdata/deprecated.yml +++ /dev/null @@ -1,4 +0,0 @@ -cache: - memory: - enabled: false - items: 500 diff --git a/config/testdata/deprecated/cache_memory_enabled.yml b/config/testdata/deprecated/cache_memory_enabled.yml new file mode 100644 index 0000000000..2463e071f1 --- /dev/null +++ b/config/testdata/deprecated/cache_memory_enabled.yml @@ -0,0 +1,4 @@ +cache: + memory: + enabled: true + expiration: -1 diff --git a/config/testdata/deprecated/cache_memory_items.yml b/config/testdata/deprecated/cache_memory_items.yml new file mode 100644 index 0000000000..964bd94bd8 --- /dev/null +++ b/config/testdata/deprecated/cache_memory_items.yml @@ -0,0 +1,4 @@ +cache: + memory: + enabled: false + items: 500 diff --git a/go.mod b/go.mod index 95dbadb810..86912d00c1 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/fatih/color v1.13.0 github.com/go-chi/chi/v5 v5.0.8-0.20220103191336-b750c805b4ee github.com/go-chi/cors v1.2.1 + github.com/go-redis/cache/v8 v8.4.3 + github.com/go-redis/redis/v8 v8.11.5 github.com/go-sql-driver/mysql v1.6.0 github.com/gofrs/uuid v4.2.0+incompatible github.com/golang-migrate/migrate v3.5.4+incompatible @@ -20,7 +22,7 @@ require ( github.com/luna-duclos/instrumentedsql v1.1.3 github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20200611091901-487c5ec83473 github.com/mattn/go-sqlite3 v1.14.14 - github.com/opentracing-contrib/go-grpc v0.0.0-20200813121455-4a6760c71486 + github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e github.com/opentracing/opentracing-go v1.2.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/phyber/negroni-gzip v1.0.0 @@ -29,6 +31,7 @@ require ( github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.8.0 + github.com/testcontainers/testcontainers-go v0.13.0 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3 go.flipt.io/flipt-grpc v1.0.0 @@ -40,30 +43,44 @@ require ( ) require ( - github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.4.17 // indirect + github.com/Microsoft/hcsshim v0.8.23 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect + github.com/containerd/cgroups v1.0.1 // indirect + github.com/containerd/containerd v1.5.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/docker/docker v1.13.1 // indirect + github.com/docker/docker v20.10.11+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-querystring v1.0.0 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/sys/mount v0.2.0 // indirect + github.com/moby/sys/mountinfo v0.5.0 // indirect + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -80,9 +97,14 @@ require ( github.com/subosito/gotenv v1.3.0 // indirect github.com/uber/jaeger-lib v2.2.0+incompatible // indirect github.com/urfave/negroni v1.0.1-0.20200608235619-7de0dfc1ff79 // indirect + github.com/vmihailenco/go-tinylfu v0.2.2 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect + go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.7.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee // indirect golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index ff39b5ba45..2d864262a7 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -54,47 +55,124 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX 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= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/HdrHistogram/hdrhistogram-go v0.9.0 h1:dpujRju0R4M/QZzcnR1LH1qm+TVG3UzkWdp5tH1WMcg= github.com/HdrHistogram/hdrhistogram-go v0.9.0/go.mod h1:nxrse8/Tzg2tg3DZcZjm6qEclQKK70g0KxO61gFFZD4= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc= github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= 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/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -105,22 +183,157 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.9 h1:rs6Xg1gtIxaeyG+Smsb/0xaSDu1VgFhOCKBXxMxbsF4= +github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= -github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo= +github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -131,14 +344,25 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m 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.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.8-0.20220103191336-b750c805b4ee h1:TCfv9Po2jPE4mN7sjzztbsc40otGpWXx7u4SVN05qeo= github.com/go-chi/chi/v5 v5.0.8-0.20220103191336-b750c805b4ee/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= @@ -147,30 +371,67 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-redis/cache/v8 v8.4.3 h1:+RZ0pQM+zOd6h/oWCsOl3+nsCgii9rn26oCYmU87kN8= +github.com/go-redis/cache/v8 v8.4.3/go.mod h1:5lQPQ63uyBt4aZuRmdvUJOJRRjPxfLtJtlcJ/z8o1jA= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= 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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -199,6 +460,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS 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.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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= @@ -222,6 +484,7 @@ github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3 github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -238,11 +501,18 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe 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-20210407192527-94a9f03dee38/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/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/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/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= @@ -250,19 +520,38 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 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/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.3/go.mod h1:lZdb/YAJUSj9OqrCHs2ihjtoO3+xK3G53wTYXFWRGDo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 h1:BGNSrTRW4rwfhJiFwvwF4XQ0Y72Jj9YEgxVrtovbD5o= github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3/go.mod h1:VHn7KgNsRriXa4mcgtkpR00OXyQY6g67JWMvn+R27A4= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -272,49 +561,82 @@ github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39E github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -324,133 +646,313 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20200611091901-487c5ec83473 h1:Ue6HW2pHgCF6+AcUL3VuRorR/M0uLJNDMmvkhKd+tVw= github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20200611091901-487c5ec83473/go.mod h1:YnZVBK+MxEr2sn1rbf4UMqsBd0uKaCOq52UtmbfDKNM= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= +github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opentracing-contrib/go-grpc v0.0.0-20200813121455-4a6760c71486 h1:K35HCWaOTJIPW6cDHK4yj3QfRY/NhE0pBbfoc0M2NMQ= -github.com/opentracing-contrib/go-grpc v0.0.0-20200813121455-4a6760c71486/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phyber/negroni-gzip v1.0.0 h1:ru1uBeaUeoAXYgZRE7RsH7ftj/t5v/hkufXv1OYbNK8= github.com/phyber/negroni-gzip v1.0.0/go.mod h1:poOYjiFVKpeib8SnUpOgfQGStKNGLKsM8l09lOTNeyw= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/segmentio/backo-go v1.0.0 h1:kbOAtGJY2DqOR0jfRkYEorx/b18RgtepGtY3+Cpe6qA= github.com/segmentio/backo-go v1.0.0/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +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= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -462,16 +964,48 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/testcontainers/testcontainers-go v0.13.0 h1:OUujSlEGsXVo/ykPVZk3KanBNGN0TYb/7oKIPVn15JA= +github.com/testcontainers/testcontainers-go v0.13.0/go.mod h1:z1abufU633Eb/FmSBTzV6ntZAC1eZBYPtaFsn4nPuDk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/urfave/negroni v1.0.1-0.20200608235619-7de0dfc1ff79 h1:310aEUwMcbpcxq9wp7hSr9f+mRV6grcai3HxdAmVl9k= github.com/urfave/negroni v1.0.1-0.20200608235619-7de0dfc1ff79/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vmihailenco/go-tinylfu v0.2.2 h1:H1eiG6HM36iniK6+21n9LLpzx1G9R3DJa2UjUjbynsI= +github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= +github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= +github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3 h1:NC3CI7do3KHtiuYhk1CdS9V2qS3jNa7Fs2Afcnnt+IE= github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3/go.mod h1:A47W3pdWONaZmXuLZgfKLAVgUY0qvfTRM5vVDKS40S4= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -479,34 +1013,67 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.flipt.io/flipt-grpc v1.0.0 h1:KMiR6EdHVhcSVkttymkk5o5PTlEci2didfH/yaC+iDM= go.flipt.io/flipt-grpc v1.0.0/go.mod h1:mPD3/iuyyb6Dfq9FQmlx0L7syzhthY3MfjI/u2bcGrc= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 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 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= @@ -514,6 +1081,7 @@ golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -521,6 +1089,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee h1:qlrAyYdKz4o7rWVUjiKqQJMa4PEpd55fqBU8jpsl4Iw= +golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -537,31 +1107,45 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI 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/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -572,10 +1156,12 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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= @@ -586,8 +1172,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211108170745-6635138e15ea/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= @@ -632,7 +1220,11 @@ golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -640,23 +1232,41 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -666,13 +1276,23 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -681,10 +1301,12 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20210426230700-d19ff857e887/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-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -697,6 +1319,7 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc 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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -721,25 +1344,36 @@ 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= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -747,6 +1381,8 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -770,6 +1406,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -785,6 +1422,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T 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= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -825,17 +1464,21 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -844,6 +1487,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -864,6 +1508,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -913,11 +1558,17 @@ google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f h1:hJ/Y5SqPXbarffmAsApliUlcvMU+wScNGfyop4bZm8o= google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -964,17 +1615,33 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -989,6 +1656,13 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/gotestsum v1.7.0/go.mod h1:V1m4Jw3eBerhI/A6qCxUE07RnCg7ACkKj9BYcAm09V8= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -996,8 +1670,40 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/info/flipt.go b/internal/info/flipt.go index 2a18bef5dd..bee3beef0a 100644 --- a/internal/info/flipt.go +++ b/internal/info/flipt.go @@ -16,7 +16,17 @@ type Flipt struct { } func (f Flipt) ServeHTTP(w http.ResponseWriter, r *http.Request) { - out, err := json.Marshal(f) + var ( + out []byte + err error + ) + + if r.Header.Get("Accept") == "application/json+pretty" { + out, err = json.MarshalIndent(f, "", " ") + } else { + out, err = json.Marshal(f) + } + if err != nil { w.WriteHeader(http.StatusInternalServerError) return diff --git a/storage/cache/cache.go b/server/cache/cache.go similarity index 51% rename from storage/cache/cache.go rename to server/cache/cache.go index db8e69343a..c8042a5d33 100644 --- a/storage/cache/cache.go +++ b/server/cache/cache.go @@ -2,24 +2,17 @@ package cache import ( "context" - "errors" "fmt" ) -var ( - // ErrCorrupt represents a corrupt cache error - ErrCorrupt = errors.New("cache corrupted") -) - // Cacher modifies and queries a cache type Cacher interface { // Get retrieves a value from the cache, the bool indicates if the item was found - Get(ctx context.Context, key string) (interface{}, bool, error) + Get(ctx context.Context, key string) ([]byte, bool, error) // Set sets a value in the cache - Set(ctx context.Context, key string, value interface{}) error + Set(ctx context.Context, key string, value []byte) error // Delete removes a value from the cache Delete(ctx context.Context, key string) error - // Flush removes all values from the cache - Flush(ctx context.Context) error fmt.Stringer + statsGetter } diff --git a/server/cache/memory/cache.go b/server/cache/memory/cache.go new file mode 100644 index 0000000000..f2af9df54f --- /dev/null +++ b/server/cache/memory/cache.go @@ -0,0 +1,61 @@ +package memory + +import ( + "context" + "sync/atomic" + + gocache "github.com/patrickmn/go-cache" + "go.flipt.io/flipt/config" + "go.flipt.io/flipt/server/cache" +) + +// Cache wraps gocache.Cache in order to implement Cacher +type Cache struct { + c *gocache.Cache + missTotal uint64 + hitTotal uint64 +} + +// NewCache creates a new in memory cache with the provided cache config +func NewCache(cfg config.CacheConfig) *Cache { + var ( + gc = gocache.New(cfg.TTL, cfg.Memory.EvictionInterval) + c = &Cache{c: gc} + ) + + cache.RegisterMetrics(c) + return c +} + +func (c *Cache) Get(_ context.Context, key string) ([]byte, bool, error) { + v, ok := c.c.Get(key) + if !ok { + atomic.AddUint64(&c.missTotal, 1) + return nil, false, nil + } + + atomic.AddUint64(&c.hitTotal, 1) + return v.([]byte), true, nil +} + +func (c *Cache) Set(_ context.Context, key string, value []byte) error { + c.c.SetDefault(key, value) + return nil +} + +func (c *Cache) Delete(_ context.Context, key string) error { + c.c.Delete(key) + return nil +} + +func (c *Cache) String() string { + return "memory" +} + +func (c *Cache) Stats() cache.Stats { + return cache.Stats{ + MissTotal: c.missTotal, + HitTotal: c.hitTotal, + ErrorTotal: 0, + } +} diff --git a/server/cache/memory/cache_test.go b/server/cache/memory/cache_test.go new file mode 100644 index 0000000000..bcf63ecf1e --- /dev/null +++ b/server/cache/memory/cache_test.go @@ -0,0 +1,88 @@ +package memory + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "go.flipt.io/flipt/config" +) + +func TestNewCache(t *testing.T) { + c := NewCache(config.CacheConfig{}) + assert.NotNil(t, c) + assert.Equal(t, "memory", c.String()) +} + +func TestSet(t *testing.T) { + var ( + c = NewCache(config.CacheConfig{}) + ctx = context.Background() + ) + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) +} + +func TestGet(t *testing.T) { + var ( + c = NewCache(config.CacheConfig{}) + ctx = context.Background() + ) + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) + + v, ok, err := c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(0), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + v, ok, err = c.Get(ctx, "foo") + assert.NoError(t, err) + assert.False(t, ok) + assert.Nil(t, v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + v, ok, err = c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(2), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) +} + +func TestDelete(t *testing.T) { + var ( + c = NewCache(config.CacheConfig{}) + ctx = context.Background() + ) + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) + + v, ok, err := c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(0), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + err = c.Delete(ctx, "key") + assert.NoError(t, err) + + v, ok, err = c.Get(ctx, "key") + assert.NoError(t, err) + assert.False(t, ok) + assert.Nil(t, v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) +} diff --git a/server/cache/metrics.go b/server/cache/metrics.go new file mode 100644 index 0000000000..9ef5befbd9 --- /dev/null +++ b/server/cache/metrics.go @@ -0,0 +1,84 @@ +package cache + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type Stats struct { + MissTotal uint64 + HitTotal uint64 + ErrorTotal uint64 +} + +// statsGetter is an interface that gets cache.Stats. +type statsGetter interface { + Stats() Stats +} + +const ( + namespace = "flipt" + subsystem = "cache" +) + +func RegisterMetrics(c Cacher) { + labels := prometheus.Labels{"cache": c.String()} + + collector := &metricsCollector{ + sg: c, + hitTotalDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "hit_total"), + "The number of cache hits", + nil, + labels, + ), + missTotalDec: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "miss_total"), + "The number of cache misses", + nil, + labels, + ), + errorTotalDesc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "error_total"), + "The number of times an error occurred reading or writing to the cache", + nil, + labels, + ), + } + + prometheus.Unregister(collector) + prometheus.MustRegister(collector) +} + +type metricsCollector struct { + sg statsGetter + + hitTotalDesc *prometheus.Desc + missTotalDec *prometheus.Desc + errorTotalDesc *prometheus.Desc +} + +func (c *metricsCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.hitTotalDesc + ch <- c.missTotalDec + ch <- c.errorTotalDesc +} + +func (c *metricsCollector) Collect(ch chan<- prometheus.Metric) { + stats := c.sg.Stats() + + ch <- prometheus.MustNewConstMetric( + c.hitTotalDesc, + prometheus.CounterValue, + float64(stats.HitTotal), + ) + ch <- prometheus.MustNewConstMetric( + c.missTotalDec, + prometheus.CounterValue, + float64(stats.MissTotal), + ) + ch <- prometheus.MustNewConstMetric( + c.errorTotalDesc, + prometheus.CounterValue, + float64(stats.ErrorTotal), + ) +} diff --git a/server/cache/redis/cache.go b/server/cache/redis/cache.go new file mode 100644 index 0000000000..4db1a9cc7d --- /dev/null +++ b/server/cache/redis/cache.go @@ -0,0 +1,78 @@ +package redis + +import ( + "context" + "errors" + "sync/atomic" + + redis "github.com/go-redis/cache/v8" + "go.flipt.io/flipt/config" + "go.flipt.io/flipt/server/cache" +) + +type Cache struct { + c *redis.Cache + cfg config.CacheConfig + missTotal uint64 + hitTotal uint64 + errTotal uint64 +} + +// NewCache creates a new redis cache with the provided cache config +func NewCache(cfg config.CacheConfig, r *redis.Cache) *Cache { + c := &Cache{cfg: cfg, c: r} + cache.RegisterMetrics(c) + return c +} + +func (c *Cache) Get(ctx context.Context, key string) ([]byte, bool, error) { + value := []byte{} + + if err := c.c.Get(ctx, key, &value); err != nil { + if errors.Is(err, redis.ErrCacheMiss) { + atomic.AddUint64(&c.missTotal, 1) + return nil, false, nil + } + + atomic.AddUint64(&c.errTotal, 1) + return nil, false, err + } + + atomic.AddUint64(&c.hitTotal, 1) + return value, true, nil +} + +func (c *Cache) Set(ctx context.Context, key string, value []byte) error { + if err := c.c.Set(&redis.Item{ + Ctx: ctx, + Key: key, + Value: value, + TTL: c.cfg.TTL, + }); err != nil { + atomic.AddUint64(&c.errTotal, 1) + return err + } + + return nil +} + +func (c *Cache) Delete(ctx context.Context, key string) error { + if err := c.c.Delete(ctx, key); err != nil { + atomic.AddUint64(&c.errTotal, 1) + return err + } + + return nil +} + +func (c *Cache) String() string { + return "redis" +} + +func (c *Cache) Stats() cache.Stats { + return cache.Stats{ + MissTotal: c.missTotal, + HitTotal: c.hitTotal, + ErrorTotal: c.errTotal, + } +} diff --git a/server/cache/redis/cache_test.go b/server/cache/redis/cache_test.go new file mode 100644 index 0000000000..4ea678c8a7 --- /dev/null +++ b/server/cache/redis/cache_test.go @@ -0,0 +1,159 @@ +package redis + +import ( + "context" + "fmt" + "testing" + "time" + + goredis_cache "github.com/go-redis/cache/v8" + goredis "github.com/go-redis/redis/v8" + "github.com/stretchr/testify/assert" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + "go.flipt.io/flipt/config" +) + +func TestSet(t *testing.T) { + var ( + ctx = context.Background() + c, teardown = newCache(t, ctx) + ) + + defer teardown() + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) +} + +func TestGet(t *testing.T) { + var ( + ctx = context.Background() + c, teardown = newCache(t, ctx) + ) + + defer teardown() + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) + + v, ok, err := c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(0), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + v, ok, err = c.Get(ctx, "foo") + assert.NoError(t, err) + assert.False(t, ok) + assert.Nil(t, v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + v, ok, err = c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(2), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) +} + +func TestDelete(t *testing.T) { + var ( + ctx = context.Background() + c, teardown = newCache(t, ctx) + ) + + defer teardown() + + err := c.Set(ctx, "key", []byte("value")) + assert.NoError(t, err) + + v, ok, err := c.Get(ctx, "key") + assert.NoError(t, err) + assert.True(t, ok) + assert.Equal(t, []byte("value"), v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(0), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) + + err = c.Delete(ctx, "key") + assert.NoError(t, err) + + v, ok, err = c.Get(ctx, "key") + assert.NoError(t, err) + assert.False(t, ok) + assert.Nil(t, v) + assert.Equal(t, uint64(1), c.Stats().HitTotal) + assert.Equal(t, uint64(1), c.Stats().MissTotal) + assert.Equal(t, uint64(0), c.Stats().ErrorTotal) +} + +type redisContainer struct { + testcontainers.Container + host string + port string +} + +func setupRedis(ctx context.Context) (*redisContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "redis:latest", + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("* Ready to accept connections"), + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + mappedPort, err := container.MappedPort(ctx, "6379") + if err != nil { + return nil, err + } + + hostIP, err := container.Host(ctx) + if err != nil { + return nil, err + } + + return &redisContainer{Container: container, host: hostIP, port: mappedPort.Port()}, nil +} + +func newCache(t *testing.T, ctx context.Context) (*Cache, func()) { + t.Helper() + + if testing.Short() { + t.Skip("skipping redis test in short mode") + } + + redisContainer, err := setupRedis(ctx) + if err != nil { + assert.FailNowf(t, "failed to setup redis container: %s", err.Error()) + } + + rdb := goredis.NewClient(&goredis.Options{ + Addr: fmt.Sprintf("%s:%s", redisContainer.host, redisContainer.port), + }) + + cache := NewCache(config.CacheConfig{ + TTL: 30 * time.Second, + }, goredis_cache.New(&goredis_cache.Options{ + Redis: rdb, + })) + + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + teardown := func() { + _ = rdb.Shutdown(shutdownCtx) + _ = redisContainer.Terminate(shutdownCtx) + cancel() + } + + return cache, teardown +} diff --git a/server/evaluator.go b/server/evaluator.go index 0168182dd3..220e6b8b36 100644 --- a/server/evaluator.go +++ b/server/evaluator.go @@ -8,34 +8,19 @@ import ( "sort" "strconv" "strings" - "time" - "github.com/gofrs/uuid" errs "go.flipt.io/flipt/errors" flipt "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/storage" - timestamp "google.golang.org/protobuf/types/known/timestamppb" ) // Evaluate evaluates a request for a given flag and entity func (s *Server) Evaluate(ctx context.Context, r *flipt.EvaluationRequest) (*flipt.EvaluationResponse, error) { s.logger.WithField("request", r).Debug("evaluate") - startTime := time.Now() - - // set request ID if not present - if r.RequestId == "" { - r.RequestId = uuid.Must(uuid.NewV4()).String() - } - resp, err := s.evaluate(ctx, r) - if resp != nil { - resp.RequestDurationMillis = float64(time.Since(startTime)) / float64(time.Millisecond) - } - if err != nil { return resp, err } - s.logger.WithField("response", resp).Debug("evaluate") return resp, nil } @@ -43,34 +28,23 @@ func (s *Server) Evaluate(ctx context.Context, r *flipt.EvaluationRequest) (*fli // BatchEvaluate evaluates a request for multiple flags and entities func (s *Server) BatchEvaluate(ctx context.Context, r *flipt.BatchEvaluationRequest) (*flipt.BatchEvaluationResponse, error) { s.logger.WithField("request", r).Debug("batch-evaluate") - startTime := time.Now() - - // set request ID if not present - if r.RequestId == "" { - r.RequestId = uuid.Must(uuid.NewV4()).String() - } - resp, err := s.batchEvaluate(ctx, r) if err != nil { return nil, err } - - if resp != nil { - resp.RequestDurationMillis = float64(time.Since(startTime)) / float64(time.Millisecond) - } - s.logger.WithField("response", resp).Debug("batch-evaluate") return resp, nil } func (s *Server) batchEvaluate(ctx context.Context, r *flipt.BatchEvaluationRequest) (*flipt.BatchEvaluationResponse, error) { - startTime := time.Now() res := flipt.BatchEvaluationResponse{ - RequestId: r.RequestId, Responses: make([]*flipt.EvaluationResponse, 0, len(r.GetRequests())), } + // TODO: we should change this to a native batch query instead of looping through + // each request individually for _, flag := range r.GetRequests() { + // TODO: we also need to validate each request, we should likely do this in the validation middleware f, err := s.evaluate(ctx, flag) if err != nil { var errnf errs.ErrNotFound @@ -80,7 +54,6 @@ func (s *Server) batchEvaluate(ctx context.Context, r *flipt.BatchEvaluationRequ return &res, err } f.RequestId = "" - f.RequestDurationMillis = float64(time.Since(startTime)) / float64(time.Millisecond) res.Responses = append(res.Responses, f) } @@ -89,12 +62,10 @@ func (s *Server) batchEvaluate(ctx context.Context, r *flipt.BatchEvaluationRequ func (s *Server) evaluate(ctx context.Context, r *flipt.EvaluationRequest) (*flipt.EvaluationResponse, error) { var ( - ts = timestamp.New(time.Now().UTC()) resp = &flipt.EvaluationResponse{ RequestId: r.RequestId, EntityId: r.EntityId, RequestContext: r.Context, - Timestamp: ts, FlagKey: r.FlagKey, } ) diff --git a/server/evaluator_test.go b/server/evaluator_test.go index c1c95c80da..ca877260da 100644 --- a/server/evaluator_test.go +++ b/server/evaluator_test.go @@ -60,8 +60,6 @@ func TestBatchEvaluate(t *testing.T) { }) require.NoError(t, err) - assert.Equal(t, "12345", resp.RequestId) - assert.NotEmpty(t, resp.RequestDurationMillis) assert.NotNil(t, resp.Responses) assert.Equal(t, 2, len(resp.Responses)) assert.False(t, resp.Responses[0].Match) @@ -109,8 +107,6 @@ func TestBatchEvaluate_FlagNotFoundExcluded(t *testing.T) { }) require.NoError(t, err) - assert.Equal(t, "12345", resp.RequestId) - assert.NotEmpty(t, resp.RequestDurationMillis) assert.NotNil(t, resp.Responses) assert.Equal(t, 2, len(resp.Responses)) assert.False(t, resp.Responses[0].Match) diff --git a/server/flag_test.go b/server/flag_test.go index 2a194b7322..7018325fc5 100644 --- a/server/flag_test.go +++ b/server/flag_test.go @@ -21,13 +21,16 @@ func TestGetFlag(t *testing.T) { ) store.On("GetFlag", mock.Anything, "foo").Return(&flipt.Flag{ - Key: req.Key, + Key: req.Key, + Enabled: true, }, nil) got, err := s.GetFlag(context.TODO(), req) require.NoError(t, err) assert.NotNil(t, got) + assert.Equal(t, "foo", got.Key) + assert.Equal(t, true, got.Enabled) } func TestListFlags(t *testing.T) { diff --git a/server/middleware.go b/server/middleware.go new file mode 100644 index 0000000000..e62abc6d58 --- /dev/null +++ b/server/middleware.go @@ -0,0 +1,255 @@ +package server + +import ( + "context" + "crypto/md5" + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/gofrs/uuid" + "github.com/sirupsen/logrus" + errs "go.flipt.io/flipt/errors" + flipt "go.flipt.io/flipt/rpc/flipt" + "go.flipt.io/flipt/server/cache" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + timestamp "google.golang.org/protobuf/types/known/timestamppb" +) + +// ValidationUnaryInterceptor validates incoming requests +func ValidationUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + if v, ok := req.(flipt.Validator); ok { + if err := v.Validate(); err != nil { + return nil, err + } + } + + return handler(ctx, req) +} + +// ErrorUnaryInterceptor intercepts known errors and returns the appropriate GRPC status code +func ErrorUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + resp, err = handler(ctx, req) + if err == nil { + return resp, nil + } + + errorsTotal.Inc() + + var errnf errs.ErrNotFound + if errors.As(err, &errnf) { + err = status.Error(codes.NotFound, err.Error()) + return + } + + var errin errs.ErrInvalid + if errors.As(err, &errin) { + err = status.Error(codes.InvalidArgument, err.Error()) + return + } + + var errv errs.ErrValidation + if errors.As(err, &errv) { + err = status.Error(codes.InvalidArgument, err.Error()) + return + } + + err = status.Error(codes.Internal, err.Error()) + return +} + +// EvaluationUnaryInterceptor sets required request/response fields. +// Note: this should be added before any caching interceptor to ensure the request id/response fields are unique. +func EvaluationUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + switch r := req.(type) { + case *flipt.EvaluationRequest: + startTime := time.Now() + + // set request ID if not present + if r.RequestId == "" { + r.RequestId = uuid.Must(uuid.NewV4()).String() + } + + resp, err = handler(ctx, req) + if err != nil { + return resp, err + } + + // set response fields + if resp != nil { + if rr, ok := resp.(*flipt.EvaluationResponse); ok { + rr.RequestId = r.RequestId + rr.Timestamp = timestamp.New(time.Now().UTC()) + rr.RequestDurationMillis = float64(time.Since(startTime)) / float64(time.Millisecond) + } + return resp, nil + } + + case *flipt.BatchEvaluationRequest: + startTime := time.Now() + + // set request ID if not present + if r.RequestId == "" { + r.RequestId = uuid.Must(uuid.NewV4()).String() + } + + resp, err = handler(ctx, req) + if err != nil { + return resp, err + } + + // set response fields + if resp != nil { + if rr, ok := resp.(*flipt.BatchEvaluationResponse); ok { + rr.RequestId = r.RequestId + rr.RequestDurationMillis = float64(time.Since(startTime)) / float64(time.Millisecond) + return resp, nil + } + } + } + + return handler(ctx, req) +} + +// CacheUnaryInterceptor caches the response of a request if the request is cacheable. +// TODO: we could clean this up by using generics in 1.18+ to avoid the type switch/duplicate code. +func CacheUnaryInterceptor(cache cache.Cacher, logger logrus.FieldLogger) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if cache == nil { + return handler(ctx, req) + } + + switch r := req.(type) { + case *flipt.EvaluationRequest: + key, err := evaluationCacheKey(r) + if err != nil { + logger.WithError(err).Error("getting cache key") + return handler(ctx, req) + } + + cached, ok, err := cache.Get(ctx, key) + if err != nil { + // if error, log and without cache + logger.WithError(err).Error("getting from cache") + return handler(ctx, req) + } + + if ok { + resp := &flipt.EvaluationResponse{} + if err := proto.Unmarshal(cached, resp); err != nil { + logger.WithError(err).Error("unmarshalling from cache") + return handler(ctx, req) + } + + logger.Debugf("evaluate cache hit: %+v", resp) + return resp, nil + } + + logger.Debug("evaluate cache miss") + resp, err := handler(ctx, req) + if err != nil { + return resp, err + } + + // marshal response + data, merr := proto.Marshal(resp.(*flipt.EvaluationResponse)) + if merr != nil { + logger.WithError(merr).Error("marshalling for cache") + return resp, err + } + + // set in cache + if cerr := cache.Set(ctx, key, data); cerr != nil { + logger.WithError(cerr).Error("setting in cache") + } + + return resp, err + + case *flipt.GetFlagRequest: + key := flagCacheKey(r.GetKey()) + + cached, ok, err := cache.Get(ctx, key) + if err != nil { + // if error, log and continue without cache + logger.WithError(err).Error("getting from cache") + return handler(ctx, req) + } + + if ok { + // if cached, return it + flag := &flipt.Flag{} + if err := proto.Unmarshal(cached, flag); err != nil { + logger.WithError(err).Error("unmarshalling from cache") + return handler(ctx, req) + } + + logger.Debugf("flag cache hit: %+v", flag) + return flag, nil + } + + logger.Debug("flag cache miss") + resp, err := handler(ctx, req) + if err != nil { + return nil, err + } + + // marshal response + data, merr := proto.Marshal(resp.(*flipt.Flag)) + if merr != nil { + logger.WithError(merr).Error("marshalling for cache") + return resp, err + } + + // set in cache + if cerr := cache.Set(ctx, key, data); cerr != nil { + logger.WithError(cerr).Error("setting in cache") + } + + return resp, err + + case *flipt.UpdateFlagRequest, *flipt.DeleteFlagRequest: + // need to do this assertion because the request type is not known in this block + keyer := r.(flagKeyer) + // delete from cache + if err := cache.Delete(ctx, flagCacheKey(keyer.GetKey())); err != nil { + logger.WithError(err).Error("deleting from cache") + } + case *flipt.CreateVariantRequest, *flipt.UpdateVariantRequest, *flipt.DeleteVariantRequest: + // need to do this assertion because the request type is not known in this block + keyer := r.(variantFlagKeyger) + // delete from cache + if err := cache.Delete(ctx, flagCacheKey(keyer.GetFlagKey())); err != nil { + logger.WithError(err).Error("deleting from cache") + } + } + + return handler(ctx, req) + } +} + +type flagKeyer interface { + GetKey() string +} + +type variantFlagKeyger interface { + GetFlagKey() string +} + +func flagCacheKey(key string) string { + k := fmt.Sprintf("f:%s", key) + return fmt.Sprintf("flipt:%x", md5.Sum([]byte(k))) +} + +func evaluationCacheKey(r *flipt.EvaluationRequest) (string, error) { + out, err := json.Marshal(r.GetContext()) + if err != nil { + return "", fmt.Errorf("marshalling req to json: %w", err) + } + + k := fmt.Sprintf("e:%s:%s:%s", r.GetFlagKey(), r.GetEntityId(), out) + return fmt.Sprintf("flipt:%x", md5.Sum([]byte(k))), nil +} diff --git a/server/middleware_test.go b/server/middleware_test.go new file mode 100644 index 0000000000..4849dc65c7 --- /dev/null +++ b/server/middleware_test.go @@ -0,0 +1,702 @@ +package server + +import ( + "context" + "testing" + "time" + + "go.flipt.io/flipt/config" + "go.flipt.io/flipt/errors" + flipt "go.flipt.io/flipt/rpc/flipt" + "go.flipt.io/flipt/server/cache/memory" + "go.flipt.io/flipt/storage" + + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var logger, _ = test.NewNullLogger() + +type validatable struct { + err error +} + +func (v *validatable) Validate() error { + return v.err +} + +func TestValidationUnaryInterceptor(t *testing.T) { + tests := []struct { + name string + req interface{} + wantCalled int + }{ + { + name: "does not implement Validate", + req: struct{}{}, + wantCalled: 1, + }, + { + name: "implements validate no error", + req: &validatable{}, + wantCalled: 1, + }, + { + name: "implements validate error", + req: &validatable{err: errors.New("invalid")}, + }, + } + + for _, tt := range tests { + var ( + req = tt.req + wantCalled = tt.wantCalled + called int + ) + + t.Run(tt.name, func(t *testing.T) { + var ( + spyHandler = grpc.UnaryHandler(func(ctx context.Context, req interface{}) (interface{}, error) { + called++ + return nil, nil + }) + ) + + _, _ = ValidationUnaryInterceptor(context.Background(), req, nil, spyHandler) + assert.Equal(t, wantCalled, called) + }) + } +} + +func TestErrorUnaryInterceptor(t *testing.T) { + tests := []struct { + name string + wantErr error + wantCode codes.Code + }{ + { + name: "not found error", + wantErr: errors.ErrNotFound("foo"), + wantCode: codes.NotFound, + }, + { + name: "invalid error", + wantErr: errors.ErrInvalid("foo"), + wantCode: codes.InvalidArgument, + }, + { + name: "invalid field", + wantErr: errors.InvalidFieldError("bar", "is wrong"), + wantCode: codes.InvalidArgument, + }, + { + name: "empty field", + wantErr: errors.EmptyFieldError("bar"), + wantCode: codes.InvalidArgument, + }, + { + name: "other error", + wantErr: errors.New("foo"), + wantCode: codes.Internal, + }, + { + name: "no error", + }, + } + + for _, tt := range tests { + var ( + wantErr = tt.wantErr + wantCode = tt.wantCode + ) + + t.Run(tt.name, func(t *testing.T) { + var ( + spyHandler = grpc.UnaryHandler(func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, wantErr + }) + ) + + _, err := ErrorUnaryInterceptor(context.Background(), nil, nil, spyHandler) + if wantErr != nil { + require.Error(t, err) + status := status.Convert(err) + assert.Equal(t, wantCode, status.Code()) + return + } + + require.NoError(t, err) + }) + } +} + +func TestEvaluationUnaryInterceptor_Noop(t *testing.T) { + var ( + req = &flipt.GetFlagRequest{ + Key: "foo", + } + + handler = func(ctx context.Context, r interface{}) (interface{}, error) { + return &flipt.Flag{ + Key: "foo", + }, nil + } + + info = &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + ) + + got, err := EvaluationUnaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + + assert.NotNil(t, got) + + resp, ok := got.(*flipt.Flag) + assert.True(t, ok) + assert.NotNil(t, resp) + assert.Equal(t, "foo", resp.Key) +} + +func TestEvaluationUnaryInterceptor_Evaluation(t *testing.T) { + var ( + req = &flipt.EvaluationRequest{ + FlagKey: "foo", + } + + handler = func(ctx context.Context, r interface{}) (interface{}, error) { + return &flipt.EvaluationResponse{ + FlagKey: "foo", + }, nil + } + + info = &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + ) + + got, err := EvaluationUnaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + + assert.NotNil(t, got) + + resp, ok := got.(*flipt.EvaluationResponse) + assert.True(t, ok) + assert.NotNil(t, resp) + + assert.Equal(t, "foo", resp.FlagKey) + // check that the requestID was created and set + assert.NotEmpty(t, resp.RequestId) + assert.NotZero(t, resp.Timestamp) + assert.NotZero(t, resp.RequestDurationMillis) + + req = &flipt.EvaluationRequest{ + FlagKey: "foo", + RequestId: "bar", + } + + got, err = EvaluationUnaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + + assert.NotNil(t, got) + + resp, ok = got.(*flipt.EvaluationResponse) + assert.True(t, ok) + assert.NotNil(t, resp) + + assert.Equal(t, "foo", resp.FlagKey) + // check that the requestID was propagated + assert.NotEmpty(t, resp.RequestId) + assert.Equal(t, "bar", resp.RequestId) + assert.NotZero(t, resp.Timestamp) + assert.NotZero(t, resp.RequestDurationMillis) +} + +func TestEvaluationUnaryInterceptor_BatchEvaluation(t *testing.T) { + var ( + req = &flipt.BatchEvaluationRequest{ + Requests: []*flipt.EvaluationRequest{ + { + FlagKey: "foo", + }, + }, + } + + handler = func(ctx context.Context, r interface{}) (interface{}, error) { + return &flipt.BatchEvaluationResponse{ + Responses: []*flipt.EvaluationResponse{ + { + FlagKey: "foo", + }, + }, + }, nil + } + + info = &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + ) + + got, err := EvaluationUnaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + + assert.NotNil(t, got) + + resp, ok := got.(*flipt.BatchEvaluationResponse) + assert.True(t, ok) + assert.NotNil(t, resp) + assert.NotEmpty(t, resp.Responses) + assert.Equal(t, "foo", resp.Responses[0].FlagKey) + // check that the requestID was created and set + assert.NotEmpty(t, resp.RequestId) + assert.NotZero(t, resp.RequestDurationMillis) + + req = &flipt.BatchEvaluationRequest{ + RequestId: "bar", + Requests: []*flipt.EvaluationRequest{ + { + FlagKey: "foo", + }, + }, + } + + got, err = EvaluationUnaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + + assert.NotNil(t, got) + + resp, ok = got.(*flipt.BatchEvaluationResponse) + assert.True(t, ok) + assert.NotNil(t, resp) + assert.NotEmpty(t, resp.Responses) + assert.Equal(t, "foo", resp.Responses[0].FlagKey) + // check that the requestID was propagated + assert.NotEmpty(t, resp.RequestId) + assert.Equal(t, "bar", resp.RequestId) + assert.NotZero(t, resp.RequestDurationMillis) +} + +func TestCacheUnaryInterceptor_GetFlag(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.GetFlagRequest{Key: "foo"} + ) + + store.On("GetFlag", mock.Anything, "foo").Return(&flipt.Flag{ + Key: req.Key, + Enabled: true, + }, nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.GetFlag(ctx, r.(*flipt.GetFlagRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + for i := 0; i < 10; i++ { + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + } + + assert.Equal(t, 10, cacheSpy.getCalled) + assert.NotEmpty(t, cacheSpy.getKeys) + + // cache key is flipt:(md5(f:foo)) + const cacheKey = "flipt:864ce319cc64891a59e4745fbe7ecc47" + _, ok := cacheSpy.getKeys[cacheKey] + assert.True(t, ok) + + assert.Equal(t, 1, cacheSpy.setCalled) + assert.NotEmpty(t, cacheSpy.setItems) + assert.NotEmpty(t, cacheSpy.setItems[cacheKey]) +} + +func TestCacheUnaryInterceptor_UpdateFlag(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.UpdateFlagRequest{ + Key: "key", + Name: "name", + Description: "desc", + Enabled: true, + } + ) + + store.On("UpdateFlag", mock.Anything, req).Return(&flipt.Flag{ + Key: req.Key, + Name: req.Name, + Description: req.Description, + Enabled: req.Enabled, + }, nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.UpdateFlag(ctx, r.(*flipt.UpdateFlagRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + assert.Equal(t, 1, cacheSpy.deleteCalled) + assert.NotEmpty(t, cacheSpy.deleteKeys) +} + +func TestCacheUnaryInterceptor_DeleteFlag(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.DeleteFlagRequest{ + Key: "key", + } + ) + + store.On("DeleteFlag", mock.Anything, req).Return(nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.DeleteFlag(ctx, r.(*flipt.DeleteFlagRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + assert.Equal(t, 1, cacheSpy.deleteCalled) + assert.NotEmpty(t, cacheSpy.deleteKeys) +} + +func TestCacheUnaryInterceptor_CreateVariant(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.CreateVariantRequest{ + FlagKey: "flagKey", + Key: "key", + Name: "name", + Description: "desc", + } + ) + + store.On("CreateVariant", mock.Anything, req).Return(&flipt.Variant{ + Id: "1", + FlagKey: req.FlagKey, + Key: req.Key, + Name: req.Name, + Description: req.Description, + Attachment: req.Attachment, + }, nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.CreateVariant(ctx, r.(*flipt.CreateVariantRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + assert.Equal(t, 1, cacheSpy.deleteCalled) + assert.NotEmpty(t, cacheSpy.deleteKeys) +} + +func TestCacheUnaryInterceptor_UpdateVariant(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.UpdateVariantRequest{ + Id: "1", + FlagKey: "flagKey", + Key: "key", + Name: "name", + Description: "desc", + } + ) + + store.On("UpdateVariant", mock.Anything, req).Return(&flipt.Variant{ + Id: req.Id, + FlagKey: req.FlagKey, + Key: req.Key, + Name: req.Name, + Description: req.Description, + Attachment: req.Attachment, + }, nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.UpdateVariant(ctx, r.(*flipt.UpdateVariantRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + assert.Equal(t, 1, cacheSpy.deleteCalled) + assert.NotEmpty(t, cacheSpy.deleteKeys) +} + +func TestCacheUnaryInterceptor_DeleteVariant(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + req = &flipt.DeleteVariantRequest{ + Id: "1", + } + ) + + store.On("DeleteVariant", mock.Anything, req).Return(nil) + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.DeleteVariant(ctx, r.(*flipt.DeleteVariantRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + assert.Equal(t, 1, cacheSpy.deleteCalled) + assert.NotEmpty(t, cacheSpy.deleteKeys) +} + +func TestCacheUnaryInterceptor_Evaluate(t *testing.T) { + var ( + store = &storeMock{} + cache = memory.NewCache(config.CacheConfig{ + TTL: time.Second, + Enabled: true, + Backend: config.CacheMemory, + }) + cacheSpy = newCacheSpy(cache) + s = &Server{ + logger: logger, + store: store, + } + ) + + store.On("GetFlag", mock.Anything, "foo").Return(enabledFlag, nil) + + store.On("GetEvaluationRules", mock.Anything, "foo").Return( + []*storage.EvaluationRule{ + { + ID: "1", + FlagKey: "foo", + SegmentKey: "bar", + SegmentMatchType: flipt.MatchType_ALL_MATCH_TYPE, + Rank: 0, + Constraints: []storage.EvaluationConstraint{ + // constraint: bar (string) == baz + { + ID: "2", + Type: flipt.ComparisonType_STRING_COMPARISON_TYPE, + Property: "bar", + Operator: flipt.OpEQ, + Value: "baz", + }, + // constraint: admin (bool) == true + { + ID: "3", + Type: flipt.ComparisonType_BOOLEAN_COMPARISON_TYPE, + Property: "admin", + Operator: flipt.OpTrue, + }, + }, + }, + }, nil) + + store.On("GetEvaluationDistributions", mock.Anything, "1").Return( + []*storage.EvaluationDistribution{ + { + ID: "4", + RuleID: "1", + VariantID: "5", + Rollout: 100, + VariantKey: "boz", + VariantAttachment: `{"key":"value"}`, + }, + }, nil) + + tests := []struct { + name string + req *flipt.EvaluationRequest + wantMatch bool + }{ + { + name: "matches all", + req: &flipt.EvaluationRequest{ + FlagKey: "foo", + EntityId: "1", + Context: map[string]string{ + "bar": "baz", + "admin": "true", + }, + }, + wantMatch: true, + }, + { + name: "no match all", + req: &flipt.EvaluationRequest{ + FlagKey: "foo", + EntityId: "1", + Context: map[string]string{ + "bar": "boz", + "admin": "true", + }, + }, + }, + { + name: "no match just bool value", + req: &flipt.EvaluationRequest{ + FlagKey: "foo", + EntityId: "1", + Context: map[string]string{ + "admin": "true", + }, + }, + }, + { + name: "no match just string value", + req: &flipt.EvaluationRequest{ + FlagKey: "foo", + EntityId: "1", + Context: map[string]string{ + "bar": "baz", + }, + }, + }, + } + + unaryInterceptor := CacheUnaryInterceptor(cacheSpy, logger) + + handler := func(ctx context.Context, r interface{}) (interface{}, error) { + return s.Evaluate(ctx, r.(*flipt.EvaluationRequest)) + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "FakeMethod", + } + + for i, tt := range tests { + var ( + i = i + 1 + req = tt.req + wantMatch = tt.wantMatch + ) + + t.Run(tt.name, func(t *testing.T) { + got, err := unaryInterceptor(context.Background(), req, info, handler) + require.NoError(t, err) + assert.NotNil(t, got) + + resp := got.(*flipt.EvaluationResponse) + assert.NotNil(t, resp) + assert.Equal(t, "foo", resp.FlagKey) + assert.Equal(t, req.Context, resp.RequestContext) + + assert.Equal(t, i, cacheSpy.getCalled) + assert.NotEmpty(t, cacheSpy.getKeys) + + if !wantMatch { + assert.False(t, resp.Match) + assert.Empty(t, resp.SegmentKey) + return + } + + assert.True(t, resp.Match) + assert.Equal(t, "bar", resp.SegmentKey) + assert.Equal(t, "boz", resp.Value) + assert.Equal(t, `{"key":"value"}`, resp.Attachment) + }) + } +} diff --git a/server/server.go b/server/server.go index e3e571fd4b..8a9f873598 100644 --- a/server/server.go +++ b/server/server.go @@ -1,23 +1,14 @@ package server import ( - "context" - "errors" - - errs "go.flipt.io/flipt/errors" flipt "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/storage" "github.com/sirupsen/logrus" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) var _ flipt.FliptServer = &Server{} -type Option func(s *Server) - // Server serves the Flipt backend type Server struct { logger logrus.FieldLogger @@ -26,59 +17,9 @@ type Server struct { } // New creates a new Server -func New(logger logrus.FieldLogger, store storage.Store, opts ...Option) *Server { - var ( - s = &Server{ - logger: logger, - store: store, - } - ) - - for _, fn := range opts { - fn(s) - } - - return s -} - -// ValidationUnaryInterceptor validates incomming requests -func (s *Server) ValidationUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { - if v, ok := req.(flipt.Validator); ok { - if err := v.Validate(); err != nil { - return nil, err - } +func New(logger logrus.FieldLogger, store storage.Store) *Server { + return &Server{ + logger: logger, + store: store, } - - return handler(ctx, req) -} - -// ErrorUnaryInterceptor intercepts known errors and returns the appropriate GRPC status code -func (s *Server) ErrorUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { - resp, err = handler(ctx, req) - if err == nil { - return resp, nil - } - - errorsTotal.Inc() - - var errnf errs.ErrNotFound - if errors.As(err, &errnf) { - err = status.Error(codes.NotFound, err.Error()) - return - } - - var errin errs.ErrInvalid - if errors.As(err, &errin) { - err = status.Error(codes.InvalidArgument, err.Error()) - return - } - - var errv errs.ErrValidation - if errors.As(err, &errv) { - err = status.Error(codes.InvalidArgument, err.Error()) - return - } - - err = status.Error(codes.Internal, err.Error()) - return } diff --git a/server/server_test.go b/server/server_test.go deleted file mode 100644 index edefe43c88..0000000000 --- a/server/server_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package server - -import ( - "context" - "testing" - - "go.flipt.io/flipt/errors" - - "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -var logger, _ = test.NewNullLogger() - -type validatable struct { - err error -} - -func (v *validatable) Validate() error { - return v.err -} - -func TestValidationUnaryInterceptor(t *testing.T) { - tests := []struct { - name string - req interface{} - wantCalled int - }{ - { - name: "does not implement Validate", - req: struct{}{}, - wantCalled: 1, - }, - { - name: "implements validate no error", - req: &validatable{}, - wantCalled: 1, - }, - { - name: "implements validate error", - req: &validatable{err: errors.New("invalid")}, - }, - } - - for _, tt := range tests { - var ( - req = tt.req - wantCalled = tt.wantCalled - called int - ) - - t.Run(tt.name, func(t *testing.T) { - var ( - subject = &Server{} - - spyHandler = grpc.UnaryHandler(func(ctx context.Context, req interface{}) (interface{}, error) { - called++ - return nil, nil - }) - ) - - _, _ = subject.ValidationUnaryInterceptor(context.Background(), req, nil, spyHandler) - assert.Equal(t, wantCalled, called) - }) - } -} - -func TestErrorUnaryInterceptor(t *testing.T) { - tests := []struct { - name string - wantErr error - wantCode codes.Code - }{ - { - name: "not found error", - wantErr: errors.ErrNotFound("foo"), - wantCode: codes.NotFound, - }, - { - name: "invalid error", - wantErr: errors.ErrInvalid("foo"), - wantCode: codes.InvalidArgument, - }, - { - name: "invalid field", - wantErr: errors.InvalidFieldError("bar", "is wrong"), - wantCode: codes.InvalidArgument, - }, - { - name: "empty field", - wantErr: errors.EmptyFieldError("bar"), - wantCode: codes.InvalidArgument, - }, - { - name: "other error", - wantErr: errors.New("foo"), - wantCode: codes.Internal, - }, - { - name: "no error", - }, - } - - for _, tt := range tests { - var ( - wantErr = tt.wantErr - wantCode = tt.wantCode - ) - - t.Run(tt.name, func(t *testing.T) { - var ( - subject = &Server{} - - spyHandler = grpc.UnaryHandler(func(ctx context.Context, req interface{}) (interface{}, error) { - return nil, wantErr - }) - ) - - _, err := subject.ErrorUnaryInterceptor(context.Background(), nil, nil, spyHandler) - if wantErr != nil { - require.Error(t, err) - status := status.Convert(err) - assert.Equal(t, wantCode, status.Code()) - return - } - - require.NoError(t, err) - }) - } -} diff --git a/server/support_test.go b/server/support_test.go index ce4989ec94..f78ad59433 100644 --- a/server/support_test.go +++ b/server/support_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/mock" flipt "go.flipt.io/flipt/rpc/flipt" + "go.flipt.io/flipt/server/cache" "go.flipt.io/flipt/storage" ) @@ -154,3 +155,43 @@ func (m *storeMock) GetEvaluationDistributions(ctx context.Context, ruleID strin args := m.Called(ctx, ruleID) return args.Get(0).([]*storage.EvaluationDistribution), args.Error(1) } + +type cacheSpy struct { + cache.Cacher + + getKeys map[string]struct{} + getCalled int + + setItems map[string][]byte + setCalled int + + deleteKeys map[string]struct{} + deleteCalled int +} + +func newCacheSpy(c cache.Cacher) *cacheSpy { + return &cacheSpy{ + Cacher: c, + getKeys: make(map[string]struct{}), + setItems: make(map[string][]byte), + deleteKeys: make(map[string]struct{}), + } +} + +func (c *cacheSpy) Get(ctx context.Context, key string) ([]byte, bool, error) { + c.getCalled++ + c.getKeys[key] = struct{}{} + return c.Cacher.Get(ctx, key) +} + +func (c *cacheSpy) Set(ctx context.Context, key string, value []byte) error { + c.setCalled++ + c.setItems[key] = value + return c.Cacher.Set(ctx, key, value) +} + +func (c *cacheSpy) Delete(ctx context.Context, key string) error { + c.deleteCalled++ + c.deleteKeys[key] = struct{}{} + return c.Cacher.Delete(ctx, key) +} diff --git a/storage/cache/evaluation.go b/storage/cache/evaluation.go deleted file mode 100644 index 837b978603..0000000000 --- a/storage/cache/evaluation.go +++ /dev/null @@ -1,95 +0,0 @@ -package cache - -import ( - "context" - "fmt" - - "go.flipt.io/flipt/storage" -) - -const ( - evaluationRulesCachePrefix = "eval:rules:flag:" - evaluationDistributionsCachePrefix = "eval:dist:rule:" -) - -// GetEvaluationRules returns all rules applicable to the flagKey provided from the cache if they exist; delegating to the underlying store and caching the result if no error -func (c *Store) GetEvaluationRules(ctx context.Context, flagKey string) ([]*storage.EvaluationRule, error) { - - key := evaluationRulesCachePrefix + flagKey - - // check if rules exists in cache - data, ok, err := c.cache.Get(ctx, key) - if err != nil { - return nil, fmt.Errorf("getting rules from cache: %w", err) - } - - if ok { - c.logger.Debugf("cache hit: %q", key) - - rules, ok := data.([]*storage.EvaluationRule) - if !ok { - // not rules slice, bad cache - // TODO: should we just invalidate the cache instead of returning an error? - return nil, ErrCorrupt - } - - return rules, nil - } - - // rules not in cache, delegate to underlying store - rules, err := c.store.GetEvaluationRules(ctx, flagKey) - if err != nil { - return rules, err - } - - if len(rules) > 0 { - if err := c.cache.Set(ctx, key, rules); err != nil { - return rules, err - } - - c.logger.Debugf("cache miss; added: %q", key) - } - - return rules, nil -} - -// GetEvaluationDistributions returns all distributions applicable to the ruleID provided from the cache if they exist; delegating to the underlying store and caching the result if no error -func (c *Store) GetEvaluationDistributions(ctx context.Context, ruleID string) ([]*storage.EvaluationDistribution, error) { - key := evaluationDistributionsCachePrefix + ruleID - - // check if distributions exists in cache - data, ok, err := c.cache.Get(ctx, key) - if err != nil { - return nil, fmt.Errorf("getting distributions from cache: %w", err) - } - - if ok { - c.logger.Debugf("cache hit: %q", key) - - distributions, ok := data.([]*storage.EvaluationDistribution) - if !ok { - // not distributions slice, bad cache - // TODO: should we just invalidate the cache instead of returning an error? - - return nil, ErrCorrupt - } - - return distributions, nil - } - - // distributions not in cache, delegate to underlying store - distributions, err := c.store.GetEvaluationDistributions(ctx, ruleID) - if err != nil { - return distributions, err - } - - if len(distributions) > 0 { - if err := c.cache.Set(ctx, key, distributions); err != nil { - return distributions, err - } - - c.logger.Debugf("cache miss; added %q", key) - } - - return distributions, nil -} diff --git a/storage/cache/evaluation_test.go b/storage/cache/evaluation_test.go deleted file mode 100644 index 36d6d3d7cc..0000000000 --- a/storage/cache/evaluation_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package cache - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.flipt.io/flipt/storage" -) - -func TestGetEvaluationRules(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*storage.EvaluationRule{ - { - ID: "123", - }, - { - ID: "456", - }, - } - - store.On("GetEvaluationRules", mock.Anything, mock.Anything).Return(ret, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return([]*storage.EvaluationRule{}, false, nil).Once() - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - got, err := subject.GetEvaluationRules(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // shouldnt exist in the cache so it should be added - cacher.AssertCalled(t, "Set", mock.Anything, "eval:rules:flag:foo", mock.Anything) - cacher.AssertCalled(t, "Get", mock.Anything, "eval:rules:flag:foo") - - cacher.On("Get", mock.Anything, mock.Anything).Return(ret, true, nil) - - got, err = subject.GetEvaluationRules(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should already exist in the cache so it should NOT be added - cacher.AssertNumberOfCalls(t, "Set", 1) - cacher.AssertNumberOfCalls(t, "Get", 2) -} - -func TestGetEvaluationRules_NoResults(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*storage.EvaluationRule{} - - store.On("GetEvaluationRules", mock.Anything, mock.Anything).Return(ret, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return([]*storage.EvaluationRule{}, false, nil) - - got, err := subject.GetEvaluationRules(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should not be set in the cache - cacher.AssertNotCalled(t, "Set") - cacher.AssertCalled(t, "Get", mock.Anything, "eval:rules:flag:foo") - - got, err = subject.GetEvaluationRules(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) -} - -func TestGetEvaluationDistributions(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*storage.EvaluationDistribution{ - { - ID: "123", - }, - { - ID: "456", - }, - } - - store.On("GetEvaluationDistributions", mock.Anything, mock.Anything).Return(ret, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return([]*storage.EvaluationDistribution{}, false, nil).Once() - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - got, err := subject.GetEvaluationDistributions(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // shouldnt exist in the cache so it should be added - cacher.AssertCalled(t, "Set", mock.Anything, "eval:dist:rule:foo", mock.Anything) - cacher.AssertCalled(t, "Get", mock.Anything, "eval:dist:rule:foo") - - cacher.On("Get", mock.Anything, mock.Anything).Return(ret, true, nil) - - got, err = subject.GetEvaluationDistributions(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should already exist in the cache so it should NOT be added - cacher.AssertNumberOfCalls(t, "Set", 1) - cacher.AssertNumberOfCalls(t, "Get", 2) -} - -func TestGetEvaluationDistributions_NoResults(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*storage.EvaluationDistribution{} - - store.On("GetEvaluationDistributions", mock.Anything, mock.Anything).Return(ret, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return([]*storage.EvaluationDistribution{}, false, nil) - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything) - - got, err := subject.GetEvaluationDistributions(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should not be set in the cache - cacher.AssertNotCalled(t, "Set") - cacher.AssertCalled(t, "Get", mock.Anything, "eval:dist:rule:foo") - - got, err = subject.GetEvaluationDistributions(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) -} diff --git a/storage/cache/flag.go b/storage/cache/flag.go deleted file mode 100644 index e3bff2edb8..0000000000 --- a/storage/cache/flag.go +++ /dev/null @@ -1,96 +0,0 @@ -package cache - -import ( - "context" - "fmt" - - flipt "go.flipt.io/flipt/rpc/flipt" - "go.flipt.io/flipt/storage" -) - -const flagCachePrefix = "flag:" - -// GetFlag returns the flag from the cache if it exists; otherwise it delegates to the underlying store -// caching the result if no error -func (c *Store) GetFlag(ctx context.Context, k string) (*flipt.Flag, error) { - key := flagCachePrefix + k - - // check if flag exists in cache - data, ok, err := c.cache.Get(ctx, key) - if err != nil { - return nil, fmt.Errorf("getting flag from cache: %w", err) - } - - if ok { - c.logger.Debugf("cache hit: %q", key) - - flag, ok := data.(*flipt.Flag) - if !ok { - // not flag, bad cache - // TODO: should we just invalidate the cache instead of returning an error? - return nil, ErrCorrupt - } - - return flag, nil - } - - // flag not in cache, delegate to underlying store - flag, err := c.store.GetFlag(ctx, k) - if err != nil { - return flag, err - } - - if err := c.cache.Set(ctx, key, flag); err != nil { - return flag, err - } - - c.logger.Debugf("cache miss; added: %q", key) - return flag, nil -} - -// ListFlags delegates to the underlying store -func (c *Store) ListFlags(ctx context.Context, opts ...storage.QueryOption) ([]*flipt.Flag, error) { - return c.store.ListFlags(ctx, opts...) -} - -// CreateFlag delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateFlag(ctx context.Context, r *flipt.CreateFlagRequest) (*flipt.Flag, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateFlag(ctx, r) -} - -// UpdateFlag delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateFlag(ctx context.Context, r *flipt.UpdateFlagRequest) (*flipt.Flag, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateFlag(ctx, r) -} - -// DeleteFlag delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteFlag(ctx context.Context, r *flipt.DeleteFlagRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteFlag(ctx, r) -} - -// CreateVariant delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateVariant(ctx context.Context, r *flipt.CreateVariantRequest) (*flipt.Variant, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateVariant(ctx, r) -} - -// UpdateVariant delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateVariant(ctx context.Context, r *flipt.UpdateVariantRequest) (*flipt.Variant, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateVariant(ctx, r) -} - -// DeleteVariant delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteVariant(ctx context.Context, r *flipt.DeleteVariantRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteVariant(ctx, r) -} diff --git a/storage/cache/flag_test.go b/storage/cache/flag_test.go deleted file mode 100644 index b11c70e542..0000000000 --- a/storage/cache/flag_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package cache - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.flipt.io/flipt/errors" - flipt "go.flipt.io/flipt/rpc/flipt" -) - -func TestGetFlag(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetFlag", mock.Anything, mock.Anything).Return(&flipt.Flag{Key: "foo"}, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Flag{}, false, nil).Once() - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - got, err := subject.GetFlag(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // shouldnt exist in the cache so it should be added - cacher.AssertCalled(t, "Set", mock.Anything, "flag:foo", mock.Anything) - cacher.AssertCalled(t, "Get", mock.Anything, "flag:foo") - - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Flag{Key: "foo"}, true, nil) - - got, err = subject.GetFlag(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should already exist in the cache so it should NOT be added - cacher.AssertNumberOfCalls(t, "Set", 1) - cacher.AssertNumberOfCalls(t, "Get", 2) -} - -func TestGetFlagNotFound(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetFlag", mock.Anything, mock.Anything).Return(&flipt.Flag{}, errors.ErrNotFound("foo")) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Flag{}, false, nil) - - _, err := subject.GetFlag(context.TODO(), "foo") - require.Error(t, err) - - // doesnt exists so it should not be added - cacher.AssertNotCalled(t, "Set") - cacher.AssertCalled(t, "Get", mock.Anything, "flag:foo") -} - -func TestListFlags(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*flipt.Flag{ - {Key: "foo"}, - {Key: "bar"}, - } - - store.On("ListFlags", mock.Anything, mock.Anything).Return(ret, nil) - - got, err := subject.ListFlags(context.TODO()) - require.NoError(t, err) - assert.NotEmpty(t, got) - assert.Len(t, got, 2) - - cacher.AssertNotCalled(t, "Set") - cacher.AssertNotCalled(t, "Get") -} - -func TestCreateFlag(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateFlag", mock.Anything, mock.Anything).Return(&flipt.Flag{Key: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - flag, err := subject.CreateFlag(context.TODO(), &flipt.CreateFlagRequest{Key: "foo"}) - require.NoError(t, err) - assert.NotNil(t, flag) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateFlag(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateFlag", mock.Anything, mock.Anything).Return(&flipt.Flag{Key: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateFlag(context.TODO(), &flipt.UpdateFlagRequest{Key: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteFlag(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteFlag", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteFlag(context.TODO(), &flipt.DeleteFlagRequest{Key: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestCreateVariant(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateVariant", mock.Anything, mock.Anything).Return(&flipt.Variant{FlagKey: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.CreateVariant(context.TODO(), &flipt.CreateVariantRequest{FlagKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateVariant(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateVariant", mock.Anything, mock.Anything).Return(&flipt.Variant{FlagKey: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateVariant(context.TODO(), &flipt.UpdateVariantRequest{FlagKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteVariant(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteVariant", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteVariant(context.TODO(), &flipt.DeleteVariantRequest{FlagKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} diff --git a/storage/cache/memory/cache.go b/storage/cache/memory/cache.go deleted file mode 100644 index a7b0c3a768..0000000000 --- a/storage/cache/memory/cache.go +++ /dev/null @@ -1,106 +0,0 @@ -package memory - -import ( - "context" - "time" - - gocache "github.com/patrickmn/go-cache" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/sirupsen/logrus" -) - -// InMemoryCache wraps gocache.Cache in order to implement Cacher -type InMemoryCache struct { - c *gocache.Cache -} - -const ( - namespace = "flipt" - subsystem = "cache" -) - -var ( - cacheHitTotal = promauto.NewCounterVec(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "hit_total", - Help: "The number of cache hits", - }, []string{"cache"}) - - cacheMissTotal = promauto.NewCounterVec(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "miss_total", - Help: "The number of cache misses", - }, []string{"cache"}) - - cacheItemCount = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "item_count", - Help: "The number of items currently in the cache", - }, []string{"cache"}) - - cacheEvictionTotal = promauto.NewCounterVec(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "eviction_total", - Help: "The number of times an item is evicted from the cache", - }, []string{"cache"}) - - cacheFlushTotal = promauto.NewCounterVec(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "flush_total", - Help: "The number of times the cache is flushed", - }, []string{"cache"}) -) - -// NewCache creates a new InMemoryCache with the provided expiration and evictionInterval -func NewCache(expiration time.Duration, evictionInterval time.Duration, logger logrus.FieldLogger) *InMemoryCache { - logger = logger.WithField("cache", "memory") - - c := gocache.New(expiration, evictionInterval) - c.OnEvicted(func(s string, _ interface{}) { - cacheEvictionTotal.WithLabelValues("memory").Inc() - cacheItemCount.WithLabelValues("memory").Dec() - logger.Debugf("evicted key: %q", s) - }) - - return &InMemoryCache{c: c} -} - -func (i *InMemoryCache) Get(_ context.Context, key string) (interface{}, bool, error) { - v, ok := i.c.Get(key) - if !ok { - cacheMissTotal.WithLabelValues("memory").Inc() - return nil, false, nil - } - - cacheHitTotal.WithLabelValues("memory").Inc() - return v, true, nil -} - -func (i *InMemoryCache) Set(_ context.Context, key string, value interface{}) error { - i.c.SetDefault(key, value) - cacheItemCount.WithLabelValues("memory").Inc() - return nil -} - -func (i *InMemoryCache) Delete(_ context.Context, key string) error { - i.c.Delete(key) - cacheItemCount.WithLabelValues("memory").Dec() - return nil -} - -func (i *InMemoryCache) Flush(_ context.Context) error { - i.c.Flush() - cacheItemCount.WithLabelValues("memory").Set(0) - cacheFlushTotal.WithLabelValues("memory").Inc() - return nil -} - -func (i *InMemoryCache) String() string { - return "memory" -} diff --git a/storage/cache/rule.go b/storage/cache/rule.go deleted file mode 100644 index d395d8bd21..0000000000 --- a/storage/cache/rule.go +++ /dev/null @@ -1,103 +0,0 @@ -package cache - -import ( - "context" - "fmt" - - flipt "go.flipt.io/flipt/rpc/flipt" - "go.flipt.io/flipt/storage" -) - -const ruleCachePrefix = "rule:" - -// GetRule returns the rule from the cache if it exists; otherwise it delegates to the underlying store -// caching the result if no error -func (c *Store) GetRule(ctx context.Context, id string) (*flipt.Rule, error) { - key := ruleCachePrefix + id - - // check if rule exists in cache - data, ok, err := c.cache.Get(ctx, key) - if err != nil { - return nil, fmt.Errorf("getting rule from cache: %w", err) - } - - if ok { - c.logger.Debugf("cache hit: %q", key) - - rule, ok := data.(*flipt.Rule) - if !ok { - // not rule, bad cache - // TODO: should we just invalidate the cache instead of returning an error? - return nil, ErrCorrupt - } - - return rule, nil - } - - // rule not in cache, delegate to underlying store - rule, err := c.store.GetRule(ctx, id) - if err != nil { - return rule, err - } - - if err := c.cache.Set(ctx, key, rule); err != nil { - return rule, err - } - - c.logger.Debugf("cache miss; added: %q", key) - return rule, nil -} - -// ListRules delegates to the underlying store -func (c *Store) ListRules(ctx context.Context, flagKey string, opts ...storage.QueryOption) ([]*flipt.Rule, error) { - return c.store.ListRules(ctx, flagKey, opts...) -} - -// CreateRule delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (*flipt.Rule, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateRule(ctx, r) -} - -// UpdateRule delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateRule(ctx context.Context, r *flipt.UpdateRuleRequest) (*flipt.Rule, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateRule(ctx, r) -} - -// DeleteRule delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteRule(ctx context.Context, r *flipt.DeleteRuleRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteRule(ctx, r) -} - -// OrderRules delegates to the underlying store, flushing the cache in the process -func (c *Store) OrderRules(ctx context.Context, r *flipt.OrderRulesRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.OrderRules(ctx, r) -} - -// CreateDistribution delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateDistribution(ctx context.Context, r *flipt.CreateDistributionRequest) (*flipt.Distribution, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateDistribution(ctx, r) -} - -// UpdateDistribution delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateDistribution(ctx context.Context, r *flipt.UpdateDistributionRequest) (*flipt.Distribution, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateDistribution(ctx, r) -} - -// DeleteDistribution delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteDistribution(ctx context.Context, r *flipt.DeleteDistributionRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteDistribution(ctx, r) -} diff --git a/storage/cache/rule_test.go b/storage/cache/rule_test.go deleted file mode 100644 index 6502881a09..0000000000 --- a/storage/cache/rule_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package cache - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.flipt.io/flipt/errors" - flipt "go.flipt.io/flipt/rpc/flipt" -) - -func TestGetRule(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetRule", mock.Anything, mock.Anything).Return(&flipt.Rule{Id: "foo"}, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Rule{}, false, nil).Once() - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - got, err := subject.GetRule(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // shouldnt exist in the cache so it should be added - cacher.AssertCalled(t, "Set", mock.Anything, "rule:foo", mock.Anything) - cacher.AssertCalled(t, "Get", mock.Anything, "rule:foo") - - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Rule{Id: "foo"}, true, nil) - - got, err = subject.GetRule(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should already exist in the cache so it should NOT be added - cacher.AssertNumberOfCalls(t, "Set", 1) - cacher.AssertNumberOfCalls(t, "Get", 2) -} - -func TestGetRuleNotFound(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetRule", mock.Anything, mock.Anything).Return(&flipt.Rule{}, errors.ErrNotFound("foo")) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Rule{}, false, nil) - - _, err := subject.GetRule(context.TODO(), "foo") - require.Error(t, err) - - // doesnt exists so it should not be added - cacher.AssertNotCalled(t, "Set") - cacher.AssertCalled(t, "Get", mock.Anything, "rule:foo") -} - -func TestListRules(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*flipt.Rule{ - {Id: "foo"}, - {Id: "bar"}, - } - - store.On("ListRules", mock.Anything, "foo", mock.Anything).Return(ret, nil) - - got, err := subject.ListRules(context.TODO(), "foo") - require.NoError(t, err) - assert.NotEmpty(t, got) - assert.Len(t, got, 2) - - cacher.AssertNotCalled(t, "Get") - cacher.AssertNotCalled(t, "Set") -} - -func TestCreateRule(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateRule", mock.Anything, mock.Anything).Return(&flipt.Rule{Id: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - rule, err := subject.CreateRule(context.TODO(), &flipt.CreateRuleRequest{FlagKey: "foo"}) - require.NoError(t, err) - assert.NotNil(t, rule) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateRule(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateRule", mock.Anything, mock.Anything).Return(&flipt.Rule{Id: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateRule(context.TODO(), &flipt.UpdateRuleRequest{Id: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteRule(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteRule", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteRule(context.TODO(), &flipt.DeleteRuleRequest{Id: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestCreateDistribution(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateDistribution", mock.Anything, mock.Anything).Return(&flipt.Distribution{RuleId: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.CreateDistribution(context.TODO(), &flipt.CreateDistributionRequest{RuleId: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateDistribution(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateDistribution", mock.Anything, mock.Anything).Return(&flipt.Distribution{RuleId: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateDistribution(context.TODO(), &flipt.UpdateDistributionRequest{RuleId: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteDistribution(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteDistribution", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteDistribution(context.TODO(), &flipt.DeleteDistributionRequest{RuleId: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} diff --git a/storage/cache/segment.go b/storage/cache/segment.go deleted file mode 100644 index 3fa9ef7671..0000000000 --- a/storage/cache/segment.go +++ /dev/null @@ -1,96 +0,0 @@ -package cache - -import ( - "context" - "fmt" - - flipt "go.flipt.io/flipt/rpc/flipt" - "go.flipt.io/flipt/storage" -) - -const segmentCachePrefix = "segment:" - -// GetSegment returns the segment from the cache if it exists; otherwise it delegates to the underlying store -// caching the result if no error -func (c *Store) GetSegment(ctx context.Context, k string) (*flipt.Segment, error) { - key := segmentCachePrefix + k - - // check if segment exists in cache - data, ok, err := c.cache.Get(ctx, key) - if err != nil { - return nil, fmt.Errorf("getting segment from cache: %w", err) - } - - if ok { - c.logger.Debugf("cache hit: %q", key) - - segment, ok := data.(*flipt.Segment) - if !ok { - // not segment, bad cache - // TODO: should we just invalidate the cache instead of returning an error? - return nil, ErrCorrupt - } - - return segment, nil - } - - // segment not in cache, delegate to underlying store - segment, err := c.store.GetSegment(ctx, k) - if err != nil { - return segment, err - } - - if err := c.cache.Set(ctx, key, segment); err != nil { - return segment, err - } - - c.logger.Debugf("cache miss; added: %q", key) - return segment, nil -} - -// ListSegments delegates to the underlying store -func (c *Store) ListSegments(ctx context.Context, opts ...storage.QueryOption) ([]*flipt.Segment, error) { - return c.store.ListSegments(ctx, opts...) -} - -// CreateSegment delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateSegment(ctx context.Context, r *flipt.CreateSegmentRequest) (*flipt.Segment, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateSegment(ctx, r) -} - -// UpdateSegment delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateSegment(ctx context.Context, r *flipt.UpdateSegmentRequest) (*flipt.Segment, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateSegment(ctx, r) -} - -// DeleteSegment delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteSegment(ctx context.Context, r *flipt.DeleteSegmentRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteSegment(ctx, r) -} - -// CreateConstraint delegates to the underlying store, flushing the cache in the process -func (c *Store) CreateConstraint(ctx context.Context, r *flipt.CreateConstraintRequest) (*flipt.Constraint, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.CreateConstraint(ctx, r) -} - -// UpdateConstraint delegates to the underlying store, flushing the cache in the process -func (c *Store) UpdateConstraint(ctx context.Context, r *flipt.UpdateConstraintRequest) (*flipt.Constraint, error) { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.UpdateConstraint(ctx, r) -} - -// DeleteConstraint delegates to the underlying store, flushing the cache in the process -func (c *Store) DeleteConstraint(ctx context.Context, r *flipt.DeleteConstraintRequest) error { - c.cache.Flush(ctx) - c.logger.Debug("flushed cache") - return c.store.DeleteConstraint(ctx, r) -} diff --git a/storage/cache/segment_test.go b/storage/cache/segment_test.go deleted file mode 100644 index eb23531fb4..0000000000 --- a/storage/cache/segment_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package cache - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.flipt.io/flipt/errors" - flipt "go.flipt.io/flipt/rpc/flipt" -) - -func TestGetSegment(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetSegment", mock.Anything, mock.Anything).Return(&flipt.Segment{Key: "foo"}, nil) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Segment{}, false, nil).Once() - cacher.On("Set", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - got, err := subject.GetSegment(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // shouldnt exist in the cache so it should be added - cacher.AssertCalled(t, "Get", mock.Anything, "segment:foo") - cacher.AssertCalled(t, "Set", mock.Anything, "segment:foo", mock.Anything) - - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Segment{Key: "foo"}, true, nil) - - got, err = subject.GetSegment(context.TODO(), "foo") - require.NoError(t, err) - assert.NotNil(t, got) - - // should already exist in the cache so it should NOT be added - cacher.AssertNumberOfCalls(t, "Set", 1) - cacher.AssertNumberOfCalls(t, "Get", 2) -} - -func TestGetSegmentNotFound(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("GetSegment", mock.Anything, mock.Anything).Return(&flipt.Segment{}, errors.ErrNotFound("foo")) - cacher.On("Get", mock.Anything, mock.Anything).Return(&flipt.Segment{}, false, nil) - - _, err := subject.GetSegment(context.TODO(), "foo") - require.Error(t, err) - - // doesnt exists so it should not be added - cacher.AssertNotCalled(t, "Set") - cacher.AssertCalled(t, "Get", mock.Anything, "segment:foo") -} - -func TestListSegments(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - ret := []*flipt.Segment{ - {Key: "foo"}, - {Key: "bar"}, - } - - store.On("ListSegments", mock.Anything, mock.Anything).Return(ret, nil) - - got, err := subject.ListSegments(context.TODO()) - require.NoError(t, err) - assert.NotEmpty(t, got) - assert.Len(t, got, 2) - - cacher.AssertNotCalled(t, "Set") - cacher.AssertNotCalled(t, "Get") -} - -func TestCreateSegment(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateSegment", mock.Anything, mock.Anything).Return(&flipt.Segment{Key: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - segment, err := subject.CreateSegment(context.TODO(), &flipt.CreateSegmentRequest{Key: "foo"}) - require.NoError(t, err) - assert.NotNil(t, segment) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateSegment(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateSegment", mock.Anything, mock.Anything).Return(&flipt.Segment{Key: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateSegment(context.TODO(), &flipt.UpdateSegmentRequest{Key: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteSegment(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteSegment", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteSegment(context.TODO(), &flipt.DeleteSegmentRequest{Key: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestCreateConstraint(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("CreateConstraint", mock.Anything, mock.Anything).Return(&flipt.Constraint{SegmentKey: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.CreateConstraint(context.TODO(), &flipt.CreateConstraintRequest{SegmentKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestUpdateConstraint(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("UpdateConstraint", mock.Anything, mock.Anything).Return(&flipt.Constraint{SegmentKey: "foo"}, nil) - cacher.On("Flush", mock.Anything).Return(nil) - - _, err := subject.UpdateConstraint(context.TODO(), &flipt.UpdateConstraintRequest{SegmentKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} - -func TestDeleteConstraint(t *testing.T) { - var ( - store = &storeMock{} - cacher = &cacherSpy{} - subject = NewStore(logger, cacher, store) - ) - - store.On("DeleteConstraint", mock.Anything, mock.Anything).Return(nil) - cacher.On("Flush", mock.Anything).Return(nil) - - err := subject.DeleteConstraint(context.TODO(), &flipt.DeleteConstraintRequest{SegmentKey: "foo"}) - require.NoError(t, err) - - // should not be added - cacher.AssertNotCalled(t, "Set") - // should flush cache - cacher.AssertCalled(t, "Flush", mock.Anything) -} diff --git a/storage/cache/store.go b/storage/cache/store.go deleted file mode 100644 index e99d664295..0000000000 --- a/storage/cache/store.go +++ /dev/null @@ -1,30 +0,0 @@ -package cache - -import ( - "fmt" - - "github.com/sirupsen/logrus" - "go.flipt.io/flipt/storage" -) - -var _ storage.Store = &Store{} - -// Store wraps an existing storage.Store and provides caching -type Store struct { - logger *logrus.Entry - cache Cacher - store storage.Store -} - -// NewStore creates a new *CacheStore -func NewStore(logger *logrus.Entry, cache Cacher, store storage.Store) *Store { - return &Store{ - logger: logger, - cache: cache, - store: store, - } -} - -func (c *Store) String() string { - return fmt.Sprintf("[cached] %s", c.store.String()) -} diff --git a/storage/cache/support_test.go b/storage/cache/support_test.go deleted file mode 100644 index 4aa3db1525..0000000000 --- a/storage/cache/support_test.go +++ /dev/null @@ -1,187 +0,0 @@ -package cache - -import ( - "context" - - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/mock" - flipt "go.flipt.io/flipt/rpc/flipt" - "go.flipt.io/flipt/storage" -) - -var ( - l, _ = test.NewNullLogger() - logger = logrus.NewEntry(l) -) - -// cacherSpy is a simple in memory map that acts as a cache -// and records interactions for tests -type cacherSpy struct { - mock.Mock -} - -func (s *cacherSpy) Get(ctx context.Context, key string) (interface{}, bool, error) { - args := s.Called(ctx, key) - return args.Get(0), args.Bool(1), args.Error(2) -} - -func (s *cacherSpy) Set(ctx context.Context, key string, value interface{}) error { - args := s.Called(ctx, key, value) - return args.Error(0) -} - -func (s *cacherSpy) Delete(ctx context.Context, key string) error { - args := s.Called(ctx, key) - return args.Error(0) -} - -func (s *cacherSpy) Flush(ctx context.Context) error { - args := s.Called(ctx) - return args.Error(0) -} - -var _ storage.Store = &storeMock{} - -type storeMock struct { - mock.Mock -} - -func (m *storeMock) String() string { - return "mock" -} - -func (m *storeMock) GetFlag(ctx context.Context, key string) (*flipt.Flag, error) { - args := m.Called(ctx, key) - return args.Get(0).(*flipt.Flag), args.Error(1) -} - -func (m *storeMock) ListFlags(ctx context.Context, opts ...storage.QueryOption) ([]*flipt.Flag, error) { - args := m.Called(ctx, opts) - return args.Get(0).([]*flipt.Flag), args.Error(1) -} - -func (m *storeMock) CreateFlag(ctx context.Context, r *flipt.CreateFlagRequest) (*flipt.Flag, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Flag), args.Error(1) -} - -func (m *storeMock) UpdateFlag(ctx context.Context, r *flipt.UpdateFlagRequest) (*flipt.Flag, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Flag), args.Error(1) -} - -func (m *storeMock) DeleteFlag(ctx context.Context, r *flipt.DeleteFlagRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) CreateVariant(ctx context.Context, r *flipt.CreateVariantRequest) (*flipt.Variant, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Variant), args.Error(1) -} - -func (m *storeMock) UpdateVariant(ctx context.Context, r *flipt.UpdateVariantRequest) (*flipt.Variant, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Variant), args.Error(1) -} - -func (m *storeMock) DeleteVariant(ctx context.Context, r *flipt.DeleteVariantRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) GetSegment(ctx context.Context, key string) (*flipt.Segment, error) { - args := m.Called(ctx, key) - return args.Get(0).(*flipt.Segment), args.Error(1) -} - -func (m *storeMock) ListSegments(ctx context.Context, opts ...storage.QueryOption) ([]*flipt.Segment, error) { - args := m.Called(ctx, opts) - return args.Get(0).([]*flipt.Segment), args.Error(1) -} - -func (m *storeMock) CreateSegment(ctx context.Context, r *flipt.CreateSegmentRequest) (*flipt.Segment, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Segment), args.Error(1) -} - -func (m *storeMock) UpdateSegment(ctx context.Context, r *flipt.UpdateSegmentRequest) (*flipt.Segment, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Segment), args.Error(1) -} - -func (m *storeMock) DeleteSegment(ctx context.Context, r *flipt.DeleteSegmentRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) CreateConstraint(ctx context.Context, r *flipt.CreateConstraintRequest) (*flipt.Constraint, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Constraint), args.Error(1) -} - -func (m *storeMock) UpdateConstraint(ctx context.Context, r *flipt.UpdateConstraintRequest) (*flipt.Constraint, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Constraint), args.Error(1) -} - -func (m *storeMock) DeleteConstraint(ctx context.Context, r *flipt.DeleteConstraintRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) GetRule(ctx context.Context, id string) (*flipt.Rule, error) { - args := m.Called(ctx, id) - return args.Get(0).(*flipt.Rule), args.Error(1) -} - -func (m *storeMock) ListRules(ctx context.Context, flagKey string, opts ...storage.QueryOption) ([]*flipt.Rule, error) { - args := m.Called(ctx, flagKey, opts) - return args.Get(0).([]*flipt.Rule), args.Error(1) -} - -func (m *storeMock) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (*flipt.Rule, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Rule), args.Error(1) -} - -func (m *storeMock) UpdateRule(ctx context.Context, r *flipt.UpdateRuleRequest) (*flipt.Rule, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Rule), args.Error(1) -} - -func (m *storeMock) DeleteRule(ctx context.Context, r *flipt.DeleteRuleRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) OrderRules(ctx context.Context, r *flipt.OrderRulesRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) CreateDistribution(ctx context.Context, r *flipt.CreateDistributionRequest) (*flipt.Distribution, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Distribution), args.Error(1) -} - -func (m *storeMock) UpdateDistribution(ctx context.Context, r *flipt.UpdateDistributionRequest) (*flipt.Distribution, error) { - args := m.Called(ctx, r) - return args.Get(0).(*flipt.Distribution), args.Error(1) -} - -func (m *storeMock) DeleteDistribution(ctx context.Context, r *flipt.DeleteDistributionRequest) error { - args := m.Called(ctx, r) - return args.Error(0) -} - -func (m *storeMock) GetEvaluationRules(ctx context.Context, flagKey string) ([]*storage.EvaluationRule, error) { - args := m.Called(ctx, flagKey) - return args.Get(0).([]*storage.EvaluationRule), args.Error(1) -} - -func (m *storeMock) GetEvaluationDistributions(ctx context.Context, ruleID string) ([]*storage.EvaluationDistribution, error) { - args := m.Called(ctx, ruleID) - return args.Get(0).([]*storage.EvaluationDistribution), args.Error(1) -} diff --git a/storage/sql/flag_test.go b/storage/sql/flag_test.go index dd83f0d80e..93260fe4c9 100644 --- a/storage/sql/flag_test.go +++ b/storage/sql/flag_test.go @@ -4,14 +4,9 @@ import ( "context" "fmt" "testing" - "time" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" flipt "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/storage" - "go.flipt.io/flipt/storage/cache" - "go.flipt.io/flipt/storage/cache/memory" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" @@ -615,49 +610,3 @@ func BenchmarkGetFlag(b *testing.B) { benchFlag = f }) } - -func BenchmarkGetFlag_CacheMemory(b *testing.B) { - var ( - l, _ = test.NewNullLogger() - logger = logrus.NewEntry(l) - cacher = memory.NewCache(5*time.Minute, 10*time.Minute, logger) - storeCache = cache.NewStore(logger, cacher, store) - - ctx = context.Background() - - flag, err = storeCache.CreateFlag(ctx, &flipt.CreateFlagRequest{ - Key: b.Name(), - Name: "foo", - Description: "bar", - Enabled: true, - }) - ) - - if err != nil { - b.Fatal(err) - } - - _, err = storeCache.CreateVariant(ctx, &flipt.CreateVariantRequest{ - FlagKey: flag.Key, - Key: "baz", - }) - - if err != nil { - b.Fatal(err) - } - - var f *flipt.Flag - - // warm the cache - f, _ = storeCache.GetFlag(context.TODO(), flag.Key) - - b.ResetTimer() - - b.Run("get-flag-cache", func(b *testing.B) { - for i := 0; i < b.N; i++ { - f, _ = storeCache.GetFlag(context.TODO(), flag.Key) - } - - benchFlag = f - }) -} diff --git a/storage/sql/rule_test.go b/storage/sql/rule_test.go index d6145a3d50..0f0412486a 100644 --- a/storage/sql/rule_test.go +++ b/storage/sql/rule_test.go @@ -5,16 +5,11 @@ import ( "fmt" "sort" "testing" - "time" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" flipt "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/storage" - "go.flipt.io/flipt/storage/cache" - "go.flipt.io/flipt/storage/cache/memory" ) func TestGetRule(t *testing.T) { @@ -659,70 +654,3 @@ func BenchmarkGetRule(b *testing.B) { benchRule = r }) } - -func BenchmarkGetRule_CacheMemory(b *testing.B) { - var ( - l, _ = test.NewNullLogger() - logger = logrus.NewEntry(l) - cacher = memory.NewCache(5*time.Minute, 10*time.Minute, logger) - storeCache = cache.NewStore(logger, cacher, store) - - ctx = context.Background() - flag, err = store.CreateFlag(ctx, &flipt.CreateFlagRequest{ - Key: b.Name(), - Name: "foo", - Description: "bar", - Enabled: true, - }) - ) - - if err != nil { - b.Fatal(err) - } - - _, err = store.CreateVariant(ctx, &flipt.CreateVariantRequest{ - FlagKey: flag.Key, - Key: b.Name(), - Name: "foo", - Description: "bar", - }) - - if err != nil { - b.Fatal(err) - } - - segment, err := store.CreateSegment(ctx, &flipt.CreateSegmentRequest{ - Key: b.Name(), - Name: "foo", - Description: "bar", - }) - - if err != nil { - b.Fatal(err) - } - - rule, err := storeCache.CreateRule(ctx, &flipt.CreateRuleRequest{ - FlagKey: flag.Key, - SegmentKey: segment.Key, - Rank: 1, - }) - - if err != nil { - b.Fatal(err) - } - - var r *flipt.Rule - - // warm the cache - r, _ = storeCache.GetRule(ctx, rule.Id) - - b.ResetTimer() - - b.Run("get-rule-cache", func(b *testing.B) { - for i := 0; i < b.N; i++ { - r, _ = storeCache.GetRule(ctx, rule.Id) - } - - benchRule = r - }) -} diff --git a/storage/sql/segment_test.go b/storage/sql/segment_test.go index 9f0022707f..f85d58b21f 100644 --- a/storage/sql/segment_test.go +++ b/storage/sql/segment_test.go @@ -3,14 +3,9 @@ package sql import ( "context" "testing" - "time" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" flipt "go.flipt.io/flipt/rpc/flipt" "go.flipt.io/flipt/storage" - "go.flipt.io/flipt/storage/cache" - "go.flipt.io/flipt/storage/cache/memory" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" @@ -481,51 +476,3 @@ func BenchmarkGetSegment(b *testing.B) { benchSegment = s }) } - -func BenchmarkGetSegment_CacheMemory(b *testing.B) { - var ( - l, _ = test.NewNullLogger() - logger = logrus.NewEntry(l) - cacher = memory.NewCache(5*time.Minute, 10*time.Minute, logger) - storeCache = cache.NewStore(logger, cacher, store) - - ctx = context.Background() - - segment, err = storeCache.CreateSegment(ctx, &flipt.CreateSegmentRequest{ - Key: b.Name(), - Name: "foo", - Description: "bar", - }) - ) - - if err != nil { - b.Fatal(err) - } - - _, err = storeCache.CreateConstraint(ctx, &flipt.CreateConstraintRequest{ - SegmentKey: segment.Key, - Type: flipt.ComparisonType_STRING_COMPARISON_TYPE, - Property: "foo", - Operator: "EQ", - Value: "bar", - }) - - if err != nil { - b.Fatal(err) - } - - var s *flipt.Segment - - // warm the cache - s, _ = storeCache.GetSegment(context.TODO(), segment.Key) - - b.ResetTimer() - - b.Run("get-segment-cache", func(b *testing.B) { - for i := 0; i < b.N; i++ { - s, _ = storeCache.GetSegment(context.TODO(), segment.Key) - } - - benchSegment = s - }) -} diff --git a/test/api.sh b/test/api.sh index 3cea7ecb09..03fbd7a530 100755 --- a/test/api.sh +++ b/test/api.sh @@ -8,6 +8,7 @@ export SHAKEDOWN_URL="http://127.0.0.1:8080" source ./test/helpers/shakedown/shakedown.sh +CONFIG_FILE=${1:-"test.yml"} FLIPT_PID="/tmp/flipt.api.pid" finish() { @@ -289,9 +290,9 @@ step_9_test_metrics() run() { # run any pending db migrations - ./bin/flipt migrate ---config ./test/config/test.yml &> /dev/null + ./bin/flipt migrate ---config "./test/config/$CONFIG_FILE" &> /dev/null - ./bin/flipt --config ./test/config/test.yml &> /dev/null & + ./bin/flipt --config "./test/config/$CONFIG_FILE" &> out.log & echo $! > "$FLIPT_PID" sleep 5 diff --git a/test/config/redis.yml b/test/config/redis.yml new file mode 100644 index 0000000000..67faadde5a --- /dev/null +++ b/test/config/redis.yml @@ -0,0 +1,15 @@ +log: + level: DEBUG + +db: + url: file:./test/flipt.db + migrations: + path: ./config/migrations + +cache: + enabled: true + backend: "redis" + ttl: 60s + redis: + host: "redis" + port: 6379 diff --git a/test/ui.sh b/test/ui.sh index 781a621c0d..a1cbd731dc 100755 --- a/test/ui.sh +++ b/test/ui.sh @@ -4,7 +4,7 @@ set -euo pipefail cd "$(dirname "$0")/.." || exit -FLIPT_PID="/tmp/flipt.api.pid" +FLIPT_PID="/tmp/flipt.ui.pid" finish() { [[ -f "$FLIPT_PID" ]] && kill -9 `cat $FLIPT_PID` @@ -31,7 +31,8 @@ run() ./test/helpers/wait-for-it/wait-for-it.sh "$flipt_host" -t 30 - cd "ui" && npm test && npx playwright test + cd "ui" && npm ci + npm test && npx playwright test } run