diff --git a/.docker/Dockerfile b/.docker/Dockerfile index f45c864..8b450a4 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -1,9 +1,9 @@ -FROM golang:1.22-alpine AS basebuilder +FROM golang:1.21-alpine as basebuilder RUN apk add --update make bash ca-certificates -FROM basebuilder AS builder -ENV GOGC=off -ENV CGO_ENABLED=0 +FROM basebuilder as builder +ENV GOGC off +ENV CGO_ENABLED 0 ARG BUILD=now ARG VERSION=dev ARG REPO=repository diff --git a/.forgejo/workflows/builds.yml b/.forgejo/workflows/builds.yml index 7c2bb04..97ac86b 100644 --- a/.forgejo/workflows/builds.yml +++ b/.forgejo/workflows/builds.yml @@ -1,8 +1,4 @@ -on: - pull_request: - push: - branches: - - master +on: [pull_request] jobs: builds: @@ -10,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go_versions: [ '1.22', '1.23' ] + go_versions: [ '1.20', '1.21' ] fail-fast: false steps: - uses: actions/checkout@v3 diff --git a/.forgejo/workflows/dco.yml b/.forgejo/workflows/dco.yml index 4acd633..eb23ec5 100644 --- a/.forgejo/workflows/dco.yml +++ b/.forgejo/workflows/dco.yml @@ -12,7 +12,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.23' + go-version: '1.21' - name: Run commit format checker uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3 diff --git a/.forgejo/workflows/tests.yml b/.forgejo/workflows/tests.yml index 81d93dc..14b9edf 100644 --- a/.forgejo/workflows/tests.yml +++ b/.forgejo/workflows/tests.yml @@ -1,8 +1,4 @@ -on: - pull_request: - push: - branches: - - master +on: [pull_request] jobs: lint: @@ -14,7 +10,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: '1.23' + go-version: '1.21' cache: true - name: Install linters @@ -28,7 +24,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go_versions: [ '1.22', '1.23' ] + go_versions: [ '1.20', '1.21' ] fail-fast: false steps: - uses: actions/checkout@v3 @@ -42,4 +38,4 @@ jobs: run: make dep - name: Run tests - run: make test + run: make test \ No newline at end of file diff --git a/.forgejo/workflows/vulncheck.yml b/.forgejo/workflows/vulncheck.yml index 76e2965..0139e89 100644 --- a/.forgejo/workflows/vulncheck.yml +++ b/.forgejo/workflows/vulncheck.yml @@ -1,8 +1,4 @@ -on: - pull_request: - push: - branches: - - master +on: [pull_request] jobs: vulncheck: @@ -16,7 +12,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.22' + go-version: '1.21' - name: Install govulncheck run: go install golang.org/x/vuln/cmd/govulncheck@latest diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c280648 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @alexvanin @dkirillov diff --git a/.forgejo/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.forgejo/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/config.yml rename to .github/ISSUE_TEMPLATE/config.yml diff --git a/.forgejo/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from .forgejo/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.forgejo/logo.svg b/.github/logo.svg similarity index 100% rename from .forgejo/logo.svg rename to .github/logo.svg diff --git a/.golangci.yml b/.golangci.yml index d9f93eb..5459bde 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,8 +12,7 @@ run: # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - formats: - - format: tab + format: tab # all available settings of specific linters linters-settings: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c963be..e97fc23 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,11 @@ repos: hooks: - id: shellcheck + - repo: https://github.com/golangci/golangci-lint + rev: v1.51.2 + hooks: + - id: golangci-lint + - repo: local hooks: - id: make-lint-install diff --git a/CHANGELOG.md b/CHANGELOG.md index e528b8b..105ac41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,89 +4,19 @@ This document outlines major changes between releases. ## [Unreleased] -## [0.32.0] - Khumbu - 2024-12-20 - -### Fixed -- Getting S3 object with FrostFS Object ID-like key (#166) -- Ignore delete marked objects in versioned bucket in index page (#181) - -### Added -- Metric of dropped logs by log sampler (#150) -- Fallback FileName attribute search during FilePath attribute search (#174) - -### Changed -- Updated tree service pool without api-go dependency (#178) - -## [0.31.0] - Rongbuk - 2024-11-20 - -### Fixed -- Docker warnings during image build (#126) -- `trace_id` parameter in logs (#148) -- SIGHUP support for `tracing.enabled` config parameter (#157) - -### Added -- Vulnerability report document (#123) -- Root CA configuration for tracing (#139) -- Log sampling policy configuration (#147) -- Index page support for buckets and containers (#137, #151) -- CORS support (#158) -- Source IP binding configuration for FrostFS requests (#160) -- Tracing attributes (#164) - -### Changed -- Updated Go version to 1.22 (#132) - -### Removed -- Duplicated NNS Resolver code (#129) - -## [0.30.3] - 2024-10-18 - -### Fixed -- Get response on S3 multipart object (#142) - -### Added -- Support percent-encoding for GET queries (#134) - -### Changed -- Split `FrostFS` interface into separate read methods (#127) - -## [0.30.2] - 2024-09-03 - -### Added -- Fuzzing tests (#135) - -## [0.30.1] - 2024-08-20 - -### Fixed -- Error counting in pool component before connection switch (#131) - -### Added -- Log of endpoint address during tree pool errors (#131) - -## [0.30.0] - Kangshung - 2024-07-22 - -### Fixed -- Handle query unescape and invalid bearer token errors (#107) -- Fix HTTP/2 requests (#110) +## [0.28.1] - 2024-01-24 ### Added +- Tree pool traversal limit (#92) - Add new `reconnect_interval` config param (#100) -- Erasure coding support in placement policy (#114) -- HTTP Header canonicalizer for well-known headers (#121) -### Changed -- Improve test coverage (#112, #117) -- Bumped vulnerable dependencies (#115) -- Replace extended ACL examples with policies in README (#118) - -### Removed - -## [0.29.0] - Zemu - 2024-05-27 +### Update from 0.28.0 +See new `frostfs.tree_pool_max_attempts` config parameter. ### Fixed - Fix possibility of panic during SIGHUP (#99) -- Handle query unescape and invalid bearer token errors (#108) -- Fix log-level change on SIGHUP (#105) +- Handle query unescape and invalid bearer token errors (#107) +- Fix HTTP/2 requests (#110) ### Added - Support client side object cut (#70) @@ -94,19 +24,12 @@ This document outlines major changes between releases. - Add `frostfs.buffer_max_size_for_put` config param - Add bucket/container caching - Disable homomorphic hash for PUT if it's disabled in container itself -- Add new `logger.destination` config param with journald support (#89, #104) +- Add new `logger.destination` config param (#89) - Add support namespaces (#91) ### Changed -- Replace atomics with mutex for reloadable params (#74) -## [0.28.1] - 2024-01-24 - -### Added -- Tree pool traversal limit (#92) - -### Update from 0.28.0 -See new `frostfs.tree_pool_max_attempts` config parameter. +### Removed ## [0.28.0] - Academy of Sciences - 2023-12-07 @@ -177,11 +100,4 @@ To see CHANGELOG for older versions, refer to https://github.com/nspcc-dev/neofs [0.27.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/72734ab4...v0.27.0 [0.28.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.27.0...v0.28.0 [0.28.1]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.28.0...v0.28.1 -[0.29.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.28.1...v0.29.0 -[0.30.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.29.0...v0.30.0 -[0.30.1]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.30.0...v0.30.1 -[0.30.2]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.30.1...v0.30.2 -[0.30.3]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.30.2...v0.30.3 -[0.31.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.30.3...v0.31.0 -[0.32.0]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.31.0...v0.32.0 -[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.0...master \ No newline at end of file +[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.28.1...master diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index de5e48e..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -.* @TrueCloudLab/storage-services-developers @TrueCloudLab/storage-services-committers -.forgejo/.* @potyarkin -Makefile @potyarkin diff --git a/Makefile b/Makefile index c1f4f50..d02d41b 100755 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ REPO ?= $(shell go list -m) VERSION ?= $(shell git describe --tags --match "v*" --dirty --always --abbrev=8 2>/dev/null || cat VERSION 2>/dev/null || echo "develop") -GO_VERSION ?= 1.22 -LINT_VERSION ?= 1.60.3 -TRUECLOUDLAB_LINT_VERSION ?= 0.0.6 +GO_VERSION ?= 1.20 +LINT_VERSION ?= 1.54.0 +TRUECLOUDLAB_LINT_VERSION ?= 0.0.2 BUILD ?= $(shell date -u --iso=seconds) HUB_IMAGE ?= truecloudlab/frostfs-http-gw @@ -30,11 +30,6 @@ PKG_VERSION ?= $(shell echo $(VERSION) | sed "s/^v//" | \ sed "s/-/~/")-${OS_RELEASE} .PHONY: debpackage debclean -FUZZ_NGFUZZ_DIR ?= "" -FUZZ_TIMEOUT ?= 30 -FUZZ_FUNCTIONS ?= "all" -FUZZ_AUX ?= "" - # Make all binaries all: $(BINS) $(BINS): $(DIRS) dep @@ -83,35 +78,6 @@ cover: @go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic @go tool cover -html=coverage.txt -o coverage.html -# Run fuzzing -CLANG := $(shell which clang-17 2>/dev/null) -.PHONY: check-clang all -check-clang: -ifeq ($(CLANG),) - @echo "clang-17 is not installed. Please install it before proceeding - https://apt.llvm.org/llvm.sh " - @exit 1 -endif - -.PHONY: check-ngfuzz all -check-ngfuzz: - @if [ -z "$(FUZZ_NGFUZZ_DIR)" ]; then \ - echo "Please set a variable FUZZ_NGFUZZ_DIR to specify path to the ngfuzz"; \ - exit 1; \ - fi - -.PHONY: install-fuzzing-deps -install-fuzzing-deps: check-clang check-ngfuzz - -.PHONY: fuzz -fuzz: install-fuzzing-deps - @START_PATH=$$(pwd); \ - ROOT_PATH=$$(realpath --relative-to=$(FUZZ_NGFUZZ_DIR) $$START_PATH) ; \ - cd $(FUZZ_NGFUZZ_DIR) && \ - ./ngfuzz -clean && \ - ./ngfuzz -fuzz $(FUZZ_FUNCTIONS) -rootdir $$ROOT_PATH -timeout $(FUZZ_TIMEOUT) $(FUZZ_AUX) && \ - ./ngfuzz -report - - # Reformat code fmt: @echo "⇒ Processing gofmt check" @@ -183,7 +149,7 @@ version: # Clean up clean: rm -rf vendor - rm -rf $(BINDIR) + rm -rf $(BINDIR) # Package for Debian debpackage: diff --git a/README.md b/README.md index adf793c..6e19d31 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-
+
FrostFS is a decentralized distributed object storage integrated with the NEO Blockchain.
@@ -217,8 +217,41 @@ Also, in case of downloading, you need to have a file inside a container.
### NNS
In all download/upload routes you can use container name instead of its id (`$CID`).
-Read more about it in [docs/nns.md](./docs/nns.md).
+Steps to start using name resolving:
+
+1. Enable NNS resolving in config (`rpc_endpoint` must be a valid neo rpc node, see [configs](./config) for other examples):
+
+```yaml
+rpc_endpoint: http://morph-chain.frostfs.devenv:30333
+resolve_order:
+ - nns
+```
+
+2. Make sure your container is registered in NNS contract. If you use [frostfs-dev-env](https://git.frostfs.info/TrueCloudLab/frostfs-dev-env)
+you can check if your container (e.g. with `container-name` name) is registered in NNS:
+
+```shell
+$ curl -s --data '{"id":1,"jsonrpc":"2.0","method":"getcontractstate","params":[1]}' \
+ http://morph-chain.frostfs.devenv:30333 | jq -r '.result.hash'
+
+0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667
+
+$ docker exec -it morph_chain neo-go \
+ contract testinvokefunction \
+ -r http://morph-chain.frostfs.devenv:30333 0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667 \
+ resolve string:container-name.container int:16 \
+ | jq -r '.stack[0].value | if type=="array" then .[0].value else . end' \
+ | base64 -d && echo
+
+7f3vvkw4iTiS5ZZbu5BQXEmJtETWbi3uUjLNaSs29xrL
+```
+
+3. Use container name instead of its `$CID`. For example:
+
+```shell
+$ curl http://localhost:8082/get_by_attribute/container-name/FileName/object-name
+```
#### Create a container
@@ -429,7 +462,126 @@ object ID, like this:
#### Authentication
-Read more about request authentication in [docs/authentication.md](./docs/authemtnication.md)
+You can always upload files to public containers (open for anyone to put
+objects into), but for restricted containers you need to explicitly allow PUT
+operations for a request signed with your HTTP Gateway keys.
+
+If your don't want to manage gateway's secret keys and adjust eACL rules when
+gateway configuration changes (new gate, key rotation, etc) or you plan to use
+public services, there is an option to let your application backend (or you) to
+issue Bearer Tokens ans pass them from the client via gate down to FrostFS level
+to grant access.
+
+FrostFS Bearer Token basically is a container owner-signed ACL data (refer to FrostFS
+documentation for more details). There are two options to pass them to gateway:
+ * "Authorization" header with "Bearer" type and base64-encoded token in
+ credentials field
+ * "Bearer" cookie with base64-encoded token contents
+
+For example, you have a mobile application frontend with a backend part storing
+data in FrostFS. When a user authorizes in the mobile app, the backend issues a FrostFS
+Bearer token and provides it to the frontend. Then, the mobile app may generate
+some data and upload it via any available FrostFS HTTP Gateway by adding
+the corresponding header to the upload request. Accessing the ACL protected data
+works the same way.
+
+##### Example
+In order to generate a bearer token, you need to have wallet (which will be used to sign the token) and
+the address of the sender who will do the request to FrostFS (in our case, it's a gateway wallet address).
+
+Suppose we have:
+* **NhVtreTTCoqsMQV5Wp55fqnriiUCpEaKm3** (token owner (gateway address))
+
+Firstly, we need to encode the container id and the sender address to base64 (now it's base58).
+So use **base58** and **base64** utils.
+
+1. Encoding token owner id:
+```
+$ echo 'NhVtreTTCoqsMQV5Wp55fqnriiUCpEaKm3' | base58 --decode | base64
+# output: NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg==
+```
+
+2. Form a Bearer token (10000 is lifetime expiration in epoch) and save it to **bearer.json**:
+```
+{
+ "body": {
+ "allowImpersonate": true,
+ "ownerID": {
+ "value": "NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg=="
+ },
+ "lifetime": {
+ "exp": "10000",
+ "nbf": "0",
+ "iat": "0"
+ }
+ },
+ "signature": null
+}
+```
+
+3. Sign it with the wallet:
+```
+$ frostfs-cli util sign bearer-token --from bearer.json --to signed.json -w ./wallet.json
+```
+
+4. Encode to base64 to use in header:
+```
+$ base64 -w 0 signed.json
+# output: Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==
+```
+
+After that, the Bearer token can be used:
+
+```
+$ curl -F 'file=@cat.jpeg;filename=cat.jpeg' -H "Authorization: Bearer Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==" \
+ http://localhost:8082/upload/BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K
+# output:
+# {
+# "object_id": "DhfES9nVrFksxGDD2jQLunGADfrXExxNwqXbDafyBn9X",
+# "container_id": "BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K"
+# }
+```
+
+##### Note
+For the token to work correctly, you need to create a container with a basic ACL that:
+1. Allow PUT operation to others
+2. Doesn't set "final" bit
+
+For example:
+```
+$ frostfs-cli -w ./wallet.json --basic-acl 0x0FFFCFFF -r 192.168.130.72:8080 container create --policy "REP 3" --await
+```
+
+To deny access to a container without a token, set the eACL rules:
+```
+$ frostfs-cli -w ./wallet.json -r 192.168.130.72:8080 container set-eacl --table eacl.json --await --cid BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K
+```
+
+File **eacl.json**:
+```
+{
+ "version": {
+ "major": 0,
+ "minor": 0
+ },
+ "containerID": {
+ "value": "mRnZWzewzxjzIPa7Fqlfqdl3TM1KpJ0YnsXsEhafJJg="
+ },
+ "records": [
+ {
+ "operation": "PUT",
+ "action": "DENY",
+ "filters": [],
+ "targets": [
+ {
+ "role": "OTHERS",
+ "keys": []
+ }
+ ]
+ }
+ ]
+}
+```
### Metrics and Pprof
@@ -440,26 +592,3 @@ See [configuration](./docs/gate-configuration.md).
## Credits
Please see [CREDITS](CREDITS.md) for details.
-
-## Fuzzing
-
-To run fuzzing tests use the following command:
-
-```shell
-$ make fuzz
-```
-
-This command will install dependencies for the fuzzing process and run existing fuzzing tests.
-
-You can also use the following arguments:
-
-```
-FUZZ_TIMEOUT - time to run each fuzzing test (default 30)
-FUZZ_FUNCTIONS - fuzzing tests that will be started (default "all")
-FUZZ_AUX - additional parameters for the fuzzer (for example, "-debug")
-FUZZ_NGFUZZ_DIR - path to ngfuzz tool
-````
-
-## Credits
-
-Please see [CREDITS](CREDITS.md) for details.
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 46fe535..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Security Policy
-
-
-## How To Report a Vulnerability
-
-If you think you have found a vulnerability in this repository, please report it to us through coordinated disclosure.
-
-**Please do not report security vulnerabilities through public issues, discussions, or change requests.**
-
-Instead, you can report it using one of the following ways:
-
-* Contact the [TrueCloudLab Security Team](mailto:security@frostfs.info) via email
-
-Please include as much of the information listed below as you can to help us better understand and resolve the issue:
-
-* The type of issue (e.g., buffer overflow, or cross-site scripting)
-* Affected version(s)
-* Impact of the issue, including how an attacker might exploit the issue
-* Step-by-step instructions to reproduce the issue
-* The location of the affected source code (tag/branch/commit or direct URL)
-* Full paths of source file(s) related to the manifestation of the issue
-* Any special configuration required to reproduce the issue
-* Any log files that are related to this issue (if possible)
-* Proof-of-concept or exploit code (if possible)
-
-This information will help us triage your report more quickly.
diff --git a/VERSION b/VERSION
index 420000f..244df55 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.32.0
+v0.28.1
diff --git a/cmd/http-gw/app.go b/cmd/http-gw/app.go
index 9d90ccd..2a20d86 100644
--- a/cmd/http-gw/app.go
+++ b/cmd/http-gw/app.go
@@ -1,9 +1,7 @@
package main
import (
- "bytes"
"context"
- "crypto/x509"
"errors"
"fmt"
"net/http"
@@ -16,20 +14,19 @@ import (
"syscall"
"time"
+ v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/cache"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/frostfs/services"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler/middleware"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
- internalnet "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/net"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/service/frostfs"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/templates"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/metrics"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/resolver"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/response"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
"git.frostfs.info/TrueCloudLab/frostfs-observability/tracing"
- v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
@@ -39,48 +36,43 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
- "github.com/panjf2000/ants/v2"
"github.com/spf13/viper"
"github.com/valyala/fasthttp"
- "go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"golang.org/x/exp/slices"
)
type (
app struct {
- ctx context.Context
- log *zap.Logger
- logLevel zap.AtomicLevel
- pool *pool.Pool
- treePool *treepool.Pool
- key *keys.PrivateKey
- owner *user.ID
- cfg *viper.Viper
- webServer *fasthttp.Server
- webDone chan struct{}
- resolver *resolver.ContainerResolver
- metrics *gateMetrics
- services []*metrics.Service
- settings *appSettings
- loggerSettings *loggerSettings
+ ctx context.Context
+ log *zap.Logger
+ logLevel zap.AtomicLevel
+ pool *pool.Pool
+ treePool *treepool.Pool
+ key *keys.PrivateKey
+ owner *user.ID
+ cfg *viper.Viper
+ webServer *fasthttp.Server
+ webDone chan struct{}
+ resolver *resolver.ContainerResolver
+ metrics *gateMetrics
+ services []*metrics.Service
+ settings *appSettings
servers []Server
unbindServers []ServerInfo
mu sync.RWMutex
}
- loggerSettings struct {
- mu sync.RWMutex
- appMetrics *metrics.GateMetrics
- }
-
// App is an interface for the main gateway function.
App interface {
Wait()
Serve()
}
+ // Option is an application option.
+ Option func(a *app)
+
gateMetrics struct {
logger *zap.Logger
provider *metrics.GateMetrics
@@ -91,51 +83,49 @@ type (
// appSettings stores reloading parameters, so it has to provide getters and setters which use RWMutex.
appSettings struct {
reconnectInterval time.Duration
- dialerSource *internalnet.DialerSource
- workerPoolSize int
- mu sync.RWMutex
- defaultTimestamp bool
- zipCompression bool
- clientCut bool
- returnIndexPage bool
- indexPageTemplate string
- bufferMaxSizeForPut uint64
- namespaceHeader string
- defaultNamespaces []string
- corsAllowOrigin string
- corsAllowMethods []string
- corsAllowHeaders []string
- corsExposeHeaders []string
- corsAllowCredentials bool
- corsMaxAge int
- enableFilepathFallback bool
- }
-
- CORS struct {
- AllowOrigin string
- AllowMethods []string
- AllowHeaders []string
- ExposeHeaders []string
- AllowCredentials bool
- MaxAge int
+ mu sync.RWMutex
+ defaultTimestamp bool
+ zipCompression bool
+ clientCut bool
+ bufferMaxSizeForPut uint64
+ namespaceHeader string
+ defaultNamespaces []string
}
)
-func newApp(ctx context.Context, v *viper.Viper) App {
- logSettings := &loggerSettings{}
- log := pickLogger(v, logSettings)
-
- a := &app{
- ctx: ctx,
- log: log.logger,
- cfg: v,
- loggerSettings: logSettings,
- webServer: new(fasthttp.Server),
- webDone: make(chan struct{}),
+// WithLogger returns Option to set a specific logger.
+func WithLogger(l *zap.Logger, lvl zap.AtomicLevel) Option {
+ return func(a *app) {
+ if l == nil {
+ return
+ }
+ a.log = l
+ a.logLevel = lvl
}
+}
- a.initAppSettings()
+// WithConfig returns Option to use specific Viper configuration.
+func WithConfig(c *viper.Viper) Option {
+ return func(a *app) {
+ if c == nil {
+ return
+ }
+ a.cfg = c
+ }
+}
+
+func newApp(ctx context.Context, opt ...Option) App {
+ a := &app{
+ ctx: ctx,
+ log: zap.L(),
+ cfg: viper.GetViper(),
+ webServer: new(fasthttp.Server),
+ webDone: make(chan struct{}),
+ }
+ for i := range opt {
+ opt[i](a)
+ }
// -- setup FastHTTP server --
a.webServer.Name = "frost-http-gw"
@@ -150,7 +140,7 @@ func newApp(ctx context.Context, v *viper.Viper) App {
a.webServer.DisablePreParseMultipartForm = true
a.webServer.StreamRequestBody = a.cfg.GetBool(cfgWebStreamRequestBody)
// -- -- -- -- -- -- -- -- -- -- -- -- -- --
- a.pool, a.treePool, a.key = getPools(ctx, a.log, a.cfg, a.settings.dialerSource)
+ a.pool, a.treePool, a.key = getPools(ctx, a.log, a.cfg)
var owner user.ID
user.IDFromKey(&owner, a.key.PrivateKey.PublicKey)
@@ -158,6 +148,7 @@ func newApp(ctx context.Context, v *viper.Viper) App {
a.setRuntimeParameters()
+ a.initAppSettings()
a.initResolver()
a.initMetrics()
a.initTracing(ctx)
@@ -165,117 +156,28 @@ func newApp(ctx context.Context, v *viper.Viper) App {
return a
}
-func (a *app) initAppSettings() {
- a.settings = &appSettings{
- reconnectInterval: fetchReconnectInterval(a.cfg),
- dialerSource: getDialerSource(a.log, a.cfg),
- workerPoolSize: a.cfg.GetInt(cfgWorkerPoolSize),
- }
- a.settings.update(a.cfg, a.log)
-}
-
-func (s *appSettings) update(v *viper.Viper, l *zap.Logger) {
- defaultTimestamp := v.GetBool(cfgUploaderHeaderEnableDefaultTimestamp)
- zipCompression := v.GetBool(cfgZipCompression)
- returnIndexPage := v.GetBool(cfgIndexPageEnabled)
- clientCut := v.GetBool(cfgClientCut)
- bufferMaxSizeForPut := v.GetUint64(cfgBufferMaxSizeForPut)
- namespaceHeader := v.GetString(cfgResolveNamespaceHeader)
- defaultNamespaces := fetchDefaultNamespaces(v)
- indexPage, indexEnabled := fetchIndexPageTemplate(v, l)
- corsAllowOrigin := v.GetString(cfgCORSAllowOrigin)
- corsAllowMethods := v.GetStringSlice(cfgCORSAllowMethods)
- corsAllowHeaders := v.GetStringSlice(cfgCORSAllowHeaders)
- corsExposeHeaders := v.GetStringSlice(cfgCORSExposeHeaders)
- corsAllowCredentials := v.GetBool(cfgCORSAllowCredentials)
- corsMaxAge := fetchCORSMaxAge(v)
- enableFilepathFallback := v.GetBool(cfgFeaturesEnableFilepathFallback)
-
- s.mu.Lock()
- defer s.mu.Unlock()
-
- s.defaultTimestamp = defaultTimestamp
- s.zipCompression = zipCompression
- s.returnIndexPage = returnIndexPage
- s.clientCut = clientCut
- s.bufferMaxSizeForPut = bufferMaxSizeForPut
- s.namespaceHeader = namespaceHeader
- s.defaultNamespaces = defaultNamespaces
- s.returnIndexPage = indexEnabled
- s.indexPageTemplate = indexPage
- s.corsAllowOrigin = corsAllowOrigin
- s.corsAllowMethods = corsAllowMethods
- s.corsAllowHeaders = corsAllowHeaders
- s.corsExposeHeaders = corsExposeHeaders
- s.corsAllowCredentials = corsAllowCredentials
- s.corsMaxAge = corsMaxAge
- s.enableFilepathFallback = enableFilepathFallback
-}
-
-func (s *loggerSettings) DroppedLogsInc() {
- s.mu.RLock()
- defer s.mu.RUnlock()
-
- if s.appMetrics != nil {
- s.appMetrics.DroppedLogsInc()
- }
-}
-
-func (s *loggerSettings) setMetrics(appMetrics *metrics.GateMetrics) {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- s.appMetrics = appMetrics
-}
-
func (s *appSettings) DefaultTimestamp() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.defaultTimestamp
}
+func (s *appSettings) setDefaultTimestamp(val bool) {
+ s.mu.Lock()
+ s.defaultTimestamp = val
+ s.mu.Unlock()
+}
+
func (s *appSettings) ZipCompression() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.zipCompression
}
-func (s *appSettings) IndexPageEnabled() bool {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.returnIndexPage
-}
-
-func (s *appSettings) IndexPageTemplate() string {
- s.mu.RLock()
- defer s.mu.RUnlock()
- if s.indexPageTemplate == "" {
- return templates.DefaultIndexTemplate
- }
- return s.indexPageTemplate
-}
-
-func (s *appSettings) CORS() CORS {
- s.mu.RLock()
- defer s.mu.RUnlock()
-
- allowMethods := make([]string, len(s.corsAllowMethods))
- copy(allowMethods, s.corsAllowMethods)
-
- allowHeaders := make([]string, len(s.corsAllowHeaders))
- copy(allowHeaders, s.corsAllowHeaders)
-
- exposeHeaders := make([]string, len(s.corsExposeHeaders))
- copy(exposeHeaders, s.corsExposeHeaders)
-
- return CORS{
- AllowOrigin: s.corsAllowOrigin,
- AllowMethods: allowMethods,
- AllowHeaders: allowHeaders,
- ExposeHeaders: exposeHeaders,
- AllowCredentials: s.corsAllowCredentials,
- MaxAge: s.corsMaxAge,
- }
+func (s *appSettings) setZipCompression(val bool) {
+ s.mu.Lock()
+ s.zipCompression = val
+ s.mu.Unlock()
}
func (s *appSettings) ClientCut() bool {
@@ -284,33 +186,29 @@ func (s *appSettings) ClientCut() bool {
return s.clientCut
}
+func (s *appSettings) setClientCut(val bool) {
+ s.mu.Lock()
+ s.clientCut = val
+ s.mu.Unlock()
+}
+
func (s *appSettings) BufferMaxSizeForPut() uint64 {
s.mu.RLock()
defer s.mu.RUnlock()
return s.bufferMaxSizeForPut
}
-func (s *appSettings) NamespaceHeader() string {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.namespaceHeader
+func (s *appSettings) setBufferMaxSizeForPut(val uint64) {
+ s.mu.Lock()
+ s.bufferMaxSizeForPut = val
+ s.mu.Unlock()
}
-func (s *appSettings) FormContainerZone(ns string) (zone string, isDefault bool) {
- s.mu.RLock()
- namespaces := s.defaultNamespaces
- s.mu.RUnlock()
- if slices.Contains(namespaces, ns) {
- return v2container.SysAttributeZoneDefault, true
+func (a *app) initAppSettings() {
+ a.settings = &appSettings{
+ reconnectInterval: fetchReconnectInterval(a.cfg),
}
-
- return ns + ".ns", false
-}
-
-func (s *appSettings) EnableFilepathFallback() bool {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.enableFilepathFallback
+ a.updateSettings()
}
func (a *app) initResolver() {
@@ -323,7 +221,7 @@ func (a *app) initResolver() {
func (a *app) getResolverConfig() ([]string, *resolver.Config) {
resolveCfg := &resolver.Config{
- FrostFS: frostfs.NewResolverFrostFS(a.pool),
+ FrostFS: resolver.NewFrostFSResolver(a.pool),
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
Settings: a.settings,
}
@@ -345,7 +243,6 @@ func (a *app) initMetrics() {
gateMetricsProvider := metrics.NewGateMetrics(a.pool)
a.metrics = newGateMetrics(a.log, gateMetricsProvider, a.cfg.GetBool(cfgPrometheusEnabled))
a.metrics.SetHealth(metrics.HealthStatusStarting)
- a.loggerSettings.setMetrics(a.metrics.provider)
}
func newGateMetrics(logger *zap.Logger, provider *metrics.GateMetrics, enabled bool) *gateMetrics {
@@ -501,16 +398,10 @@ func (a *app) setHealthStatus() {
}
func (a *app) Serve() {
- workerPool := a.initWorkerPool()
- defer func() {
- workerPool.Release()
- close(a.webDone)
- }()
-
- handle := handler.New(a.AppParams(), a.settings, tree.NewTree(frostfs.NewPoolWrapper(a.treePool)), workerPool)
+ handler := handler.New(a.AppParams(), a.settings, tree.NewTree(services.NewPoolWrapper(a.treePool)))
// Configure router.
- a.configureRouter(handle)
+ a.configureRouter(handler)
a.startServices()
a.initServers(a.ctx)
@@ -549,14 +440,8 @@ LOOP:
a.metrics.Shutdown()
a.stopServices()
a.shutdownTracing()
-}
-func (a *app) initWorkerPool() *ants.Pool {
- workerPool, err := ants.NewPool(a.settings.workerPoolSize)
- if err != nil {
- a.log.Fatal(logs.FailedToCreateWorkerPool, zap.Error(err))
- }
- return workerPool
+ close(a.webDone)
}
func (a *app) shutdownTracing() {
@@ -586,10 +471,6 @@ func (a *app) configReload(ctx context.Context) {
a.logLevel.SetLevel(lvl)
}
- if err := a.settings.dialerSource.Update(fetchMultinetConfig(a.cfg, a.log)); err != nil {
- a.log.Warn(logs.MultinetConfigWontBeUpdated, zap.Error(err))
- }
-
if err := a.resolver.UpdateResolvers(a.getResolverConfig()); err != nil {
a.log.Warn(logs.FailedToUpdateResolvers, zap.Error(err))
}
@@ -603,7 +484,7 @@ func (a *app) configReload(ctx context.Context) {
a.stopServices()
a.startServices()
- a.settings.update(a.cfg, a.log)
+ a.updateSettings()
a.metrics.SetEnabled(a.cfg.GetBool(cfgPrometheusEnabled))
a.initTracing(ctx)
@@ -612,6 +493,15 @@ func (a *app) configReload(ctx context.Context) {
a.log.Info(logs.SIGHUPConfigReloadCompleted)
}
+func (a *app) updateSettings() {
+ a.settings.setDefaultTimestamp(a.cfg.GetBool(cfgUploaderHeaderEnableDefaultTimestamp))
+ a.settings.setZipCompression(a.cfg.GetBool(cfgZipCompression))
+ a.settings.setClientCut(a.cfg.GetBool(cfgClientCut))
+ a.settings.setBufferMaxSizeForPut(a.cfg.GetUint64(cfgBufferMaxSizeForPut))
+ a.settings.setNamespaceHeader(a.cfg.GetString(cfgResolveNamespaceHeader))
+ a.settings.setDefaultNamespaces(a.cfg.GetStringSlice(cfgResolveDefaultNamespaces))
+}
+
func (a *app) startServices() {
pprofConfig := metrics.Config{Enabled: a.cfg.GetBool(cfgPprofEnabled), Address: a.cfg.GetString(cfgPprofAddress)}
pprofService := metrics.NewPprofService(a.log, pprofConfig)
@@ -633,171 +523,47 @@ func (a *app) stopServices() {
}
}
-func (a *app) configureRouter(h *handler.Handler) {
+func (a *app) configureRouter(handler *handler.Handler) {
r := router.New()
r.RedirectTrailingSlash = true
r.NotFound = func(r *fasthttp.RequestCtx) {
- handler.ResponseError(r, "Not found", fasthttp.StatusNotFound)
+ response.Error(r, "Not found", fasthttp.StatusNotFound)
}
r.MethodNotAllowed = func(r *fasthttp.RequestCtx) {
- handler.ResponseError(r, "Method Not Allowed", fasthttp.StatusMethodNotAllowed)
+ response.Error(r, "Method Not Allowed", fasthttp.StatusMethodNotAllowed)
}
- r.POST("/upload/{cid}", a.addMiddlewares(h.Upload))
- r.OPTIONS("/upload/{cid}", a.addPreflight())
+ r.POST("/upload/{cid}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.Upload)))))
a.log.Info(logs.AddedPathUploadCid)
- r.GET("/get/{cid}/{oid:*}", a.addMiddlewares(h.DownloadByAddressOrBucketName))
- r.HEAD("/get/{cid}/{oid:*}", a.addMiddlewares(h.HeadByAddressOrBucketName))
- r.OPTIONS("/get/{cid}/{oid:*}", a.addPreflight())
+ r.GET("/get/{cid}/{oid:*}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadByAddressOrBucketName)))))
+ r.HEAD("/get/{cid}/{oid:*}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.HeadByAddressOrBucketName)))))
a.log.Info(logs.AddedPathGetCidOid)
- r.GET("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.addMiddlewares(h.DownloadByAttribute))
- r.HEAD("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.addMiddlewares(h.HeadByAttribute))
- r.OPTIONS("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.addPreflight())
+ r.GET("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadByAttribute)))))
+ r.HEAD("/get_by_attribute/{cid}/{attr_key}/{attr_val:*}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.HeadByAttribute)))))
a.log.Info(logs.AddedPathGetByAttributeCidAttrKeyAttrVal)
- r.GET("/zip/{cid}/{prefix:*}", a.addMiddlewares(h.DownloadZipped))
- r.OPTIONS("/zip/{cid}/{prefix:*}", a.addPreflight())
+ r.GET("/zip/{cid}/{prefix:*}", a.logger(a.tokenizer(a.tracer(a.reqNamespace(handler.DownloadZipped)))))
a.log.Info(logs.AddedPathZipCidPrefix)
a.webServer.Handler = r.Handler
}
-func (a *app) addMiddlewares(h fasthttp.RequestHandler) fasthttp.RequestHandler {
- list := []func(fasthttp.RequestHandler) fasthttp.RequestHandler{
- a.tracer,
- a.logger,
- a.canonicalizer,
- a.tokenizer,
- a.reqNamespace,
- a.cors,
- }
-
- for i := len(list) - 1; i >= 0; i-- {
- h = list[i](h)
- }
-
- return h
-}
-
-func (a *app) addPreflight() fasthttp.RequestHandler {
- list := []func(fasthttp.RequestHandler) fasthttp.RequestHandler{
- a.tracer,
- a.logger,
- a.reqNamespace,
- }
-
- h := a.preflightHandler
- for i := len(list) - 1; i >= 0; i-- {
- h = list[i](h)
- }
-
- return h
-}
-
-func (a *app) preflightHandler(c *fasthttp.RequestCtx) {
- cors := a.settings.CORS()
- setCORSHeaders(c, cors)
-}
-
-func (a *app) cors(h fasthttp.RequestHandler) fasthttp.RequestHandler {
- return func(c *fasthttp.RequestCtx) {
- h(c)
- code := c.Response.StatusCode()
- if code >= fasthttp.StatusOK && code < fasthttp.StatusMultipleChoices {
- cors := a.settings.CORS()
- setCORSHeaders(c, cors)
- }
- }
-}
-
-func setCORSHeaders(c *fasthttp.RequestCtx, cors CORS) {
- c.Response.Header.Set(fasthttp.HeaderAccessControlMaxAge, strconv.Itoa(cors.MaxAge))
-
- if len(cors.AllowOrigin) != 0 {
- c.Response.Header.Set(fasthttp.HeaderAccessControlAllowOrigin, cors.AllowOrigin)
- }
-
- if len(cors.AllowMethods) != 0 {
- c.Response.Header.Set(fasthttp.HeaderAccessControlAllowMethods, strings.Join(cors.AllowMethods, ","))
- }
-
- if len(cors.AllowHeaders) != 0 {
- c.Response.Header.Set(fasthttp.HeaderAccessControlAllowHeaders, strings.Join(cors.AllowHeaders, ","))
- }
-
- if len(cors.ExposeHeaders) != 0 {
- c.Response.Header.Set(fasthttp.HeaderAccessControlExposeHeaders, strings.Join(cors.ExposeHeaders, ","))
- }
-
- if cors.AllowCredentials {
- c.Response.Header.Set(fasthttp.HeaderAccessControlAllowCredentials, "true")
- }
-}
-
func (a *app) logger(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(req *fasthttp.RequestCtx) {
- requiredFields := []zap.Field{zap.Uint64("id", req.ID())}
- reqCtx := utils.GetContextFromRequest(req)
- if traceID := trace.SpanFromContext(reqCtx).SpanContext().TraceID(); traceID.IsValid() {
- requiredFields = append(requiredFields, zap.String("trace_id", traceID.String()))
- }
- log := a.log.With(requiredFields...)
-
- reqCtx = utils.SetReqLog(reqCtx, log)
- utils.SetContextToRequest(reqCtx, req)
-
- fields := []zap.Field{
- zap.String("remote", req.RemoteAddr().String()),
+ a.log.Info(logs.Request, zap.String("remote", req.RemoteAddr().String()),
zap.ByteString("method", req.Method()),
zap.ByteString("path", req.Path()),
zap.ByteString("query", req.QueryArgs().QueryString()),
- }
-
- log.Info(logs.Request, fields...)
- h(req)
- }
-}
-
-func (a *app) canonicalizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
- return func(req *fasthttp.RequestCtx) {
- // regardless of DisableHeaderNamesNormalizing setting, some headers
- // MUST be normalized in order to process execution. They are normalized
- // here.
-
- toAddKeys := make([][]byte, 0, 10)
- toAddValues := make([][]byte, 0, 10)
- prefix := []byte(utils.UserAttributeHeaderPrefix)
-
- req.Request.Header.VisitAll(func(k, v []byte) {
- if bytes.HasPrefix(k, prefix) {
- return
- }
- toAddKeys = append(toAddKeys, k)
- toAddValues = append(toAddValues, v)
- })
-
- // this is safe to do after all headers were read into header structure
- req.Request.Header.EnableNormalizing()
-
- for i := range toAddKeys {
- req.Request.Header.SetBytesKV(toAddKeys[i], toAddValues[i])
- }
-
- // return normalization setting back
- req.Request.Header.DisableNormalizing()
-
+ zap.Uint64("id", req.ID()))
h(req)
}
}
func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(req *fasthttp.RequestCtx) {
- reqCtx := utils.GetContextFromRequest(req)
- appCtx, err := tokens.StoreBearerTokenAppCtx(reqCtx, req)
+ appCtx, err := tokens.StoreBearerTokenAppCtx(a.ctx, req)
if err != nil {
- log := utils.GetReqLogOrDefault(reqCtx, a.log)
-
- log.Error(logs.CouldNotFetchAndStoreBearerToken, zap.Error(err))
- handler.ResponseError(req, "could not fetch and store bearer token: "+err.Error(), fasthttp.StatusBadRequest)
+ a.log.Error(logs.CouldNotFetchAndStoreBearerToken, zap.Uint64("id", req.ID()), zap.Error(err))
+ response.Error(req, "could not fetch and store bearer token: "+err.Error(), fasthttp.StatusBadRequest)
return
}
utils.SetContextToRequest(appCtx, req)
@@ -807,7 +573,9 @@ func (a *app) tokenizer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
func (a *app) tracer(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(req *fasthttp.RequestCtx) {
- appCtx, span := utils.StartHTTPServerSpan(a.ctx, req, "REQUEST")
+ appCtx := utils.GetContextFromRequest(req)
+
+ appCtx, span := utils.StartHTTPServerSpan(appCtx, req, "REQUEST")
defer func() {
utils.SetHTTPTraceInfo(appCtx, span, req)
span.End()
@@ -832,10 +600,10 @@ func (a *app) reqNamespace(h fasthttp.RequestHandler) fasthttp.RequestHandler {
}
}
-func (a *app) AppParams() *handler.AppParams {
- return &handler.AppParams{
+func (a *app) AppParams() *utils.AppParams {
+ return &utils.AppParams{
Logger: a.log,
- FrostFS: frostfs.NewFrostFS(a.pool),
+ Pool: a.pool,
Owner: a.owner,
Resolver: a.resolver,
Cache: cache.NewBucketCache(getCacheOptions(a.cfg, a.log)),
@@ -935,29 +703,6 @@ func (a *app) initTracing(ctx context.Context) {
InstanceID: instanceID,
Version: Version,
}
-
- if trustedCa := a.cfg.GetString(cfgTracingTrustedCa); trustedCa != "" {
- caBytes, err := os.ReadFile(trustedCa)
- if err != nil {
- a.log.Warn(logs.FailedToInitializeTracing, zap.Error(err))
- return
- }
- certPool := x509.NewCertPool()
- ok := certPool.AppendCertsFromPEM(caBytes)
- if !ok {
- a.log.Warn(logs.FailedToInitializeTracing, zap.String("error", "can't fill cert pool by ca cert"))
- return
- }
- cfg.ServerCaCertPool = certPool
- }
-
- attributes, err := fetchTracingAttributes(a.cfg)
- if err != nil {
- a.log.Warn(logs.FailedToInitializeTracing, zap.Error(err))
- return
- }
- cfg.Attributes = attributes
-
updated, err := tracing.Setup(ctx, cfg)
if err != nil {
a.log.Warn(logs.FailedToInitializeTracing, zap.Error(err))
@@ -983,6 +728,39 @@ func (a *app) setRuntimeParameters() {
}
}
+func (s *appSettings) NamespaceHeader() string {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ return s.namespaceHeader
+}
+
+func (s *appSettings) setNamespaceHeader(nsHeader string) {
+ s.mu.Lock()
+ s.namespaceHeader = nsHeader
+ s.mu.Unlock()
+}
+
+func (s *appSettings) FormContainerZone(ns string) (zone string, isDefault bool) {
+ s.mu.RLock()
+ namespaces := s.defaultNamespaces
+ s.mu.RUnlock()
+ if slices.Contains(namespaces, ns) {
+ return v2container.SysAttributeZoneDefault, true
+ }
+
+ return ns + ".ns", false
+}
+
+func (s *appSettings) setDefaultNamespaces(namespaces []string) {
+ for i := range namespaces { // to be set namespaces in env variable as `HTTP_GW_RESOLVE_BUCKET_DEFAULT_NAMESPACES="" "root"`
+ namespaces[i] = strings.Trim(namespaces[i], "\"")
+ }
+
+ s.mu.Lock()
+ s.defaultNamespaces = namespaces
+ s.mu.Unlock()
+}
+
func (a *app) scheduleReconnect(ctx context.Context, srv *fasthttp.Server) {
go func() {
t := time.NewTicker(a.settings.reconnectInterval)
diff --git a/cmd/http-gw/integration_test.go b/cmd/http-gw/integration_test.go
index 6a4d428..f76c3ce 100644
--- a/cmd/http-gw/integration_test.go
+++ b/cmd/http-gw/integration_test.go
@@ -6,35 +6,30 @@ import (
"archive/zip"
"bytes"
"context"
- "encoding/base64"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
- "os"
"sort"
- "strings"
"testing"
"time"
- containerv2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
+ containerv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
- "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
+ "go.uber.org/zap/zapcore"
)
type putResponse struct {
@@ -52,19 +47,11 @@ func TestIntegration(t *testing.T) {
rootCtx := context.Background()
aioImage := "truecloudlab/frostfs-aio:"
versions := []string{
- "1.2.7",
- "1.3.0",
- "1.5.0",
- "1.6.5",
+ "1.2.7", // frostfs-storage v0.36.0 RC
}
key, err := keys.NewPrivateKeyFromHex("1dd37fba80fec4e6a6f13fd708d8dcb3b29def768017052f6c930fa1c5d90bbb")
require.NoError(t, err)
- file, err := os.CreateTemp("", "wallet")
- require.NoError(t, err)
- defer os.Remove(file.Name())
- makeTempWallet(t, key, file.Name())
-
var ownerID user.ID
user.IDFromKey(&ownerID, key.PrivateKey.PublicKey)
@@ -72,26 +59,17 @@ func TestIntegration(t *testing.T) {
ctx, cancel2 := context.WithCancel(rootCtx)
aioContainer := createDockerContainer(ctx, t, aioImage+version)
- if strings.HasPrefix(version, "1.6") {
- registerUser(t, ctx, aioContainer, file.Name())
- }
-
- // See the logs from the command execution.
- server, cancel := runServer(file.Name())
+ server, cancel := runServer()
clientPool := getPool(ctx, t, key)
- CID, err := createContainer(ctx, t, clientPool, ownerID)
+ CID, err := createContainer(ctx, t, clientPool, ownerID, version)
require.NoError(t, err, version)
- token := makeBearerToken(t, key, ownerID, version)
-
- t.Run("simple put "+version, func(t *testing.T) { simplePut(ctx, t, clientPool, CID) })
- t.Run("put with bearer token in header"+version, func(t *testing.T) { putWithBearerTokenInHeader(ctx, t, clientPool, CID, token) })
- t.Run("put with bearer token in cookie"+version, func(t *testing.T) { putWithBearerTokenInCookie(ctx, t, clientPool, CID, token) })
+ t.Run("simple put "+version, func(t *testing.T) { simplePut(ctx, t, clientPool, CID, version) })
t.Run("put with duplicate keys "+version, func(t *testing.T) { putWithDuplicateKeys(t, CID) })
- t.Run("simple get "+version, func(t *testing.T) { simpleGet(ctx, t, clientPool, ownerID, CID) })
- t.Run("get by attribute "+version, func(t *testing.T) { getByAttr(ctx, t, clientPool, ownerID, CID) })
- t.Run("get zip "+version, func(t *testing.T) { getZip(ctx, t, clientPool, ownerID, CID) })
- t.Run("test namespaces "+version, func(t *testing.T) { checkNamespaces(ctx, t, clientPool, ownerID, CID) })
+ t.Run("simple get "+version, func(t *testing.T) { simpleGet(ctx, t, clientPool, ownerID, CID, version) })
+ t.Run("get by attribute "+version, func(t *testing.T) { getByAttr(ctx, t, clientPool, ownerID, CID, version) })
+ t.Run("get zip "+version, func(t *testing.T) { getZip(ctx, t, clientPool, ownerID, CID, version) })
+ t.Run("test namespaces "+version, func(t *testing.T) { checkNamespaces(ctx, t, clientPool, ownerID, CID, version) })
cancel()
server.Wait()
@@ -101,20 +79,18 @@ func TestIntegration(t *testing.T) {
}
}
-func runServer(pathToWallet string) (App, context.CancelFunc) {
+func runServer() (App, context.CancelFunc) {
cancelCtx, cancel := context.WithCancel(context.Background())
v := getDefaultConfig()
- v.Set(cfgWalletPath, pathToWallet)
- v.Set(cfgWalletPassphrase, "")
-
- application := newApp(cancelCtx, v)
+ l, lvl := newStdoutLogger(zapcore.DebugLevel)
+ application := newApp(cancelCtx, WithConfig(v), WithLogger(l, lvl))
go application.Serve()
return application, cancel
}
-func simplePut(ctx context.Context, t *testing.T, p *pool.Pool, CID cid.ID) {
+func simplePut(ctx context.Context, t *testing.T, p *pool.Pool, CID cid.ID, version string) {
url := testHost + "/upload/" + CID.String()
makePutRequestAndCheck(ctx, t, p, CID, url)
@@ -122,38 +98,7 @@ func simplePut(ctx context.Context, t *testing.T, p *pool.Pool, CID cid.ID) {
makePutRequestAndCheck(ctx, t, p, CID, url)
}
-func putWithBearerTokenInHeader(ctx context.Context, t *testing.T, p *pool.Pool, CID cid.ID, token string) {
- url := testHost + "/upload/" + CID.String()
-
- request, content, attributes := makePutRequest(t, url)
- request.Header.Set("Authorization", "Bearer "+token)
- resp, err := http.DefaultClient.Do(request)
- require.NoError(t, err)
-
- checkPutResponse(ctx, t, p, CID, resp, content, attributes)
-}
-
-func putWithBearerTokenInCookie(ctx context.Context, t *testing.T, p *pool.Pool, CID cid.ID, token string) {
- url := testHost + "/upload/" + CID.String()
-
- request, content, attributes := makePutRequest(t, url)
- request.AddCookie(&http.Cookie{Name: "Bearer", Value: token})
- resp, err := http.DefaultClient.Do(request)
- require.NoError(t, err)
-
- checkPutResponse(ctx, t, p, CID, resp, content, attributes)
-}
-
func makePutRequestAndCheck(ctx context.Context, t *testing.T, p *pool.Pool, cnrID cid.ID, url string) {
- request, content, attributes := makePutRequest(t, url)
-
- resp, err := http.DefaultClient.Do(request)
- require.NoError(t, err)
-
- checkPutResponse(ctx, t, p, cnrID, resp, content, attributes)
-}
-
-func makePutRequest(t *testing.T, url string) (*http.Request, string, map[string]string) {
content := "content of file"
keyAttr, valAttr := "User-Attribute", "user value"
attributes := map[string]string{
@@ -175,10 +120,9 @@ func makePutRequest(t *testing.T, url string) (*http.Request, string, map[string
request.Header.Set("Content-Type", w.FormDataContentType())
request.Header.Set("X-Attribute-"+keyAttr, valAttr)
- return request, content, attributes
-}
+ resp, err := http.DefaultClient.Do(request)
+ require.NoError(t, err)
-func checkPutResponse(ctx context.Context, t *testing.T, p *pool.Pool, cnrID cid.ID, resp *http.Response, content string, attributes map[string]string) {
defer func() {
err := resp.Body.Close()
require.NoError(t, err)
@@ -262,7 +206,7 @@ func putWithDuplicateKeys(t *testing.T, CID cid.ID) {
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
}
-func simpleGet(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID) {
+func simpleGet(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID, version string) {
content := "content of file"
attributes := map[string]string{
"some-attr": "some-get-value",
@@ -309,7 +253,7 @@ func checkGetByAttrResponse(t *testing.T, resp *http.Response, content string, a
}
}
-func getByAttr(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID) {
+func getByAttr(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID, version string) {
keyAttr, valAttr := "some-attr", "some-get-by-attr-value"
content := "content of file"
attributes := map[string]string{keyAttr: valAttr}
@@ -331,7 +275,7 @@ func getByAttr(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID
checkGetByAttrResponse(t, resp, content, expectedAttr)
}
-func getZip(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID) {
+func getZip(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID, version string) {
names := []string{"zipfolder/dir/name1.txt", "zipfolder/name2.txt"}
contents := []string{"content of file1", "content of file2"}
attributes1 := map[string]string{object.AttributeFilePath: names[0]}
@@ -396,7 +340,7 @@ func checkZip(t *testing.T, data []byte, length int64, names, contents []string)
}
}
-func checkNamespaces(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID) {
+func checkNamespaces(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID, version string) {
content := "content of file"
attributes := map[string]string{
"some-attr": "some-get-value",
@@ -433,7 +377,7 @@ func checkNamespaces(ctx context.Context, t *testing.T, clientPool *pool.Pool, o
func createDockerContainer(ctx context.Context, t *testing.T, image string) testcontainers.Container {
req := testcontainers.ContainerRequest{
Image: image,
- WaitingFor: wait.NewLogStrategy("aio container started").WithStartupTimeout(2 * time.Minute),
+ WaitingFor: wait.NewLogStrategy("aio container started").WithStartupTimeout(30 * time.Second),
Name: "aio",
Hostname: "aio",
NetworkMode: "host",
@@ -473,7 +417,7 @@ func getPool(ctx context.Context, t *testing.T, key *keys.PrivateKey) *pool.Pool
return clientPool
}
-func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID) (cid.ID, error) {
+func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, version string) (cid.ID, error) {
var policy netmap.PlacementPolicy
err := policy.DecodeString("REP 1")
require.NoError(t, err)
@@ -512,7 +456,7 @@ func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, o
func putObject(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, CID cid.ID, content string, attributes map[string]string) oid.ID {
obj := object.New()
obj.SetContainerID(CID)
- obj.SetOwnerID(ownerID)
+ obj.SetOwnerID(&ownerID)
var attrs []object.Attribute
for key, val := range attributes {
@@ -530,51 +474,5 @@ func putObject(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID
id, err := clientPool.PutObject(ctx, prm)
require.NoError(t, err)
- return id.ObjectID
-}
-
-func registerUser(t *testing.T, ctx context.Context, aioContainer testcontainers.Container, pathToWallet string) {
- err := aioContainer.CopyFileToContainer(ctx, pathToWallet, "/usr/wallet.json", 644)
- require.NoError(t, err)
-
- _, err = aioContainer.Exec(ctx, []string{
- "/usr/bin/frostfs-s3-authmate", "register-user",
- "--wallet", "/usr/wallet.json",
- "--rpc-endpoint", "http://localhost:30333",
- "--contract-wallet", "/config/s3-gw-wallet.json"})
- require.NoError(t, err)
-}
-
-func makeBearerToken(t *testing.T, key *keys.PrivateKey, ownerID user.ID, version string) string {
- tkn := new(bearer.Token)
- tkn.ForUser(ownerID)
- tkn.SetExp(10000)
-
- if version == "1.2.7" {
- tkn.SetEACLTable(*eacl.NewTable())
- } else {
- tkn.SetImpersonate(true)
- }
-
- err := tkn.Sign(key.PrivateKey)
- require.NoError(t, err)
-
- t64 := base64.StdEncoding.EncodeToString(tkn.Marshal())
- require.NotEmpty(t, t64)
-
- return t64
-}
-
-func makeTempWallet(t *testing.T, key *keys.PrivateKey, path string) {
- w, err := wallet.NewWallet(path)
- require.NoError(t, err)
-
- acc := wallet.NewAccountFromPrivateKey(key)
- err = acc.Encrypt("", w.Scrypt)
- require.NoError(t, err)
-
- w.AddAccount(acc)
-
- err = w.Save()
- require.NoError(t, err)
+ return id
}
diff --git a/cmd/http-gw/main.go b/cmd/http-gw/main.go
index fdd148c..ea9fbd7 100644
--- a/cmd/http-gw/main.go
+++ b/cmd/http-gw/main.go
@@ -9,8 +9,9 @@ import (
func main() {
globalContext, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
v := settings()
+ logger, atomicLevel := pickLogger(v)
- application := newApp(globalContext, v)
+ application := newApp(globalContext, WithLogger(logger, atomicLevel), WithConfig(v))
go application.Serve()
application.Wait()
}
diff --git a/cmd/http-gw/settings.go b/cmd/http-gw/settings.go
index 62ef83e..0d97dcb 100644
--- a/cmd/http-gw/settings.go
+++ b/cmd/http-gw/settings.go
@@ -4,7 +4,6 @@ import (
"context"
"encoding/hex"
"fmt"
- "io"
"math"
"os"
"path"
@@ -16,7 +15,6 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/cache"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
- internalnet "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/net"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/resolver"
grpctracing "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
@@ -43,8 +41,6 @@ const (
defaultConnectTimeout = 10 * time.Second
defaultStreamTimeout = 10 * time.Second
- defaultLoggerSamplerInterval = 1 * time.Second
-
defaultShutdownTimeout = 15 * time.Second
defaultPoolErrorThreshold uint32 = 100
@@ -57,10 +53,6 @@ const (
defaultReconnectInterval = time.Minute
- defaultCORSMaxAge = 600 // seconds
-
- defaultMultinetFallbackDelay = 300 * time.Millisecond
-
cfgServer = "server"
cfgTLSEnabled = "tls.enabled"
cfgTLSCertFile = "tls.cert_file"
@@ -68,11 +60,6 @@ const (
cfgReconnectInterval = "reconnect_interval"
- cfgIndexPageEnabled = "index_page.enabled"
- cfgIndexPageTemplatePath = "index_page.template_path"
-
- cfgWorkerPoolSize = "worker_pool_size"
-
// Web.
cfgWebReadBufferSize = "web.read_buffer_size"
cfgWebWriteBufferSize = "web.write_buffer_size"
@@ -88,11 +75,9 @@ const (
cfgPprofAddress = "pprof.address"
// Tracing ...
- cfgTracingEnabled = "tracing.enabled"
- cfgTracingExporter = "tracing.exporter"
- cfgTracingEndpoint = "tracing.endpoint"
- cfgTracingTrustedCa = "tracing.trusted_ca"
- cfgTracingAttributes = "tracing.attributes"
+ cfgTracingEnabled = "tracing.enabled"
+ cfgTracingExporter = "tracing.exporter"
+ cfgTracingEndpoint = "tracing.endpoint"
// Pool config.
cfgConTimeout = "connect_timeout"
@@ -105,11 +90,6 @@ const (
cfgLoggerLevel = "logger.level"
cfgLoggerDestination = "logger.destination"
- cfgLoggerSamplingEnabled = "logger.sampling.enabled"
- cfgLoggerSamplingInitial = "logger.sampling.initial"
- cfgLoggerSamplingThereafter = "logger.sampling.thereafter"
- cfgLoggerSamplingInterval = "logger.sampling.interval"
-
// Wallet.
cfgWalletPassphrase = "wallet.passphrase"
cfgWalletPath = "wallet.path"
@@ -149,24 +129,6 @@ const (
cfgResolveNamespaceHeader = "resolve_bucket.namespace_header"
cfgResolveDefaultNamespaces = "resolve_bucket.default_namespaces"
- // CORS.
- cfgCORSAllowOrigin = "cors.allow_origin"
- cfgCORSAllowMethods = "cors.allow_methods"
- cfgCORSAllowHeaders = "cors.allow_headers"
- cfgCORSExposeHeaders = "cors.expose_headers"
- cfgCORSAllowCredentials = "cors.allow_credentials"
- cfgCORSMaxAge = "cors.max_age"
-
- // Multinet.
- cfgMultinetEnabled = "multinet.enabled"
- cfgMultinetBalancer = "multinet.balancer"
- cfgMultinetRestrict = "multinet.restrict"
- cfgMultinetFallbackDelay = "multinet.fallback_delay"
- cfgMultinetSubnets = "multinet.subnets"
-
- // Feature.
- cfgFeaturesEnableFilepathFallback = "features.enable_filepath_fallback"
-
// Command line args.
cmdHelp = "help"
cmdVersion = "version"
@@ -185,11 +147,6 @@ var ignore = map[string]struct{}{
cmdVersion: {},
}
-type Logger struct {
- logger *zap.Logger
- lvl zap.AtomicLevel
-}
-
func settings() *viper.Viper {
v := viper.New()
v.AutomaticEnv()
@@ -230,10 +187,6 @@ func settings() *viper.Viper {
// logger:
v.SetDefault(cfgLoggerLevel, "debug")
v.SetDefault(cfgLoggerDestination, "stdout")
- v.SetDefault(cfgLoggerSamplingEnabled, false)
- v.SetDefault(cfgLoggerSamplingThereafter, 100)
- v.SetDefault(cfgLoggerSamplingInitial, 100)
- v.SetDefault(cfgLoggerSamplingInterval, defaultLoggerSamplerInterval)
// pool:
v.SetDefault(cfgPoolErrorThreshold, defaultPoolErrorThreshold)
@@ -249,7 +202,6 @@ func settings() *viper.Viper {
v.SetDefault(cfgWebStreamRequestBody, true)
v.SetDefault(cfgWebMaxRequestBodySize, fasthttp.DefaultMaxRequestBodySize)
- v.SetDefault(cfgWorkerPoolSize, 1000)
// upload header
v.SetDefault(cfgUploaderHeaderEnableDefaultTimestamp, false)
@@ -264,9 +216,6 @@ func settings() *viper.Viper {
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
v.SetDefault(cfgResolveDefaultNamespaces, []string{"", "root"})
- // multinet
- v.SetDefault(cfgMultinetFallbackDelay, defaultMultinetFallbackDelay)
-
// Binding flags
if err := v.BindPFlag(cfgPprofEnabled, flags.Lookup(cmdPprof)); err != nil {
panic(err)
@@ -426,11 +375,7 @@ func mergeConfig(v *viper.Viper, fileName string) error {
return v.MergeConfig(cfgFile)
}
-type LoggerAppSettings interface {
- DroppedLogsInc()
-}
-
-func pickLogger(v *viper.Viper, settings LoggerAppSettings) *Logger {
+func pickLogger(v *viper.Viper) (*zap.Logger, zap.AtomicLevel) {
lvl, err := getLogLevel(v)
if err != nil {
panic(err)
@@ -440,9 +385,9 @@ func pickLogger(v *viper.Viper, settings LoggerAppSettings) *Logger {
switch dest {
case destinationStdout:
- return newStdoutLogger(v, lvl, settings)
+ return newStdoutLogger(lvl)
case destinationJournald:
- return newJournaldLogger(v, lvl, settings)
+ return newJournaldLogger(lvl)
default:
panic(fmt.Sprintf("wrong destination for logger: %s", dest))
}
@@ -459,60 +404,39 @@ func pickLogger(v *viper.Viper, settings LoggerAppSettings) *Logger {
// Logger records a stack trace for all messages at or above fatal level.
//
// See also zapcore.Level, zap.NewProductionConfig, zap.AddStacktrace.
-func newStdoutLogger(v *viper.Viper, lvl zapcore.Level, settings LoggerAppSettings) *Logger {
- stdout := zapcore.AddSync(os.Stderr)
- level := zap.NewAtomicLevelAt(lvl)
+func newStdoutLogger(lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
+ c := zap.NewProductionConfig()
+ c.Level = zap.NewAtomicLevelAt(lvl)
+ c.Encoding = "console"
+ c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
- consoleOutCore := zapcore.NewCore(newLogEncoder(), stdout, level)
- consoleOutCore = applyZapCoreMiddlewares(consoleOutCore, v, settings)
-
- return &Logger{
- logger: zap.New(consoleOutCore, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel))),
- lvl: level,
+ l, err := c.Build(
+ zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)),
+ )
+ if err != nil {
+ panic(fmt.Sprintf("build zap logger instance: %v", err))
}
+
+ return l, c.Level
}
-func newJournaldLogger(v *viper.Viper, lvl zapcore.Level, settings LoggerAppSettings) *Logger {
- level := zap.NewAtomicLevelAt(lvl)
+func newJournaldLogger(lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
+ c := zap.NewProductionConfig()
+ c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
+ c.Level = zap.NewAtomicLevelAt(lvl)
- encoder := zapjournald.NewPartialEncoder(newLogEncoder(), zapjournald.SyslogFields)
+ encoder := zapjournald.NewPartialEncoder(zapcore.NewConsoleEncoder(c.EncoderConfig), zapjournald.SyslogFields)
- core := zapjournald.NewCore(level, encoder, &journald.Journal{}, zapjournald.SyslogFields)
+ core := zapjournald.NewCore(c.Level, encoder, &journald.Journal{}, zapjournald.SyslogFields)
coreWithContext := core.With([]zapcore.Field{
zapjournald.SyslogFacility(zapjournald.LogDaemon),
zapjournald.SyslogIdentifier(),
zapjournald.SyslogPid(),
})
- coreWithContext = applyZapCoreMiddlewares(coreWithContext, v, settings)
+ l := zap.New(coreWithContext, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)))
- return &Logger{
- logger: zap.New(coreWithContext, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel))),
- lvl: level,
- }
-}
-
-func newLogEncoder() zapcore.Encoder {
- c := zap.NewProductionEncoderConfig()
- c.EncodeTime = zapcore.ISO8601TimeEncoder
-
- return zapcore.NewConsoleEncoder(c)
-}
-
-func applyZapCoreMiddlewares(core zapcore.Core, v *viper.Viper, settings LoggerAppSettings) zapcore.Core {
- if v.GetBool(cfgLoggerSamplingEnabled) {
- core = zapcore.NewSamplerWithOptions(core,
- v.GetDuration(cfgLoggerSamplingInterval),
- v.GetInt(cfgLoggerSamplingInitial),
- v.GetInt(cfgLoggerSamplingThereafter),
- zapcore.SamplerHook(func(_ zapcore.Entry, dec zapcore.SamplingDecision) {
- if dec&zapcore.LogDropped > 0 {
- settings.DroppedLogsInc()
- }
- }))
- }
-
- return core
+ return l, c.Level
}
func getLogLevel(v *viper.Viper) (zapcore.Level, error) {
@@ -543,46 +467,6 @@ func fetchReconnectInterval(cfg *viper.Viper) time.Duration {
return reconnect
}
-func fetchIndexPageTemplate(v *viper.Viper, l *zap.Logger) (string, bool) {
- if !v.GetBool(cfgIndexPageEnabled) {
- return "", false
- }
-
- reader, err := os.Open(v.GetString(cfgIndexPageTemplatePath))
- if err != nil {
- l.Warn(logs.FailedToReadIndexPageTemplate, zap.Error(err))
- return "", true
- }
-
- tmpl, err := io.ReadAll(reader)
- if err != nil {
- l.Warn(logs.FailedToReadIndexPageTemplate, zap.Error(err))
- return "", true
- }
-
- l.Info(logs.SetCustomIndexPageTemplate)
- return string(tmpl), true
-}
-
-func fetchDefaultNamespaces(v *viper.Viper) []string {
- namespaces := v.GetStringSlice(cfgResolveDefaultNamespaces)
-
- for i := range namespaces { // to be set namespaces in env variable as `HTTP_GW_RESOLVE_BUCKET_DEFAULT_NAMESPACES="" "root"`
- namespaces[i] = strings.Trim(namespaces[i], "\"")
- }
-
- return namespaces
-}
-
-func fetchCORSMaxAge(v *viper.Viper) int {
- maxAge := v.GetInt(cfgCORSMaxAge)
- if maxAge <= 0 {
- maxAge = defaultCORSMaxAge
- }
-
- return maxAge
-}
-
func fetchServers(v *viper.Viper, log *zap.Logger) []ServerInfo {
var servers []ServerInfo
seen := make(map[string]struct{})
@@ -611,7 +495,7 @@ func fetchServers(v *viper.Viper, log *zap.Logger) []ServerInfo {
return servers
}
-func getPools(ctx context.Context, logger *zap.Logger, cfg *viper.Viper, dialSource *internalnet.DialerSource) (*pool.Pool, *treepool.Pool, *keys.PrivateKey) {
+func getPools(ctx context.Context, logger *zap.Logger, cfg *viper.Viper) (*pool.Pool, *treepool.Pool, *keys.PrivateKey) {
key, err := getFrostFSKey(cfg, logger)
if err != nil {
logger.Fatal(logs.CouldNotLoadFrostFSPrivateKey, zap.Error(err))
@@ -667,13 +551,18 @@ func getPools(ctx context.Context, logger *zap.Logger, cfg *viper.Viper, dialSou
prmTree.SetMaxRequestAttempts(cfg.GetInt(cfgTreePoolMaxAttempts))
- interceptors := []grpc.DialOption{
- grpc.WithUnaryInterceptor(grpctracing.NewUnaryClientInteceptor()),
- grpc.WithStreamInterceptor(grpctracing.NewStreamClientInterceptor()),
- grpc.WithContextDialer(dialSource.GrpcContextDialer()),
+ var apiGRPCDialOpts []grpc.DialOption
+ var treeGRPCDialOpts []grpc.DialOption
+ if cfg.GetBool(cfgTracingEnabled) {
+ interceptors := []grpc.DialOption{
+ grpc.WithUnaryInterceptor(grpctracing.NewUnaryClientInteceptor()),
+ grpc.WithStreamInterceptor(grpctracing.NewStreamClientInterceptor()),
+ }
+ treeGRPCDialOpts = append(treeGRPCDialOpts, interceptors...)
+ apiGRPCDialOpts = append(apiGRPCDialOpts, interceptors...)
}
- prm.SetGRPCDialOptions(interceptors...)
- prmTree.SetGRPCDialOptions(interceptors...)
+ prm.SetGRPCDialOptions(apiGRPCDialOpts...)
+ prmTree.SetGRPCDialOptions(treeGRPCDialOpts...)
p, err := pool.NewPool(prm)
if err != nil {
@@ -773,58 +662,3 @@ func fetchCacheSize(v *viper.Viper, l *zap.Logger, cfgEntry string, defaultValue
return defaultValue
}
-
-func getDialerSource(logger *zap.Logger, cfg *viper.Viper) *internalnet.DialerSource {
- source, err := internalnet.NewDialerSource(fetchMultinetConfig(cfg, logger))
- if err != nil {
- logger.Fatal(logs.FailedToLoadMultinetConfig, zap.Error(err))
- }
- return source
-}
-
-func fetchMultinetConfig(v *viper.Viper, l *zap.Logger) (cfg internalnet.Config) {
- cfg.Enabled = v.GetBool(cfgMultinetEnabled)
- cfg.Balancer = v.GetString(cfgMultinetBalancer)
- cfg.Restrict = v.GetBool(cfgMultinetRestrict)
- cfg.FallbackDelay = v.GetDuration(cfgMultinetFallbackDelay)
- cfg.Subnets = make([]internalnet.Subnet, 0, 5)
- cfg.EventHandler = internalnet.NewLogEventHandler(l)
-
- for i := 0; ; i++ {
- key := cfgMultinetSubnets + "." + strconv.Itoa(i) + "."
- subnet := internalnet.Subnet{}
-
- subnet.Prefix = v.GetString(key + "mask")
- if subnet.Prefix == "" {
- break
- }
- subnet.SourceIPs = v.GetStringSlice(key + "source_ips")
- cfg.Subnets = append(cfg.Subnets, subnet)
- }
-
- return
-}
-
-func fetchTracingAttributes(v *viper.Viper) (map[string]string, error) {
- attributes := make(map[string]string)
- for i := 0; ; i++ {
- key := cfgTracingAttributes + "." + strconv.Itoa(i) + "."
- attrKey := v.GetString(key + "key")
- attrValue := v.GetString(key + "value")
- if attrKey == "" {
- break
- }
-
- if _, ok := attributes[attrKey]; ok {
- return nil, fmt.Errorf("tracing attribute key %s defined more than once", attrKey)
- }
-
- if attrValue == "" {
- return nil, fmt.Errorf("empty tracing attribute value for key %s", attrKey)
- }
-
- attributes[attrKey] = attrValue
- }
-
- return attributes, nil
-}
diff --git a/config/config.env b/config/config.env
index 2822357..05b83b3 100644
--- a/config/config.env
+++ b/config/config.env
@@ -14,12 +14,8 @@ HTTP_GW_PPROF_ADDRESS=localhost:8083
HTTP_GW_PROMETHEUS_ENABLED=true
HTTP_GW_PROMETHEUS_ADDRESS=localhost:8084
-# Logger.
+# Log level.
HTTP_GW_LOGGER_LEVEL=debug
-HTTP_GW_LOGGER_SAMPLING_ENABLED=false
-HTTP_GW_LOGGER_SAMPLING_INITIAL=100
-HTTP_GW_LOGGER_SAMPLING_THEREAFTER=100
-HTTP_GW_LOGGER_SAMPLING_INTERVAL=1s
HTTP_GW_SERVER_0_ADDRESS=0.0.0.0:443
HTTP_GW_SERVER_0_TLS_ENABLED=false
@@ -103,11 +99,6 @@ HTTP_GW_ZIP_COMPRESSION=false
HTTP_GW_TRACING_ENABLED=true
HTTP_GW_TRACING_ENDPOINT="localhost:4317"
HTTP_GW_TRACING_EXPORTER="otlp_grpc"
-HTTP_GW_TRACING_TRUSTED_CA=""
-HTTP_GW_TRACING_ATTRIBUTES_0_KEY=key0
-HTTP_GW_TRACING_ATTRIBUTES_0_VALUE=value
-HTTP_GW_TRACING_ATTRIBUTES_1_KEY=key1
-HTTP_GW_TRACING_ATTRIBUTES_1_VALUE=value
HTTP_GW_RUNTIME_SOFT_MEMORY_LIMIT=1073741824
@@ -130,35 +121,3 @@ HTTP_GW_RESOLVE_BUCKET_DEFAULT_NAMESPACES="" "root"
# Max attempt to make successful tree request.
# default value is 0 that means the number of attempts equals to number of nodes in pool.
HTTP_GW_FROSTFS_TREE_POOL_MAX_ATTEMPTS=0
-
-HTTP_GW_CORS_ALLOW_ORIGIN="*"
-HTTP_GW_CORS_ALLOW_METHODS="GET" "POST"
-HTTP_GW_CORS_ALLOW_HEADERS="*"
-HTTP_GW_CORS_EXPOSE_HEADERS="*"
-HTTP_GW_CORS_ALLOW_CREDENTIALS=false
-HTTP_GW_CORS_MAX_AGE=600
-
-# Multinet properties
-# Enable multinet support
-HTTP_GW_MULTINET_ENABLED=false
-# Strategy to pick source IP address
-HTTP_GW_MULTINET_BALANCER=roundrobin
-# Restrict requests with unknown destination subnet
-HTTP_GW_MULTINET_RESTRICT=false
-# Delay between ipv6 to ipv4 fallback switch
-HTTP_GW_MULTINET_FALLBACK_DELAY=300ms
-# List of subnets and IP addresses to use as source for those subnets
-HTTP_GW_MULTINET_SUBNETS_1_MASK=1.2.3.4/24
-HTTP_GW_MULTINET_SUBNETS_1_SOURCE_IPS=1.2.3.4 1.2.3.5
-
-# Number of workers in handler's worker pool
-HTTP_GW_WORKER_POOL_SIZE=1000
-
-# Index page
-# Enable index page support
-HTTP_GW_INDEX_PAGE_ENABLED=false
-# Index page template path
-HTTP_GW_INDEX_PAGE_TEMPLATE_PATH=internal/handler/templates/index.gotmpl
-
-# Enable using fallback path to search for a object by attribute
-HTTP_GW_FEATURES_ENABLE_FILEPATH_FALLBACK=false
diff --git a/config/config.yaml b/config/config.yaml
index 6296bd9..7f8077b 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -9,26 +9,14 @@ pprof:
prometheus:
enabled: false # Enable metrics.
address: localhost:8084
-
tracing:
enabled: true
exporter: "otlp_grpc"
endpoint: "localhost:4317"
- trusted_ca: ""
- attributes:
- - key: key0
- value: value
- - key: key1
- value: value
logger:
level: debug # Log level.
destination: stdout
- sampling:
- enabled: false
- initial: 100
- thereafter: 100
- interval: 1s
server:
- address: 0.0.0.0:8080
@@ -113,14 +101,6 @@ request_timeout: 5s # Timeout to check node health during rebalance.
rebalance_timer: 30s # Interval to check nodes health.
pool_error_threshold: 100 # The number of errors on connection after which node is considered as unhealthy.
-# Number of workers in handler's worker pool
-worker_pool_size: 1000
-
-# Enable index page to see objects list for specified container and prefix
-index_page:
- enabled: false
- template_path: internal/handler/templates/index.gotmpl
-
zip:
compression: false # Enable zip compression to download files by common prefix.
@@ -146,33 +126,4 @@ cache:
resolve_bucket:
namespace_header: X-Frostfs-Namespace
- default_namespaces: [ "", "root" ]
-
-cors:
- allow_origin: ""
- allow_methods: []
- allow_headers: []
- expose_headers: []
- allow_credentials: false
- max_age: 600
-
-# Multinet properties
-multinet:
- # Enable multinet support
- enabled: false
- # Strategy to pick source IP address
- balancer: roundrobin
- # Restrict requests with unknown destination subnet
- restrict: false
- # Delay between ipv6 to ipv4 fallback switch
- fallback_delay: 300ms
- # List of subnets and IP addresses to use as source for those subnets
- subnets:
- - mask: 1.2.3.4/24
- source_ips:
- - 1.2.3.4
- - 1.2.3.5
-
-features:
- # Enable using fallback path to search for a object by attribute
- enable_filepath_fallback: false
+ default_namespaces: [ "", "root" ]
\ No newline at end of file
diff --git a/docs/api.md b/docs/api.md
index e59956a..78df766 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -8,7 +8,7 @@
| `/zip/{cid}/{prefix}` | [Download objects in archive](#download-zip) |
**Note:** `cid` parameter can be base58 encoded container ID or container name
-(the name must be registered in NNS, see appropriate section in [nns.md](./nns.md)).
+(the name must be registered in NNS, see appropriate section in [README](../README.md#nns)).
Route parameters can be:
@@ -18,7 +18,7 @@ Route parameters can be:
### Bearer token
-All routes can accept [bearer token](./authentication.md) from:
+All routes can accept [bearer token](../README.md#authentication) from:
* `Authorization` header with `Bearer` type and base64-encoded token in
credentials field
@@ -95,12 +95,12 @@ The `filename` field from the multipart form will be set as `FileName` attribute
## Get object
-Route: `/get/{cid}/{oid}?[download=false]`
+Route: `/get/{cid}/{oid}?[download=true]`
| Route parameter | Type | Description |
|-----------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `cid` | Single | Base58 encoded `container ID` or `container name` from NNS or `bucket name`. |
-| `oid` | Single | Base58 encoded `object ID`. Also could be `S3 object name` if `cid` is specified as bucket name. |
+| `cid` | Single | Base58 encoded container ID or container name from NNS. |
+| `oid` | Single | Base58 encoded object ID. |
| `download` | Query | Set the `Content-Disposition` header as `attachment` in response.
This make the browser to download object as file instead of showing it on the page. |
### Methods
@@ -141,13 +141,6 @@ Get an object (payload and attributes) by an address.
| 400 | Some error occurred during object downloading. |
| 404 | Container or object not found. |
-###### Body
-
-Returns object data. If request performed from browser, either displays raw data or downloads it as
-attachment if `download` query parameter is set to `true`.
-If `index_page.enabled` is set to `true`, returns HTML with index-page if no object with specified
-S3-name was found.
-
#### HEAD
Get an object attributes by an address.
diff --git a/docs/authentication.md b/docs/authentication.md
deleted file mode 100644
index d8bb235..0000000
--- a/docs/authentication.md
+++ /dev/null
@@ -1,108 +0,0 @@
-# Request authentication
-
-HTTP Gateway does not authorize requests. Gateway converts HTTP request to a
-FrostFS request and signs it with its own private key.
-
-You can always upload files to public containers (open for anyone to put
-objects into), but for restricted containers you need to explicitly allow PUT
-operations for a request signed with your HTTP Gateway keys.
-
-If you don't want to manage gateway's secret keys and adjust policies when
-gateway configuration changes (new gate, key rotation, etc) or you plan to use
-public services, there is an option to let your application backend (or you) to
-issue Bearer Tokens and pass them from the client via gate down to FrostFS level
-to grant access.
-
-FrostFS Bearer Token basically is a container owner-signed policy (refer to FrostFS
-documentation for more details). There are two options to pass them to gateway:
-* "Authorization" header with "Bearer" type and base64-encoded token in
- credentials field
-* "Bearer" cookie with base64-encoded token contents
-
-For example, you have a mobile application frontend with a backend part storing
-data in FrostFS. When a user authorizes in the mobile app, the backend issues a FrostFS
-Bearer token and provides it to the frontend. Then, the mobile app may generate
-some data and upload it via any available FrostFS HTTP Gateway by adding
-the corresponding header to the upload request. Accessing policy protected data
-works the same way.
-
-##### Example
-In order to generate a bearer token, you need to have wallet (which will be used to sign the token)
-
-1. Suppose you have a container with private policy for wallet key
-
-```
-$ frostfs-cli container create -r
Possible values: `debug`, `info`, `warn`, `error`, `dpanic`, `panic`, `fatal`. |
-| `destination` | `string` | no | `stdout` | Destination for logger: `stdout` or `journald` |
-| `sampling.enabled` | `bool` | no | false | Sampling enabling flag. |
-| `sampling.initial` | `int` | no | '100' | Sampling count of first log entries. |
-| `sampling.thereafter` | `int` | no | '100' | Sampling count of entries after an `interval`. |
-| `sampling.interval` | `duration` | no | '1s' | Sampling interval of messaging similar entries. |
+| Parameter | Type | SIGHUP reload | Default value | Description |
+|---------------|----------|---------------|---------------|----------------------------------------------------------------------------------------------------|
+| `level` | `string` | yes | `debug` | Logging level.
Possible values: `debug`, `info`, `warn`, `error`, `dpanic`, `panic`, `fatal`. |
+| `destination` | `string` | no | `stdout` | Destination for logger: `stdout` or `journald` |
# `web` section
@@ -270,37 +256,13 @@ tracing:
enabled: true
exporter: "otlp_grpc"
endpoint: "localhost:4317"
- trusted_ca: "/etc/ssl/telemetry-trusted-ca.pem"
- attributes:
- - key: key0
- value: value
- - key: key1
- value: value
```
-| Parameter | Type | SIGHUP reload | Default value | Description |
-| ------------ | -------------------------------------- | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
-| `enabled` | `bool` | yes | `false` | Flag to enable the tracing. |
-| `exporter` | `string` | yes | | Trace collector type (`stdout` or `otlp_grpc` are supported). |
-| `endpoint` | `string` | yes | | Address of collector endpoint for OTLP exporters. |
-| `trusted_ca` | `string` | yes | | Path to certificate of a certification authority in pem format, that issued the TLS certificate of the telemetry remote server. |
-| `attributes` | [[]Attributes](#attributes-subsection) | yes | | An array of configurable attributes in key-value format. |
-
-
-#### `attributes` subsection
-
-```yaml
- attributes:
- - key: key0
- value: value
- - key: key1
- value: value
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-|-----------------------|----------|---------------|---------------|----------------------------------------------------------|
-| `key` | `string` | yes | | Attribute key. |
-| `value` | `string` | yes | | Attribute value. |
+| Parameter | Type | SIGHUP reload | Default value | Description |
+|------------|----------|---------------|------------------|---------------------------------------------------------------|
+| `enabled` | `bool` | yes | `false` | Flag to enable the tracing. |
+| `exporter` | `string` | yes | | Trace collector type (`stdout` or `otlp_grpc` are supported). |
+| `endpoint` | `string` | yes | | Address of collector endpoint for OTLP exporters. |
# `runtime` section
Contains runtime parameters.
@@ -373,100 +335,4 @@ resolve_bucket:
| Parameter | Type | SIGHUP reload | Default value | Description |
|----------------------|------------|---------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------|
| `namespace_header` | `string` | yes | `X-Frostfs-Namespace` | Header to determine zone to resolve bucket name. |
-| `default_namespaces` | `[]string` | yes | ["","root"] | Namespaces that should be handled as default. |
-
-# `index_page` section
-
-Parameters for index HTML-page output. Activates if `GetObject` request returns `not found`. Two
-index page modes available:
-
-* `s3` mode uses tree service for listing objects,
-* `native` sends requests to nodes via native protocol.
- If request pass S3-bucket name instead of CID, `s3` mode will be used, otherwise `native`.
-
-```yaml
-index_page:
- enabled: false
- template_path: ""
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-|-----------------|----------|---------------|---------------|---------------------------------------------------------------------------------|
-| `enabled` | `bool` | yes | `false` | Flag to enable index_page return if no object with specified S3-name was found. |
-| `template_path` | `string` | yes | `""` | Path to .gotmpl file with html template for index_page. |
-
-# `cors` section
-
-Parameters for CORS (used in OPTIONS requests and responses in all handlers).
-If values are not set, headers will not be included to response.
-
-```yaml
-cors:
- allow_origin: "*"
- allow_methods: ["GET", "HEAD"]
- allow_headers: ["Authorization"]
- expose_headers: ["*"]
- allow_credentials: false
- max_age: 600
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-|---------------------|------------|---------------|---------------|--------------------------------------------------------|
-| `allow_origin` | `string` | yes | | Values for `Access-Control-Allow-Origin` headers. |
-| `allow_methods` | `[]string` | yes | | Values for `Access-Control-Allow-Methods` headers. |
-| `allow_headers` | `[]string` | yes | | Values for `Access-Control-Allow-Headers` headers. |
-| `expose_headers` | `[]string` | yes | | Values for `Access-Control-Expose-Headers` headers. |
-| `allow_credentials` | `bool` | yes | `false` | Values for `Access-Control-Allow-Credentials` headers. |
-| `max_age` | `int` | yes | `600` | Values for `Access-Control-Max-Age ` headers. |
-
-# `multinet` section
-
-Configuration of multinet support.
-
-```yaml
-multinet:
- enabled: false
- balancer: roundrobin
- restrict: false
- fallback_delay: 300ms
- subnets:
- - mask: 1.2.3.4/24
- source_ips:
- - 1.2.3.4
- - 1.2.3.5
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-|------------------|--------------------------------|---------------|---------------|--------------------------------------------------------------------------------------------|
-| `enabled` | `bool` | yes | `false` | Enables multinet setting to manage source ip of outcoming requests. |
-| `balancer` | `string` | yes | `""` | Strategy to pick source IP. By default picks first address. Supports `roundrobin` setting. |
-| `restrict` | `bool` | yes | `false` | Restricts requests to an undefined subnets. |
-| `fallback_delay` | `duration` | yes | `300ms` | Delay between IPv6 and IPv4 fallback stack switch. |
-| `subnets` | [[]Subnet](#subnet-subsection) | yes | | Set of subnets to apply multinet dial settings. |
-
-#### `subnet` subsection
-
-```yaml
-- mask: 1.2.3.4/24
- source_ips:
- - 1.2.3.4
- - 1.2.3.5
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-|--------------|------------|---------------|---------------|----------------------------------------------------------------------|
-| `mask` | `string` | yes | | Destination subnet. |
-| `source_ips` | `[]string` | yes | | Array of source IP addresses to use when dialing destination subnet. |
-
-# `features` section
-
-Contains parameters for enabling features.
-
-```yaml
-features:
- enable_filepath_fallback: true
-```
-
-| Parameter | Type | SIGHUP reload | Default value | Description |
-| ----------------------------------- | ------ | ------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `features.enable_filepath_fallback` | `bool` | yes | `false` | Enable using fallback path to search for a object by attribute. If the value of the `FilePath` attribute in the request contains no `/` symbols or single leading `/` symbol and the object was not found, then an attempt is made to search for the object by the attribute `FileName`. |
+| `default_namespaces` | `[]string` | yes | ["","root"] | Namespaces that should be handled as default. |
\ No newline at end of file
diff --git a/docs/nns.md b/docs/nns.md
deleted file mode 100644
index acb9f21..0000000
--- a/docs/nns.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Nicename Resolving with NNS
-
-Steps to start using name resolving:
-
-1. Enable NNS resolving in config (`rpc_endpoint` must be a valid neo rpc node, see [configs](./config) for other examples):
-
-```yaml
-rpc_endpoint: http://morph-chain.frostfs.devenv:30333
-resolve_order:
- - nns
-```
-
-2. Make sure your container is registered in NNS contract. If you use [frostfs-dev-env](https://git.frostfs.info/TrueCloudLab/frostfs-dev-env)
- you can check if your container (e.g. with `container-name` name) is registered in NNS:
-
-```shell
-$ curl -s --data '{"id":1,"jsonrpc":"2.0","method":"getcontractstate","params":[1]}' \
- http://morph-chain.frostfs.devenv:30333 | jq -r '.result.hash'
-
-0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667
-
-$ docker exec -it morph_chain neo-go \
- contract testinvokefunction \
- -r http://morph-chain.frostfs.devenv:30333 0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667 \
- resolve string:container-name.container int:16 \
- | jq -r '.stack[0].value | if type=="array" then .[0].value else . end' \
- | base64 -d && echo
-
-7f3vvkw4iTiS5ZZbu5BQXEmJtETWbi3uUjLNaSs29xrL
-```
-
-3. Use container name instead of its `$CID`. For example:
-
-```shell
-$ curl http://localhost:8082/get_by_attribute/container-name/FileName/object-name
-```
diff --git a/go.mod b/go.mod
index 3dd27b8..dd2896c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,37 +1,33 @@
module git.frostfs.info/TrueCloudLab/frostfs-http-gw
-go 1.22
+go 1.20
require (
- git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88
- git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20241206094944-81c423e7094d
- git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
+ git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4
+ git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
+ git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
github.com/bluele/gcache v0.0.2
- github.com/docker/go-units v0.4.0
github.com/fasthttp/router v1.4.1
- github.com/nspcc-dev/neo-go v0.106.2
- github.com/panjf2000/ants/v2 v2.5.0
- github.com/prometheus/client_golang v1.19.0
- github.com/prometheus/client_model v0.5.0
+ github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc
+ github.com/prometheus/client_golang v1.15.1
+ github.com/prometheus/client_model v0.3.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0
github.com/ssgreg/journald v1.0.0
- github.com/stretchr/testify v1.9.0
+ github.com/stretchr/testify v1.8.3
github.com/testcontainers/testcontainers-go v0.13.0
- github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4
github.com/valyala/fasthttp v1.34.0
- go.opentelemetry.io/otel v1.28.0
- go.opentelemetry.io/otel/trace v1.28.0
- go.uber.org/zap v1.27.0
- golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
- golang.org/x/net v0.26.0
- golang.org/x/sys v0.22.0
- google.golang.org/grpc v1.66.2
+ go.opentelemetry.io/otel v1.16.0
+ go.opentelemetry.io/otel/trace v1.16.0
+ go.uber.org/zap v1.24.0
+ golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
+ golang.org/x/net v0.10.0
+ google.golang.org/grpc v1.55.0
)
require (
- git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e // indirect
+ git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb // indirect
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 // indirect
git.frostfs.info/TrueCloudLab/hrw v1.2.1 // indirect
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
@@ -39,53 +35,53 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.2 // indirect
- github.com/VictoriaMetrics/easyproto v0.1.4 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
- github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/cenkalti/backoff/v4 v4.3.0 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.0.3 // indirect
github.com/containerd/containerd v1.6.2 // indirect
- github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
+ github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.14+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.6.0 // indirect
- github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/google/uuid v1.6.0 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
+ github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
- github.com/gorilla/websocket v1.5.1 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
- github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect
+ github.com/hashicorp/golang-lru v0.6.0 // indirect
+ github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
- github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.16.4 // indirect
github.com/magiconair/properties v1.8.7 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/sys/mount v0.3.2 // indirect
github.com/moby/sys/mountinfo v0.6.1 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
- github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 // indirect
- github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect
- github.com/nspcc-dev/rfc6979 v0.2.1 // indirect
+ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect
+ github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce // indirect
+ github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/common v0.48.0 // indirect
- github.com/prometheus/procfs v0.12.0 // indirect
+ github.com/prometheus/common v0.42.0 // indirect
+ github.com/prometheus/procfs v0.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/savsgio/gotils v0.0.0-20210617111740-97865ed5a873 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
@@ -97,23 +93,24 @@ require (
github.com/twmb/murmur3 v1.1.8 // indirect
github.com/urfave/cli v1.22.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- go.etcd.io/bbolt v1.3.9 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
- go.opentelemetry.io/otel/metric v1.28.0 // indirect
- go.opentelemetry.io/otel/sdk v1.28.0 // indirect
- go.opentelemetry.io/proto/otlp v1.3.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 // indirect
+ go.opentelemetry.io/otel/metric v1.16.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.16.0 // indirect
+ go.opentelemetry.io/proto/otlp v0.19.0 // indirect
+ go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/crypto v0.24.0 // indirect
- golang.org/x/sync v0.7.0 // indirect
- golang.org/x/term v0.21.0 // indirect
- golang.org/x/text v0.16.0 // indirect
+ golang.org/x/crypto v0.9.0 // indirect
+ golang.org/x/sync v0.2.0 // indirect
+ golang.org/x/sys v0.8.0 // indirect
+ golang.org/x/term v0.8.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 7f43c86..1bd67bc 100644
--- a/go.sum
+++ b/go.sum
@@ -37,18 +37,18 @@ 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=
-git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e h1:kcBqZBiFIUBATUqEuvVigtkJJWQ2Gug/eYXn967o3M4=
-git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
+git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4 h1:wjLfZ3WCt7qNGsQv+Jl0TXnmtg0uVk/jToKPFTBc/jo=
+git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
+git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb h1:S/TrbOOu9qEXZRZ9/Ddw7crnxbBUQLo68PSzQWYrc9M=
+git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
-git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88 h1:9bvBDLApbbO5sXBKdODpE9tzy3HV99nXxkDWNn22rdI=
-git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88/go.mod h1:kbwB4v2o6RyOfCo9kEFeUDZIX3LKhmS0yXPrtvzkQ1g=
-git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20241206094944-81c423e7094d h1:FpXI+mOrmJk3t2MKQFZuhLjCHDyDeo5rtP1WXl7gUWc=
-git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20241206094944-81c423e7094d/go.mod h1:eoK7+KZQ9GJxbzIs6vTnoUJqFDppavInLRHaN4MYgZg=
+git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
+git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6/go.mod h1:W8Nn08/l6aQ7UlIbpF7FsQou7TVpcRD1ZT1KG4TrFhE=
+git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939 h1:jZEepi9yWmqrWgLRQcHQu4YPJaudmd7d2AEhpmM3m4U=
+git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939/go.mod h1:t1akKcUH7iBrFHX8rSXScYMP17k2kYQXMbZooiL5Juw=
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
-git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972 h1:/960fWeyn2AFHwQUwDsWB3sbP6lTEnFnMzLMM6tx6N8=
-git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972/go.mod h1:2hM42MBrlhvN6XToaW6OWNk5ZLcu1FhaukGgxtfpDDI=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=
@@ -71,6 +71,10 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
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/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1:MJCkWUBhi9pn/CrYO1Q3P687y2KeahrOPS9BD9LDGb0=
+github.com/CityOfZion/neo-go v0.70.1-pre.0.20191209120015-fccb0085941e/go.mod h1:0enZl0az8xA6PVkwzEOwPWVJGqlt/GO4hA4kmQ5Xzig=
+github.com/CityOfZion/neo-go v0.70.1-pre.0.20191212173117-32ac01130d4c/go.mod h1:JtlHfeqLywZLswKIKFnAp+yzezY4Dji9qlfQKB2OD/I=
+github.com/CityOfZion/neo-go v0.71.1-pre.0.20200129171427-f773ec69fb84/go.mod h1:FLI526IrRWHmcsO+mHsCbj64pJZhwQFTLJZu+A4PGOA=
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=
@@ -101,22 +105,31 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
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/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc=
-github.com/VictoriaMetrics/easyproto v0.1.4/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710=
+github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
+github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
+github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs=
+github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
+github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
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/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
-github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
+github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
+github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
+github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
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=
@@ -125,27 +138,39 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
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/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
-github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
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/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
+github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
+github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
+github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
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/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
-github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/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/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
@@ -162,12 +187,12 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
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=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
-github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
-github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc=
-github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
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=
@@ -216,7 +241,6 @@ github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR
github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/continuity v0.2.2 h1:QSqfxcn8c+12slxwu00AtzXrsami0MJb/MQs9lOLHLA=
-github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
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=
@@ -278,8 +302,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
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 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1/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=
@@ -290,11 +314,13 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S
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 v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -334,16 +360,20 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fasthttp/router v1.4.1 h1:3xPUO+hy/HAkgGDSd5sX5w18cyGDIFbC7vip8KwPDk8=
github.com/fasthttp/router v1.4.1/go.mod h1:4P0Kq4C882tA2evBKDW7De7hGfWmvV8FN+zqt8Lu49Q=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
-github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -358,13 +388,17 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
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/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
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-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
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 v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
-github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
@@ -378,11 +412,13 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
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/redis v6.10.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
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-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-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
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=
@@ -399,6 +435,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
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=
@@ -413,6 +451,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -430,9 +469,14 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
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=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -447,8 +491,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
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=
@@ -471,9 +515,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.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/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
@@ -487,8 +530,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
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/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
-github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/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=
@@ -496,20 +539,23 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
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/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08=
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-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/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/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
-github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
+github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU=
+github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
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/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
-github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
+github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
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=
@@ -520,24 +566,31 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
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/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
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.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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
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.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
@@ -552,8 +605,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
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/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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=
@@ -568,18 +621,23 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
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.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
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-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
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/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
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=
@@ -588,8 +646,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
-github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
github.com/moby/sys/mount v0.3.2 h1:uq/CiGDZPvr+c85RYHtKIUORFbmavBUyWH3E1NEyjqI=
@@ -607,49 +663,74 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
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/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
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/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
-github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
-github.com/nspcc-dev/neo-go v0.106.2 h1:KXSJ2J5Oacc7LrX3r4jvnC8ihKqHs5NB21q4f2S3r9o=
-github.com/nspcc-dev/neo-go v0.106.2/go.mod h1:Ojwfx3/lv0VTeEHMpQ17g0wTnXcCSoFQVq5GEeCZmGo=
-github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k=
-github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
-github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
-github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw=
+github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY=
+github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
+github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
+github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y=
+github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647/go.mod h1:g9xisXmX9NP9MjioaTe862n9SlZTrP+6PVUWLBYOr98=
+github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
+github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
+github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
+github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
+github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
+github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
+github.com/nspcc-dev/neo-go v0.99.4/go.mod h1:mKTolfRUfKjFso5HPvGSQtUZc70n0VKBMs16eGuC5gA=
+github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc h1:fySIWvUQsitK5e5qYIHnTDCXuPpwzz89SEUEIyY11sg=
+github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc/go.mod h1:s9QhjMC784MWqTURovMbyYduIJc86mnCruxcMiAebpc=
+github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
+github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce h1:vLGuUNDkmQrWMa4rr4vTd1u8ULqejWxVmNz1L7ocTEI=
+github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce/go.mod h1:ZUuXOkdtHZgaC13za/zMgXfQFncZ0jLzfQTe+OsDOtg=
+github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
+github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
+github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
+github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
+github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
+github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs=
+github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
+github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
+github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
+github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
+github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
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.8.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.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
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.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/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.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
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=
@@ -680,13 +761,12 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
-github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
-github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
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/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pierrec/lz4 v2.6.1+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=
@@ -701,24 +781,32 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
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.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
-github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
+github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
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-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.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
-github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
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.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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
-github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
+github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
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-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -730,14 +818,16 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
+github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -762,6 +852,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/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.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
@@ -803,13 +894,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
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/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
@@ -817,8 +910,7 @@ github.com/testcontainers/testcontainers-go v0.13.0 h1:OUujSlEGsXVo/ykPVZk3KanBN
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/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4 h1:GpfJ7OdNjS7BFTVwNCUI9L4aCJOFRbr5fdHqjdhoYE8=
-github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4/go.mod h1:f3jBhpWvuZmue0HZK52GzRHJOYHYSILs/c8+K2S/J+o=
+github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@@ -834,6 +926,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4=
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo=
+github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c=
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=
@@ -852,15 +946,17 @@ 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/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
+github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
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/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
-go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
-go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -871,34 +967,43 @@ 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.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bEkIYOVMw4q1WJxIAGoFTrtYOzWuRQ=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
+go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
+go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0=
+go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc=
+go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
+go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
+go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
+go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
+go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
+go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
-go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
+go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
+go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
-go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
-go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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=
@@ -908,16 +1013,19 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
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=
@@ -928,8 +1036,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-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
-golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
+golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
+golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
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=
@@ -954,8 +1062,8 @@ 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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@@ -1003,12 +1111,15 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1018,6 +1129,9 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1029,14 +1143,17 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-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-20190204203706-41f3e6584952/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=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1053,11 +1170,14 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
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-20190813064441-fde4db37ae7a/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-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-20191010194322-b09406accb47/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=
@@ -1085,6 +1205,7 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
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-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1111,32 +1232,37 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
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=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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=
@@ -1146,6 +1272,7 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180318012157-96caea41033d/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-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1167,6 +1294,7 @@ golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1197,6 +1325,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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=
@@ -1206,14 +1335,11 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/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.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -1283,10 +1409,9 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
-google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1310,8 +1435,10 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
-google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
+google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
+google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
+google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1325,8 +1452,10 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/abiosoft/ishell.v2 v2.0.0/go.mod h1:sFp+cGtH6o4s1FtpVPTMcHq2yue+c4DGOVohJCPUzwY=
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=
@@ -1335,7 +1464,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
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=
@@ -1348,7 +1476,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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/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=
@@ -1358,7 +1485,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -1410,8 +1536,6 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
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=
-rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
-rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
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.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
diff --git a/internal/layer/tree_service.go b/internal/api/layer/tree_service.go
similarity index 64%
rename from internal/layer/tree_service.go
rename to internal/api/layer/tree_service.go
index ff80543..beb1e7a 100644
--- a/internal/layer/tree_service.go
+++ b/internal/api/layer/tree_service.go
@@ -4,15 +4,13 @@ import (
"context"
"errors"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/api"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
)
// TreeService provide interface to interact with tree service using s3 data models.
type TreeService interface {
- GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error)
- GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) ([]data.NodeInfo, string, error)
- CheckSettingsNodeExists(ctx context.Context, bktInfo *data.BucketInfo) error
+ GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*api.NodeVersion, error)
}
var (
diff --git a/internal/data/tree.go b/internal/api/tree.go
similarity index 61%
rename from internal/data/tree.go
rename to internal/api/tree.go
index fcf8add..4d16cc7 100644
--- a/internal/data/tree.go
+++ b/internal/api/tree.go
@@ -1,4 +1,4 @@
-package data
+package api
import (
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@@ -7,21 +7,11 @@ import (
// NodeVersion represent node from tree service.
type NodeVersion struct {
BaseNodeVersion
+ DeleteMarker bool
}
// BaseNodeVersion is minimal node info from tree service.
// Basically used for "system" object.
type BaseNodeVersion struct {
- ID uint64
- OID oid.ID
- IsDeleteMarker bool
-}
-
-type NodeInfo struct {
- Meta []NodeMeta
-}
-
-type NodeMeta interface {
- GetKey() string
- GetValue() []byte
+ OID oid.ID
}
diff --git a/internal/data/info.go b/internal/data/bucket.go
similarity index 100%
rename from internal/data/info.go
rename to internal/data/bucket.go
diff --git a/internal/frostfs/services/pool_wrapper.go b/internal/frostfs/services/pool_wrapper.go
new file mode 100644
index 0000000..039d575
--- /dev/null
+++ b/internal/frostfs/services/pool_wrapper.go
@@ -0,0 +1,115 @@
+package services
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tokens"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree"
+ treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
+ grpcService "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree/service"
+)
+
+type GetNodeByPathResponseInfoWrapper struct {
+ response *grpcService.GetNodeByPathResponse_Info
+}
+
+func (n GetNodeByPathResponseInfoWrapper) GetNodeID() uint64 {
+ return n.response.GetNodeId()
+}
+
+func (n GetNodeByPathResponseInfoWrapper) GetParentID() uint64 {
+ return n.response.GetParentId()
+}
+
+func (n GetNodeByPathResponseInfoWrapper) GetTimestamp() uint64 {
+ return n.response.GetTimestamp()
+}
+
+func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta {
+ res := make([]tree.Meta, len(n.response.Meta))
+ for i, value := range n.response.Meta {
+ res[i] = value
+ }
+ return res
+}
+
+type GetSubTreeResponseBodyWrapper struct {
+ response *grpcService.GetSubTreeResponse_Body
+}
+
+func (n GetSubTreeResponseBodyWrapper) GetNodeID() uint64 {
+ return n.response.GetNodeId()
+}
+
+func (n GetSubTreeResponseBodyWrapper) GetParentID() uint64 {
+ return n.response.GetParentId()
+}
+
+func (n GetSubTreeResponseBodyWrapper) GetTimestamp() uint64 {
+ return n.response.GetTimestamp()
+}
+
+func (n GetSubTreeResponseBodyWrapper) GetMeta() []tree.Meta {
+ res := make([]tree.Meta, len(n.response.Meta))
+ for i, value := range n.response.Meta {
+ res[i] = value
+ }
+ return res
+}
+
+type PoolWrapper struct {
+ p *treepool.Pool
+}
+
+func NewPoolWrapper(p *treepool.Pool) *PoolWrapper {
+ return &PoolWrapper{p: p}
+}
+
+func (w *PoolWrapper) GetNodes(ctx context.Context, prm *tree.GetNodesParams) ([]tree.NodeResponse, error) {
+ poolPrm := treepool.GetNodesParams{
+ CID: prm.CnrID,
+ TreeID: prm.TreeID,
+ Path: prm.Path,
+ Meta: prm.Meta,
+ PathAttribute: tree.FileNameKey,
+ LatestOnly: prm.LatestOnly,
+ AllAttrs: prm.AllAttrs,
+ BearerToken: getBearer(ctx),
+ }
+
+ nodes, err := w.p.GetNodes(ctx, poolPrm)
+ if err != nil {
+ return nil, handleError(err)
+ }
+
+ res := make([]tree.NodeResponse, len(nodes))
+ for i, info := range nodes {
+ res[i] = GetNodeByPathResponseInfoWrapper{info}
+ }
+
+ return res, nil
+}
+
+func getBearer(ctx context.Context) []byte {
+ token, err := tokens.LoadBearerToken(ctx)
+ if err != nil {
+ return nil
+ }
+ return token.Marshal()
+}
+
+func handleError(err error) error {
+ if err == nil {
+ return nil
+ }
+ if errors.Is(err, treepool.ErrNodeNotFound) {
+ return fmt.Errorf("%w: %s", tree.ErrNodeNotFound, err.Error())
+ }
+ if errors.Is(err, treepool.ErrNodeAccessDenied) {
+ return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error())
+ }
+
+ return err
+}
diff --git a/internal/handler/browse.go b/internal/handler/browse.go
deleted file mode 100644
index 64ad1f5..0000000
--- a/internal/handler/browse.go
+++ /dev/null
@@ -1,382 +0,0 @@
-package handler
-
-import (
- "context"
- "html/template"
- "net/url"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
- cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
- oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
- "github.com/docker/go-units"
- "github.com/valyala/fasthttp"
- "go.uber.org/zap"
-)
-
-const (
- dateFormat = "02-01-2006 15:04"
- attrOID = "OID"
- attrCreated = "Created"
- attrFileName = "FileName"
- attrFilePath = "FilePath"
- attrSize = "Size"
- attrDeleteMarker = "IsDeleteMarker"
-)
-
-type (
- BrowsePageData struct {
- HasErrors bool
- Container string
- Prefix string
- Protocol string
- Objects []ResponseObject
- }
- ResponseObject struct {
- OID string
- Created string
- FileName string
- FilePath string
- Size string
- IsDir bool
- GetURL string
- IsDeleteMarker bool
- }
-)
-
-func newListObjectsResponseS3(attrs map[string]string) ResponseObject {
- return ResponseObject{
- Created: formatTimestamp(attrs[attrCreated]),
- OID: attrs[attrOID],
- FileName: attrs[attrFileName],
- Size: attrs[attrSize],
- IsDir: attrs[attrOID] == "",
- IsDeleteMarker: attrs[attrDeleteMarker] == "true",
- }
-}
-
-func newListObjectsResponseNative(attrs map[string]string) ResponseObject {
- filename := lastPathElement(attrs[object.AttributeFilePath])
- if filename == "" {
- filename = attrs[attrFileName]
- }
- return ResponseObject{
- OID: attrs[attrOID],
- Created: formatTimestamp(attrs[object.AttributeTimestamp] + "000"),
- FileName: filename,
- FilePath: attrs[object.AttributeFilePath],
- Size: attrs[attrSize],
- IsDir: false,
- }
-}
-
-func getNextDir(filepath, prefix string) string {
- restPath := strings.Replace(filepath, prefix, "", 1)
- index := strings.Index(restPath, "/")
- if index == -1 {
- return ""
- }
- return restPath[:index]
-}
-
-func lastPathElement(path string) string {
- if path == "" {
- return path
- }
- index := strings.LastIndex(path, "/")
- if index == len(path)-1 {
- index = strings.LastIndex(path[:index], "/")
- }
- return path[index+1:]
-}
-
-func parseTimestamp(tstamp string) (time.Time, error) {
- millis, err := strconv.ParseInt(tstamp, 10, 64)
- if err != nil {
- return time.Time{}, err
- }
-
- return time.UnixMilli(millis), nil
-}
-
-func formatTimestamp(strdate string) string {
- date, err := parseTimestamp(strdate)
- if err != nil || date.IsZero() {
- return ""
- }
-
- return date.Format(dateFormat)
-}
-
-func formatSize(strsize string) string {
- size, err := strconv.ParseFloat(strsize, 64)
- if err != nil {
- return "0B"
- }
- return units.HumanSize(size)
-}
-
-func parentDir(prefix string) string {
- index := strings.LastIndex(prefix, "/")
- if index == -1 {
- return prefix
- }
- return prefix[index:]
-}
-
-func trimPrefix(encPrefix string) string {
- prefix, err := url.PathUnescape(encPrefix)
- if err != nil {
- return ""
- }
- slashIndex := strings.LastIndex(prefix, "/")
- if slashIndex == -1 {
- return ""
- }
- return prefix[:slashIndex]
-}
-
-func urlencode(path string) string {
- var res strings.Builder
-
- prefixParts := strings.Split(path, "/")
- for _, prefixPart := range prefixParts {
- prefixPart = "/" + url.PathEscape(prefixPart)
- if prefixPart == "/." || prefixPart == "/.." {
- prefixPart = url.PathEscape(prefixPart)
- }
- res.WriteString(prefixPart)
- }
-
- return res.String()
-}
-
-type GetObjectsResponse struct {
- objects []ResponseObject
- hasErrors bool
-}
-
-func (h *Handler) getDirObjectsS3(ctx context.Context, bucketInfo *data.BucketInfo, prefix string) (*GetObjectsResponse, error) {
- nodes, _, err := h.tree.GetSubTreeByPrefix(ctx, bucketInfo, prefix, true)
- if err != nil {
- return nil, err
- }
-
- result := &GetObjectsResponse{
- objects: make([]ResponseObject, 0, len(nodes)),
- }
- for _, node := range nodes {
- meta := node.Meta
- if meta == nil {
- continue
- }
- var attrs = make(map[string]string, len(meta))
- for _, m := range meta {
- attrs[m.GetKey()] = string(m.GetValue())
- }
- obj := newListObjectsResponseS3(attrs)
- if obj.IsDeleteMarker {
- continue
- }
- obj.FilePath = prefix + obj.FileName
- obj.GetURL = "/get/" + bucketInfo.Name + urlencode(obj.FilePath)
- result.objects = append(result.objects, obj)
- }
-
- return result, nil
-}
-
-func (h *Handler) getDirObjectsNative(ctx context.Context, bucketInfo *data.BucketInfo, prefix string) (*GetObjectsResponse, error) {
- var basePath string
- if ind := strings.LastIndex(prefix, "/"); ind != -1 {
- basePath = prefix[:ind+1]
- }
-
- filters := object.NewSearchFilters()
- filters.AddRootFilter()
- if prefix != "" {
- filters.AddFilter(object.AttributeFilePath, prefix, object.MatchCommonPrefix)
- }
-
- prm := PrmObjectSearch{
- PrmAuth: PrmAuth{
- BearerToken: bearerToken(ctx),
- },
- Container: bucketInfo.CID,
- Filters: filters,
- }
- objectIDs, err := h.frostfs.SearchObjects(ctx, prm)
- if err != nil {
- return nil, err
- }
- defer objectIDs.Close()
-
- resp, err := h.headDirObjects(ctx, bucketInfo.CID, objectIDs, basePath)
- if err != nil {
- return nil, err
- }
-
- log := utils.GetReqLogOrDefault(ctx, h.log)
- dirs := make(map[string]struct{})
- result := &GetObjectsResponse{
- objects: make([]ResponseObject, 0, 100),
- }
- for objExt := range resp {
- if objExt.Error != nil {
- log.Error(logs.FailedToHeadObject, zap.Error(objExt.Error))
- result.hasErrors = true
- continue
- }
- if objExt.Object.IsDir {
- if _, ok := dirs[objExt.Object.FileName]; ok {
- continue
- }
- objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + urlencode(objExt.Object.FilePath)
- dirs[objExt.Object.FileName] = struct{}{}
- } else {
- objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + "/" + objExt.Object.OID
- }
- result.objects = append(result.objects, objExt.Object)
- }
- return result, nil
-}
-
-type ResponseObjectExtended struct {
- Object ResponseObject
- Error error
-}
-
-func (h *Handler) headDirObjects(ctx context.Context, cnrID cid.ID, objectIDs ResObjectSearch, basePath string) (<-chan ResponseObjectExtended, error) {
- res := make(chan ResponseObjectExtended)
-
- go func() {
- defer close(res)
- log := utils.GetReqLogOrDefault(ctx, h.log).With(
- zap.String("cid", cnrID.EncodeToString()),
- zap.String("path", basePath),
- )
- var wg sync.WaitGroup
- err := objectIDs.Iterate(func(id oid.ID) bool {
- wg.Add(1)
- err := h.workerPool.Submit(func() {
- defer wg.Done()
- var obj ResponseObjectExtended
- obj.Object, obj.Error = h.headDirObject(ctx, cnrID, id, basePath)
- res <- obj
- })
- if err != nil {
- wg.Done()
- log.Warn(logs.FailedToSumbitTaskToPool, zap.Error(err))
- }
- select {
- case <-ctx.Done():
- return true
- default:
- return false
- }
- })
- if err != nil {
- log.Error(logs.FailedToIterateOverResponse, zap.Error(err))
- }
- wg.Wait()
- }()
-
- return res, nil
-}
-
-func (h *Handler) headDirObject(ctx context.Context, cnrID cid.ID, objID oid.ID, basePath string) (ResponseObject, error) {
- addr := newAddress(cnrID, objID)
- obj, err := h.frostfs.HeadObject(ctx, PrmObjectHead{
- PrmAuth: PrmAuth{BearerToken: bearerToken(ctx)},
- Address: addr,
- })
- if err != nil {
- return ResponseObject{}, err
- }
-
- attrs := loadAttributes(obj.Attributes())
- attrs[attrOID] = objID.EncodeToString()
- if multipartSize, ok := attrs[attributeMultipartObjectSize]; ok {
- attrs[attrSize] = multipartSize
- } else {
- attrs[attrSize] = strconv.FormatUint(obj.PayloadSize(), 10)
- }
-
- dirname := getNextDir(attrs[object.AttributeFilePath], basePath)
- if dirname == "" {
- return newListObjectsResponseNative(attrs), nil
- }
-
- return ResponseObject{
- FileName: dirname,
- FilePath: basePath + dirname,
- IsDir: true,
- }, nil
-}
-
-type browseParams struct {
- bucketInfo *data.BucketInfo
- prefix string
- isNative bool
- listObjects func(ctx context.Context, bucketName *data.BucketInfo, prefix string) (*GetObjectsResponse, error)
-}
-
-func (h *Handler) browseObjects(c *fasthttp.RequestCtx, p browseParams) {
- const S3Protocol = "s3"
- const FrostfsProtocol = "frostfs"
-
- ctx := utils.GetContextFromRequest(c)
- reqLog := utils.GetReqLogOrDefault(ctx, h.log)
- log := reqLog.With(
- zap.String("bucket", p.bucketInfo.Name),
- zap.String("container", p.bucketInfo.CID.EncodeToString()),
- zap.String("prefix", p.prefix),
- )
- resp, err := p.listObjects(ctx, p.bucketInfo, p.prefix)
- if err != nil {
- logAndSendBucketError(c, log, err)
- return
- }
-
- objects := resp.objects
- sort.Slice(objects, func(i, j int) bool {
- if objects[i].IsDir == objects[j].IsDir {
- return objects[i].FileName < objects[j].FileName
- }
- return objects[i].IsDir
- })
-
- tmpl, err := template.New("index").Funcs(template.FuncMap{
- "formatSize": formatSize,
- "trimPrefix": trimPrefix,
- "urlencode": urlencode,
- "parentDir": parentDir,
- }).Parse(h.config.IndexPageTemplate())
- if err != nil {
- logAndSendBucketError(c, log, err)
- return
- }
- bucketName := p.bucketInfo.Name
- protocol := S3Protocol
- if p.isNative {
- bucketName = p.bucketInfo.CID.EncodeToString()
- protocol = FrostfsProtocol
- }
- if err = tmpl.Execute(c, &BrowsePageData{
- Container: bucketName,
- Prefix: p.prefix,
- Objects: objects,
- Protocol: protocol,
- HasErrors: resp.hasErrors,
- }); err != nil {
- logAndSendBucketError(c, log, err)
- return
- }
-}
diff --git a/internal/handler/download.go b/internal/handler/download.go
index 8766f0c..a7aee64 100644
--- a/internal/handler/download.go
+++ b/internal/handler/download.go
@@ -4,66 +4,38 @@ import (
"archive/zip"
"bufio"
"context"
- "errors"
"fmt"
"io"
"net/http"
"net/url"
"time"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/layer"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/response"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
+ "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
// DownloadByAddressOrBucketName handles download requests using simple cid/oid or bucketname/key format.
func (h *Handler) DownloadByAddressOrBucketName(c *fasthttp.RequestCtx) {
- cidParam := c.UserValue("cid").(string)
- oidParam := c.UserValue("oid").(string)
- downloadParam := c.QueryArgs().GetBool("download")
-
- ctx := utils.GetContextFromRequest(c)
- log := utils.GetReqLogOrDefault(ctx, h.log).With(
- zap.String("cid", cidParam),
- zap.String("oid", oidParam),
- )
-
- bktInfo, err := h.getBucketInfo(ctx, cidParam, log)
+ test, _ := c.UserValue("oid").(string)
+ var id oid.ID
+ err := id.DecodeString(test)
if err != nil {
- logAndSendBucketError(c, log, err)
- return
- }
-
- checkS3Err := h.tree.CheckSettingsNodeExists(ctx, bktInfo)
- if checkS3Err != nil && !errors.Is(checkS3Err, layer.ErrNodeNotFound) {
- logAndSendBucketError(c, log, checkS3Err)
- return
- }
-
- req := h.newRequest(c, log)
-
- var objID oid.ID
- if checkS3Err == nil && shouldDownload(oidParam, downloadParam) {
- h.byS3Path(ctx, req, bktInfo.CID, oidParam, h.receiveFile)
- } else if err = objID.DecodeString(oidParam); err == nil {
- h.byNativeAddress(ctx, req, bktInfo.CID, objID, h.receiveFile)
+ h.byObjectName(c, h.receiveFile)
} else {
- h.browseIndex(c, checkS3Err != nil)
+ h.byAddress(c, h.receiveFile)
}
}
-func shouldDownload(oidParam string, downloadParam bool) bool {
- return !isDir(oidParam) || downloadParam
-}
-
-func (h *Handler) newRequest(ctx *fasthttp.RequestCtx, log *zap.Logger) request {
- return request{
+func (h *Handler) newRequest(ctx *fasthttp.RequestCtx, log *zap.Logger) *request {
+ return &request{
RequestCtx: ctx,
log: log,
}
@@ -74,20 +46,19 @@ func (h *Handler) DownloadByAttribute(c *fasthttp.RequestCtx) {
h.byAttribute(c, h.receiveFile)
}
-func (h *Handler) search(ctx context.Context, cnrID cid.ID, key, val string, op object.SearchMatchType) (ResObjectSearch, error) {
+func (h *Handler) search(ctx context.Context, cid *cid.ID, key, val string, op object.SearchMatchType) (pool.ResObjectSearch, error) {
filters := object.NewSearchFilters()
filters.AddRootFilter()
filters.AddFilter(key, val, op)
- prm := PrmObjectSearch{
- PrmAuth: PrmAuth{
- BearerToken: bearerToken(ctx),
- },
- Container: cnrID,
- Filters: filters,
+ var prm pool.PrmObjectSearch
+ prm.SetContainerID(*cid)
+ prm.SetFilters(filters)
+ if btoken := bearerToken(ctx); btoken != nil {
+ prm.UseBearer(*btoken)
}
- return h.frostfs.SearchObjects(ctx, prm)
+ return h.pool.SearchObjects(ctx, prm)
}
func (h *Handler) addObjectToZip(zw *zip.Writer, obj *object.Object) (io.Writer, error) {
@@ -113,17 +84,16 @@ func (h *Handler) DownloadZipped(c *fasthttp.RequestCtx) {
scid, _ := c.UserValue("cid").(string)
prefix, _ := c.UserValue("prefix").(string)
- ctx := utils.GetContextFromRequest(c)
- log := utils.GetReqLogOrDefault(ctx, h.log)
-
prefix, err := url.QueryUnescape(prefix)
if err != nil {
- log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("prefix", prefix), zap.Error(err))
- ResponseError(c, "could not unescape prefix: "+err.Error(), fasthttp.StatusBadRequest)
+ h.log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("prefix", prefix), zap.Uint64("id", c.ID()), zap.Error(err))
+ response.Error(c, "could not unescape prefix: "+err.Error(), fasthttp.StatusBadRequest)
return
}
- log = log.With(zap.String("cid", scid), zap.String("prefix", prefix))
+ log := h.log.With(zap.String("cid", scid), zap.String("prefix", prefix), zap.Uint64("id", c.ID()))
+
+ ctx := utils.GetContextFromRequest(c)
bktInfo, err := h.getBucketInfo(ctx, scid, log)
if err != nil {
@@ -131,10 +101,10 @@ func (h *Handler) DownloadZipped(c *fasthttp.RequestCtx) {
return
}
- resSearch, err := h.search(ctx, bktInfo.CID, object.AttributeFilePath, prefix, object.MatchCommonPrefix)
+ resSearch, err := h.search(ctx, &bktInfo.CID, object.AttributeFilePath, prefix, object.MatchCommonPrefix)
if err != nil {
log.Error(logs.CouldNotSearchForObjects, zap.Error(err))
- ResponseError(c, "could not search for objects: "+err.Error(), fasthttp.StatusBadRequest)
+ response.Error(c, "could not search for objects: "+err.Error(), fasthttp.StatusBadRequest)
return
}
@@ -183,14 +153,13 @@ func (h *Handler) DownloadZipped(c *fasthttp.RequestCtx) {
}
func (h *Handler) zipObject(ctx context.Context, zipWriter *zip.Writer, addr oid.Address, btoken *bearer.Token, bufZip []byte) error {
- prm := PrmObjectGet{
- PrmAuth: PrmAuth{
- BearerToken: btoken,
- },
- Address: addr,
+ var prm pool.PrmObjectGet
+ prm.SetAddress(addr)
+ if btoken != nil {
+ prm.UseBearer(*btoken)
}
- resGet, err := h.frostfs.GetObject(ctx, prm)
+ resGet, err := h.pool.GetObject(ctx, prm)
if err != nil {
return fmt.Errorf("get FrostFS object: %v", err)
}
diff --git a/internal/handler/frostfs_mock.go b/internal/handler/frostfs_mock.go
deleted file mode 100644
index b60915e..0000000
--- a/internal/handler/frostfs_mock.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package handler
-
-import (
- "bytes"
- "context"
- "crypto/rand"
- "crypto/sha256"
- "fmt"
- "io"
- "strings"
-
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
- apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
- cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
- oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
- "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
-)
-
-type TestFrostFS struct {
- objects map[string]*object.Object
- containers map[string]*container.Container
- accessList map[string]bool
- key *keys.PrivateKey
-}
-
-func NewTestFrostFS(key *keys.PrivateKey) *TestFrostFS {
- return &TestFrostFS{
- objects: make(map[string]*object.Object),
- containers: make(map[string]*container.Container),
- accessList: make(map[string]bool),
- key: key,
- }
-}
-
-func (t *TestFrostFS) ContainerID(name string) (*cid.ID, error) {
- for id, cnr := range t.containers {
- if container.Name(*cnr) == name {
- var cnrID cid.ID
- return &cnrID, cnrID.DecodeString(id)
- }
- }
- return nil, fmt.Errorf("not found")
-}
-
-func (t *TestFrostFS) SetContainer(cnrID cid.ID, cnr *container.Container) {
- t.containers[cnrID.EncodeToString()] = cnr
-}
-
-// AllowUserOperation grants access to object operations.
-// Empty userID and objID means any user and object respectively.
-func (t *TestFrostFS) AllowUserOperation(cnrID cid.ID, userID user.ID, op acl.Op, objID oid.ID) {
- t.accessList[fmt.Sprintf("%s/%s/%s/%s", cnrID, userID, op, objID)] = true
-}
-
-func (t *TestFrostFS) Container(_ context.Context, prm PrmContainer) (*container.Container, error) {
- for k, v := range t.containers {
- if k == prm.ContainerID.EncodeToString() {
- return v, nil
- }
- }
-
- return nil, fmt.Errorf("container not found %s", prm.ContainerID)
-}
-
-func (t *TestFrostFS) requestOwner(btoken *bearer.Token) user.ID {
- if btoken != nil {
- return bearer.ResolveIssuer(*btoken)
- }
-
- var owner user.ID
- user.IDFromKey(&owner, t.key.PrivateKey.PublicKey)
- return owner
-}
-
-func (t *TestFrostFS) retrieveObject(addr oid.Address, btoken *bearer.Token) (*object.Object, error) {
- sAddr := addr.EncodeToString()
-
- if obj, ok := t.objects[sAddr]; ok {
- owner := t.requestOwner(btoken)
-
- if !t.isAllowed(addr.Container(), owner, acl.OpObjectGet, addr.Object()) {
- return nil, ErrAccessDenied
- }
-
- return obj, nil
- }
-
- return nil, fmt.Errorf("%w: %s", &apistatus.ObjectNotFound{}, addr)
-}
-
-func (t *TestFrostFS) HeadObject(_ context.Context, prm PrmObjectHead) (*object.Object, error) {
- return t.retrieveObject(prm.Address, prm.BearerToken)
-}
-
-func (t *TestFrostFS) GetObject(_ context.Context, prm PrmObjectGet) (*Object, error) {
- obj, err := t.retrieveObject(prm.Address, prm.BearerToken)
- if err != nil {
- return nil, err
- }
-
- return &Object{
- Header: *obj,
- Payload: io.NopCloser(bytes.NewReader(obj.Payload())),
- }, nil
-}
-
-func (t *TestFrostFS) RangeObject(_ context.Context, prm PrmObjectRange) (io.ReadCloser, error) {
- obj, err := t.retrieveObject(prm.Address, prm.BearerToken)
- if err != nil {
- return nil, err
- }
-
- off := prm.PayloadRange[0]
- payload := obj.Payload()[off : off+prm.PayloadRange[1]]
- return io.NopCloser(bytes.NewReader(payload)), nil
-}
-
-func (t *TestFrostFS) CreateObject(_ context.Context, prm PrmObjectCreate) (oid.ID, error) {
- b := make([]byte, 32)
- if _, err := io.ReadFull(rand.Reader, b); err != nil {
- return oid.ID{}, err
- }
- var id oid.ID
- id.SetSHA256(sha256.Sum256(b))
- prm.Object.SetID(id)
-
- attrs := prm.Object.Attributes()
- if prm.ClientCut {
- a := object.NewAttribute()
- a.SetKey("s3-client-cut")
- a.SetValue("true")
- attrs = append(attrs, *a)
- }
-
- prm.Object.SetAttributes(attrs...)
-
- if prm.Payload != nil {
- all, err := io.ReadAll(prm.Payload)
- if err != nil {
- return oid.ID{}, err
- }
- prm.Object.SetPayload(all)
- prm.Object.SetPayloadSize(uint64(len(all)))
- var hash checksum.Checksum
- checksum.Calculate(&hash, checksum.SHA256, all)
- prm.Object.SetPayloadChecksum(hash)
- }
-
- cnrID, _ := prm.Object.ContainerID()
- objID, _ := prm.Object.ID()
-
- owner := t.requestOwner(prm.BearerToken)
-
- if !t.isAllowed(cnrID, owner, acl.OpObjectPut, objID) {
- return oid.ID{}, ErrAccessDenied
- }
-
- addr := newAddress(cnrID, objID)
- t.objects[addr.EncodeToString()] = prm.Object
- return objID, nil
-}
-
-type resObjectSearchMock struct {
- res []oid.ID
-}
-
-func (r *resObjectSearchMock) Read(buf []oid.ID) (int, error) {
- for i := range buf {
- if i > len(r.res)-1 {
- return len(r.res), io.EOF
- }
- buf[i] = r.res[i]
- }
-
- r.res = r.res[len(buf):]
-
- return len(buf), nil
-}
-
-func (r *resObjectSearchMock) Iterate(f func(oid.ID) bool) error {
- for _, id := range r.res {
- if f(id) {
- return nil
- }
- }
-
- return nil
-}
-
-func (r *resObjectSearchMock) Close() {}
-
-func (t *TestFrostFS) SearchObjects(_ context.Context, prm PrmObjectSearch) (ResObjectSearch, error) {
- if !t.isAllowed(prm.Container, t.requestOwner(prm.BearerToken), acl.OpObjectSearch, oid.ID{}) {
- return nil, ErrAccessDenied
- }
-
- cidStr := prm.Container.EncodeToString()
- var res []oid.ID
-
- if len(prm.Filters) == 1 { // match root filter
- for k, v := range t.objects {
- if strings.Contains(k, cidStr) {
- id, _ := v.ID()
- res = append(res, id)
- }
- }
- return &resObjectSearchMock{res: res}, nil
- }
-
- filter := prm.Filters[1]
- if len(prm.Filters) != 2 ||
- filter.Operation() != object.MatchCommonPrefix && filter.Operation() != object.MatchStringEqual {
- return nil, fmt.Errorf("usupported filters")
- }
-
- for k, v := range t.objects {
- if strings.Contains(k, cidStr) && isMatched(v.Attributes(), filter) {
- id, _ := v.ID()
- res = append(res, id)
- }
- }
-
- return &resObjectSearchMock{res: res}, nil
-}
-
-func (t *TestFrostFS) InitMultiObjectReader(context.Context, PrmInitMultiObjectReader) (io.Reader, error) {
- return nil, nil
-}
-
-func isMatched(attributes []object.Attribute, filter object.SearchFilter) bool {
- for _, attr := range attributes {
- if attr.Key() == filter.Header() {
- switch filter.Operation() {
- case object.MatchStringEqual:
- return attr.Value() == filter.Value()
- case object.MatchCommonPrefix:
- return strings.HasPrefix(attr.Value(), filter.Value())
- default:
- return false
- }
- }
- }
-
- return false
-}
-
-func (t *TestFrostFS) GetEpochDurations(context.Context) (*utils.EpochDurations, error) {
- return &utils.EpochDurations{
- CurrentEpoch: 10,
- MsPerBlock: 1000,
- BlockPerEpoch: 100,
- }, nil
-}
-
-func (t *TestFrostFS) isAllowed(cnrID cid.ID, userID user.ID, op acl.Op, objID oid.ID) bool {
- keysToCheck := []string{
- fmt.Sprintf("%s/%s/%s/%s", cnrID, userID, op, objID),
- fmt.Sprintf("%s/%s/%s/%s", cnrID, userID, op, oid.ID{}),
- fmt.Sprintf("%s/%s/%s/%s", cnrID, user.ID{}, op, objID),
- fmt.Sprintf("%s/%s/%s/%s", cnrID, user.ID{}, op, oid.ID{}),
- }
-
- for _, key := range keysToCheck {
- if t.accessList[key] {
- return true
- }
- }
- return false
-}
diff --git a/internal/handler/handler.go b/internal/handler/handler.go
index ed90163..f88dff1 100644
--- a/internal/handler/handler.go
+++ b/internal/handler/handler.go
@@ -11,17 +11,18 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/cache"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler/middleware"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/layer"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/resolver"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/response"
+ "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
+ "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
- "github.com/panjf2000/ants/v2"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
@@ -30,278 +31,163 @@ type Config interface {
DefaultTimestamp() bool
ZipCompression() bool
ClientCut() bool
- IndexPageEnabled() bool
- IndexPageTemplate() string
BufferMaxSizeForPut() uint64
NamespaceHeader() string
- EnableFilepathFallback() bool
-}
-
-// PrmContainer groups parameters of FrostFS.Container operation.
-type PrmContainer struct {
- // Container identifier.
- ContainerID cid.ID
-}
-
-// PrmAuth groups authentication parameters for the FrostFS operation.
-type PrmAuth struct {
- // Bearer token to be used for the operation. Overlaps PrivateKey. Optional.
- BearerToken *bearer.Token
-}
-
-// PrmObjectHead groups parameters of FrostFS.HeadObject operation.
-type PrmObjectHead struct {
- // Authentication parameters.
- PrmAuth
-
- // Address to read the object header from.
- Address oid.Address
-}
-
-// PrmObjectGet groups parameters of FrostFS.GetObject operation.
-type PrmObjectGet struct {
- // Authentication parameters.
- PrmAuth
-
- // Address to read the object header from.
- Address oid.Address
-}
-
-// PrmObjectRange groups parameters of FrostFS.RangeObject operation.
-type PrmObjectRange struct {
- // Authentication parameters.
- PrmAuth
-
- // Address to read the object header from.
- Address oid.Address
-
- // Offset-length range of the object payload to be read.
- PayloadRange [2]uint64
-}
-
-// Object represents FrostFS object.
-type Object struct {
- // Object header (doesn't contain payload).
- Header object.Object
-
- // Object payload part encapsulated in io.Reader primitive.
- // Returns ErrAccessDenied on read access violation.
- Payload io.ReadCloser
-}
-
-// PrmObjectCreate groups parameters of FrostFS.CreateObject operation.
-type PrmObjectCreate struct {
- // Authentication parameters.
- PrmAuth
-
- Object *object.Object
-
- // Object payload encapsulated in io.Reader primitive.
- Payload io.Reader
-
- // Enables client side object preparing.
- ClientCut bool
-
- // Disables using Tillich-Zémor hash for payload.
- WithoutHomomorphicHash bool
-
- // Sets max buffer size to read payload.
- BufferMaxSize uint64
-}
-
-// PrmObjectSearch groups parameters of FrostFS.sear SearchObjects operation.
-type PrmObjectSearch struct {
- // Authentication parameters.
- PrmAuth
-
- // Container to select the objects from.
- Container cid.ID
-
- Filters object.SearchFilters
-}
-
-type PrmInitMultiObjectReader struct {
- // payload range
- Off, Ln uint64
-
- Addr oid.Address
- Bearer *bearer.Token
-}
-
-type ResObjectSearch interface {
- Read(buf []oid.ID) (int, error)
- Iterate(f func(oid.ID) bool) error
- Close()
-}
-
-var (
- // ErrAccessDenied is returned from FrostFS in case of access violation.
- ErrAccessDenied = errors.New("access denied")
- // ErrGatewayTimeout is returned from FrostFS in case of timeout, deadline exceeded etc.
- ErrGatewayTimeout = errors.New("gateway timeout")
- // ErrQuotaLimitReached is returned from FrostFS in case of quota exceeded.
- ErrQuotaLimitReached = errors.New("quota limit reached")
-)
-
-// FrostFS represents virtual connection to FrostFS network.
-type FrostFS interface {
- Container(context.Context, PrmContainer) (*container.Container, error)
- HeadObject(context.Context, PrmObjectHead) (*object.Object, error)
- GetObject(context.Context, PrmObjectGet) (*Object, error)
- RangeObject(context.Context, PrmObjectRange) (io.ReadCloser, error)
- CreateObject(context.Context, PrmObjectCreate) (oid.ID, error)
- SearchObjects(context.Context, PrmObjectSearch) (ResObjectSearch, error)
- InitMultiObjectReader(ctx context.Context, p PrmInitMultiObjectReader) (io.Reader, error)
-
- utils.EpochInfoFetcher
-}
-
-type ContainerResolver interface {
- Resolve(ctx context.Context, name string) (*cid.ID, error)
}
type Handler struct {
log *zap.Logger
- frostfs FrostFS
+ pool *pool.Pool
ownerID *user.ID
config Config
- containerResolver ContainerResolver
- tree layer.TreeService
+ containerResolver *resolver.ContainerResolver
+ tree *tree.Tree
cache *cache.BucketCache
- workerPool *ants.Pool
}
-type AppParams struct {
- Logger *zap.Logger
- FrostFS FrostFS
- Owner *user.ID
- Resolver ContainerResolver
- Cache *cache.BucketCache
-}
-
-func New(params *AppParams, config Config, tree layer.TreeService, workerPool *ants.Pool) *Handler {
+func New(params *utils.AppParams, config Config, tree *tree.Tree) *Handler {
return &Handler{
log: params.Logger,
- frostfs: params.FrostFS,
+ pool: params.Pool,
ownerID: params.Owner,
config: config,
containerResolver: params.Resolver,
tree: tree,
cache: params.Cache,
- workerPool: workerPool,
}
}
-// byNativeAddress is a wrapper for function (e.g. request.headObject, request.receiveFile) that
+// byAddress is a wrapper for function (e.g. request.headObject, request.receiveFile) that
// prepares request and object address to it.
-func (h *Handler) byNativeAddress(ctx context.Context, req request, cnrID cid.ID, objID oid.ID, handler func(context.Context, request, oid.Address)) {
- addr := newAddress(cnrID, objID)
- handler(ctx, req, addr)
-}
-
-// byS3Path is a wrapper for function (e.g. request.headObject, request.receiveFile) that
-// resolves object address from S3-like path