Compare commits
37 commits
master
...
support/v0
Author | SHA1 | Date | |
---|---|---|---|
5abd69f58f | |||
0707f1e070 | |||
19262730c1 | |||
313ee45657 | |||
9637479d3b | |||
847cb28c81 | |||
a2422e74d7 | |||
85a5b65807 | |||
0e3dd2ff19 | |||
caea6e4208 | |||
94a21f5351 | |||
5d6d5e41d0 | |||
7d86b816a1 | |||
dea79631bb | |||
618ea318ba | |||
7ae4323116 | |||
c0f959ece7 | |||
0cf19d24ee | |||
188e0cfd01 | |||
50aeba6a4e | |||
c6d0e5fc44 | |||
377fa127b5 | |||
f02bad65a8 | |||
13d00dd7ce | |||
02122892ca | |||
272e3a0f03 | |||
65a8e2dadc | |||
b7e15402a1 | |||
0cc6b41b2d | |||
51be9d9778 | |||
1cad101609 | |||
d631ee55c9 | |||
85c8210ffd | |||
bcfbcdc82f | |||
fd310f5e9f | |||
1f5f2bd3d5 | |||
a32b41716f |
67 changed files with 2857 additions and 1044 deletions
|
@ -6,7 +6,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go_versions: [ '1.20', '1.21' ]
|
go_versions: [ '1.21', '1.22' ]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
|
|
||||||
- name: Run commit format checker
|
- name: Run commit format checker
|
||||||
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3
|
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3
|
||||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Install linters
|
- name: Install linters
|
||||||
|
@ -24,7 +24,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go_versions: [ '1.20', '1.21' ]
|
go_versions: [ '1.21', '1.22' ]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
|
|
||||||
- name: Install govulncheck
|
- name: Install govulncheck
|
||||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
|
|
53
CHANGELOG.md
53
CHANGELOG.md
|
@ -4,13 +4,39 @@ This document outlines major changes between releases.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.29.3] - 2024-07-19
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Support tree split environment when multiple nodes
|
||||||
|
may be part of the same sub path (#431)
|
||||||
|
- Collision of multipart name and system data in the tree (#431)
|
||||||
|
- Workaround for removal of multiple null versions in unversioned bucket (#431)
|
||||||
|
|
||||||
|
## [0.29.2] - 2024-07-03
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Parsing of put-bucket-setting retry configuration (#398)
|
||||||
|
|
||||||
|
## [0.29.1] - 2024-06-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- OPTIONS request processing for object operations (#399)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Retries of put-bucket-setting operation during container creation (#398)
|
||||||
|
|
||||||
|
## [0.29.0] - Zemu - 2024-05-27
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix marshaling errors in `DeleteObjects` method (#222)
|
- Fix marshaling errors in `DeleteObjects` method (#222)
|
||||||
- Fix status code in GET/HEAD delete marker (#226)
|
- Fix status code in GET/HEAD delete marker (#226)
|
||||||
- Fix `NextVersionIDMarker` in `list-object-versions` (#248)
|
- Fix `NextVersionIDMarker` in `list-object-versions` (#248)
|
||||||
- Fix possibility of panic during SIGHUP (#288)
|
- Fix possibility of panic during SIGHUP (#288)
|
||||||
- Fix flaky `TestErrorTimeoutChecking` (`make test` sometimes failed) (#290)
|
- Fix flaky `TestErrorTimeoutChecking` (`make test` sometimes failed) (#290)
|
||||||
- Fix user owner ID in billing metrics (#321)
|
- Fix log-level change on SIGHUP (#313)
|
||||||
|
- Fix anonymous put request (#311)
|
||||||
|
- Fix routine leak from nns resolver (#324)
|
||||||
|
- Fix svace errors (#325, #328)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Add new `frostfs.buffer_max_size_for_put` config param and sync TZ hash for PUT operations (#197)
|
- Add new `frostfs.buffer_max_size_for_put` config param and sync TZ hash for PUT operations (#197)
|
||||||
|
@ -22,10 +48,10 @@ This document outlines major changes between releases.
|
||||||
- Support per namespace placement policies configuration (see `namespaces.config` config param) (#266)
|
- Support per namespace placement policies configuration (see `namespaces.config` config param) (#266)
|
||||||
- Support control api to manage policies. See `control` config section (#258)
|
- Support control api to manage policies. See `control` config section (#258)
|
||||||
- Add `namespace` label to billing metrics (#271)
|
- Add `namespace` label to billing metrics (#271)
|
||||||
- Support policy-engine (#257)
|
- Support policy-engine (#257, #259, #282, #283, #302, #307, #345, #351, #358, #360, #362, #383, #354)
|
||||||
- Support `policy` contract (#259)
|
|
||||||
- Support `proxy` contract (#287)
|
- Support `proxy` contract (#287)
|
||||||
- Authmate: support custom attributes (#292)
|
- Authmate: support custom attributes (#292)
|
||||||
|
- Add FrostfsID cache (#269)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)
|
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)
|
||||||
|
@ -34,9 +60,23 @@ This document outlines major changes between releases.
|
||||||
- Use tombstone when delete multipart upload (#275)
|
- Use tombstone when delete multipart upload (#275)
|
||||||
- Support new parameter `cache.accessbox.removing_check_interval` (#305)
|
- Support new parameter `cache.accessbox.removing_check_interval` (#305)
|
||||||
- Use APE rules instead of eACL in container creation (#306)
|
- Use APE rules instead of eACL in container creation (#306)
|
||||||
|
- Rework bucket policy with policy-engine (#261)
|
||||||
|
- Improved object listing speed (#165, #347)
|
||||||
|
- Logging improvement (#300, #318)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Drop sending whitespace characters during complete multipart upload and related config param `kludge.complete_multipart_keepalive` (#227)
|
- Drop sending whitespace characters during complete multipart upload and related config param `kludge.complete_multipart_keepalive` (#227)
|
||||||
|
- Unused legacy minio related code (#299)
|
||||||
|
- Redundant output with journald logging (#298)
|
||||||
|
|
||||||
|
## [0.28.2] - 2024-05-27
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `anon` user in billing metrics (#321)
|
||||||
|
- Parts are not removed when multipart object removed (#370)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Put request in duration metrics (#280)
|
||||||
|
|
||||||
## [0.28.1] - 2024-01-24
|
## [0.28.1] - 2024-01-24
|
||||||
|
|
||||||
|
@ -154,4 +194,9 @@ To see CHANGELOG for older versions, refer to https://github.com/nspcc-dev/neofs
|
||||||
[0.27.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/b2148cc3...v0.27.0
|
[0.27.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/b2148cc3...v0.27.0
|
||||||
[0.28.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.27.0...v0.28.0
|
[0.28.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.27.0...v0.28.0
|
||||||
[0.28.1]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.28.0...v0.28.1
|
[0.28.1]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.28.0...v0.28.1
|
||||||
[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.28.1...master
|
[0.28.2]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.28.1...v0.28.2
|
||||||
|
[0.29.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.28.2...v0.29.0
|
||||||
|
[0.29.1]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.0...v0.29.1
|
||||||
|
[0.29.2]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.1...v0.29.2
|
||||||
|
[0.29.3]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.2...v0.29.3
|
||||||
|
[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.3...master
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@
|
||||||
# Common variables
|
# Common variables
|
||||||
REPO ?= $(shell go list -m)
|
REPO ?= $(shell go list -m)
|
||||||
VERSION ?= $(shell git describe --tags --dirty --match "v*" --always --abbrev=8 2>/dev/null || cat VERSION 2>/dev/null || echo "develop")
|
VERSION ?= $(shell git describe --tags --dirty --match "v*" --always --abbrev=8 2>/dev/null || cat VERSION 2>/dev/null || echo "develop")
|
||||||
GO_VERSION ?= 1.20
|
GO_VERSION ?= 1.22
|
||||||
LINT_VERSION ?= 1.56.1
|
LINT_VERSION ?= 1.56.1
|
||||||
TRUECLOUDLAB_LINT_VERSION ?= 0.0.5
|
TRUECLOUDLAB_LINT_VERSION ?= 0.0.5
|
||||||
BINDIR = bin
|
BINDIR = bin
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
v0.28.1
|
v0.29.3
|
41
api/cache/cache_test.go
vendored
41
api/cache/cache_test.go
vendored
|
@ -3,10 +3,13 @@ package cache
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||||
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zaptest/observer"
|
"go.uber.org/zap/zaptest/observer"
|
||||||
|
@ -194,6 +197,44 @@ func TestNotificationConfigurationCacheType(t *testing.T) {
|
||||||
assertInvalidCacheEntry(t, cache.GetNotificationConfiguration(key), observedLog)
|
assertInvalidCacheEntry(t, cache.GetNotificationConfiguration(key), observedLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFrostFSIDSubjectCacheType(t *testing.T) {
|
||||||
|
logger, observedLog := getObservedLogger()
|
||||||
|
cache := NewFrostfsIDCache(DefaultFrostfsIDConfig(logger))
|
||||||
|
|
||||||
|
key, err := util.Uint160DecodeStringLE("4ea976429703418ef00fc4912a409b6a0b973034")
|
||||||
|
require.NoError(t, err)
|
||||||
|
value := &client.SubjectExtended{}
|
||||||
|
|
||||||
|
err = cache.PutSubject(key, value)
|
||||||
|
require.NoError(t, err)
|
||||||
|
val := cache.GetSubject(key)
|
||||||
|
require.Equal(t, value, val)
|
||||||
|
require.Equal(t, 0, observedLog.Len())
|
||||||
|
|
||||||
|
err = cache.cache.Set(key, "tmp")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertInvalidCacheEntry(t, cache.GetSubject(key), observedLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFrostFSIDUserKeyCacheType(t *testing.T) {
|
||||||
|
logger, observedLog := getObservedLogger()
|
||||||
|
cache := NewFrostfsIDCache(DefaultFrostfsIDConfig(logger))
|
||||||
|
|
||||||
|
ns, name := "ns", "name"
|
||||||
|
value, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = cache.PutUserKey(ns, name, value.PublicKey())
|
||||||
|
require.NoError(t, err)
|
||||||
|
val := cache.GetUserKey(ns, name)
|
||||||
|
require.Equal(t, value.PublicKey(), val)
|
||||||
|
require.Equal(t, 0, observedLog.Len())
|
||||||
|
|
||||||
|
err = cache.cache.Set(ns+"/"+name, "tmp")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertInvalidCacheEntry(t, cache.GetUserKey(ns, name), observedLog)
|
||||||
|
}
|
||||||
|
|
||||||
func assertInvalidCacheEntry(t *testing.T, val interface{}, observedLog *observer.ObservedLogs) {
|
func assertInvalidCacheEntry(t *testing.T, val interface{}, observedLog *observer.ObservedLogs) {
|
||||||
require.Nil(t, val)
|
require.Nil(t, val)
|
||||||
require.Equal(t, 1, observedLog.Len())
|
require.Equal(t, 1, observedLog.Len())
|
||||||
|
|
77
api/cache/frostfsid.go
vendored
Normal file
77
api/cache/frostfsid.go
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
"github.com/bluele/gcache"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FrostfsIDCache provides lru cache for frostfsid contract.
|
||||||
|
type FrostfsIDCache struct {
|
||||||
|
cache gcache.Cache
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultFrostfsIDCacheSize is a default maximum number of entries in cache.
|
||||||
|
DefaultFrostfsIDCacheSize = 1e4
|
||||||
|
// DefaultFrostfsIDCacheLifetime is a default lifetime of entries in cache.
|
||||||
|
DefaultFrostfsIDCacheLifetime = time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultFrostfsIDConfig returns new default cache expiration values.
|
||||||
|
func DefaultFrostfsIDConfig(logger *zap.Logger) *Config {
|
||||||
|
return &Config{
|
||||||
|
Size: DefaultFrostfsIDCacheSize,
|
||||||
|
Lifetime: DefaultFrostfsIDCacheLifetime,
|
||||||
|
Logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFrostfsIDCache creates an object of FrostfsIDCache.
|
||||||
|
func NewFrostfsIDCache(config *Config) *FrostfsIDCache {
|
||||||
|
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
|
||||||
|
return &FrostfsIDCache{cache: gc, logger: config.Logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubject returns a cached client.SubjectExtended. Returns nil if value is missing.
|
||||||
|
func (c *FrostfsIDCache) GetSubject(key util.Uint160) *client.SubjectExtended {
|
||||||
|
return get[client.SubjectExtended](c, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutSubject puts a client.SubjectExtended to cache.
|
||||||
|
func (c *FrostfsIDCache) PutSubject(key util.Uint160, subject *client.SubjectExtended) error {
|
||||||
|
return c.cache.Set(key, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserKey returns a cached *keys.PublicKey. Returns nil if value is missing.
|
||||||
|
func (c *FrostfsIDCache) GetUserKey(ns, name string) *keys.PublicKey {
|
||||||
|
return get[keys.PublicKey](c, ns+"/"+name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutUserKey puts a client.SubjectExtended to cache.
|
||||||
|
func (c *FrostfsIDCache) PutUserKey(ns, name string, userKey *keys.PublicKey) error {
|
||||||
|
return c.cache.Set(ns+"/"+name, userKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func get[T any](c *FrostfsIDCache, key any) *T {
|
||||||
|
entry, err := c.cache.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := entry.(*T)
|
||||||
|
if !ok {
|
||||||
|
c.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)),
|
||||||
|
zap.String("expected", fmt.Sprintf("%T", result)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -284,6 +284,32 @@ func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) encodeBucketCannedACL(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) *AccessControlPolicy {
|
func (h *handler) encodeBucketCannedACL(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) *AccessControlPolicy {
|
||||||
|
res := h.encodePrivateCannedACL(ctx, bktInfo, settings)
|
||||||
|
|
||||||
|
switch settings.CannedACL {
|
||||||
|
case basicACLPublic:
|
||||||
|
grantee := NewGrantee(acpGroup)
|
||||||
|
grantee.URI = allUsersGroup
|
||||||
|
|
||||||
|
res.AccessControlList = append(res.AccessControlList, &Grant{
|
||||||
|
Grantee: grantee,
|
||||||
|
Permission: aclWrite,
|
||||||
|
})
|
||||||
|
fallthrough
|
||||||
|
case basicACLReadOnly:
|
||||||
|
grantee := NewGrantee(acpGroup)
|
||||||
|
grantee.URI = allUsersGroup
|
||||||
|
|
||||||
|
res.AccessControlList = append(res.AccessControlList, &Grant{
|
||||||
|
Grantee: grantee,
|
||||||
|
Permission: aclRead,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) encodePrivateCannedACL(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) *AccessControlPolicy {
|
||||||
ownerDisplayName := bktInfo.Owner.EncodeToString()
|
ownerDisplayName := bktInfo.Owner.EncodeToString()
|
||||||
ownerEncodedID := ownerDisplayName
|
ownerEncodedID := ownerDisplayName
|
||||||
|
|
||||||
|
@ -308,26 +334,6 @@ func (h *handler) encodeBucketCannedACL(ctx context.Context, bktInfo *data.Bucke
|
||||||
Permission: aclFullControl,
|
Permission: aclFullControl,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
switch settings.CannedACL {
|
|
||||||
case basicACLPublic:
|
|
||||||
grantee := NewGrantee(acpGroup)
|
|
||||||
grantee.URI = allUsersGroup
|
|
||||||
|
|
||||||
res.AccessControlList = append(res.AccessControlList, &Grant{
|
|
||||||
Grantee: grantee,
|
|
||||||
Permission: aclWrite,
|
|
||||||
})
|
|
||||||
fallthrough
|
|
||||||
case basicACLReadOnly:
|
|
||||||
grantee := NewGrantee(acpGroup)
|
|
||||||
grantee.URI = allUsersGroup
|
|
||||||
|
|
||||||
res.AccessControlList = append(res.AccessControlList, &Grant{
|
|
||||||
Grantee: grantee,
|
|
||||||
Permission: aclRead,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +450,7 @@ func (h *handler) putBucketACLAPEHandler(w http.ResponseWriter, r *http.Request,
|
||||||
}
|
}
|
||||||
|
|
||||||
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
||||||
if err = h.ape.SaveACLChains(reqInfo.Namespace, chainRules); err != nil {
|
if err = h.ape.SaveACLChains(bktInfo.CID.EncodeToString(), chainRules); err != nil {
|
||||||
h.logAndSendError(w, "failed to add morph rule chains", reqInfo, err)
|
h.logAndSendError(w, "failed to add morph rule chains", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -513,19 +519,17 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apeEnabled := bktInfo.APEEnabled
|
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||||
|
if err != nil {
|
||||||
if !apeEnabled {
|
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
return
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
apeEnabled = len(settings.CannedACL) != 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if apeEnabled {
|
if bktInfo.APEEnabled || len(settings.CannedACL) != 0 {
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
if err = middleware.EncodeToResponse(w, h.encodePrivateCannedACL(ctx, bktInfo, settings)); err != nil {
|
||||||
|
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +547,7 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
objInfo, err := h.obj.GetObjectInfo(ctx, prm)
|
objInfo, err := h.obj.GetObjectInfo(ctx, prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not object info", reqInfo, err)
|
h.logAndSendError(w, "could not get object info", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,7 +685,8 @@ func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, getBucketChainID(chain.S3, bktInfo)); err != nil {
|
chainIDs := []chain.ID{getBucketChainID(chain.S3, bktInfo), getBucketChainID(chain.Ingress, bktInfo)}
|
||||||
|
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, chainIDs); err != nil {
|
||||||
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -735,13 +740,6 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeChain, err := engineiam.ConvertToNativeChain(bktPolicy, h.nativeResolver(reqInfo.Namespace, bktInfo))
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not convert s3 policy to native chain policy", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nativeChain.ID = getBucketChainID(chain.Ingress, bktInfo)
|
|
||||||
|
|
||||||
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not convert s3 policy to chain policy", reqInfo, err)
|
h.logAndSendError(w, "could not convert s3 policy to chain policy", reqInfo, err)
|
||||||
|
@ -749,7 +747,22 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
s3Chain.ID = getBucketChainID(chain.S3, bktInfo)
|
s3Chain.ID = getBucketChainID(chain.S3, bktInfo)
|
||||||
|
|
||||||
if err = h.ape.PutBucketPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy, []*chain.Chain{s3Chain, nativeChain}); err != nil {
|
nativeChain, err := engineiam.ConvertToNativeChain(bktPolicy, h.nativeResolver(reqInfo.Namespace, bktInfo))
|
||||||
|
if err == nil {
|
||||||
|
nativeChain.ID = getBucketChainID(chain.Ingress, bktInfo)
|
||||||
|
} else if !stderrors.Is(err, engineiam.ErrActionsNotApplicable) {
|
||||||
|
h.logAndSendError(w, "could not convert s3 policy to native chain policy", reqInfo, err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
h.reqLogger(r.Context()).Warn(logs.PolicyCouldntBeConvertedToNativeRules)
|
||||||
|
}
|
||||||
|
|
||||||
|
chainsToSave := []*chain.Chain{s3Chain}
|
||||||
|
if nativeChain != nil {
|
||||||
|
chainsToSave = append(chainsToSave, nativeChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = h.ape.PutBucketPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy, chainsToSave); err != nil {
|
||||||
h.logAndSendError(w, "failed to update policy in contract", reqInfo, err)
|
h.logAndSendError(w, "failed to update policy in contract", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -1324,60 +1325,110 @@ func TestPutBucketAPE(t *testing.T) {
|
||||||
_, err := hc.tp.ContainerEACL(hc.Context(), layer.PrmContainerEACL{ContainerID: info.BktInfo.CID})
|
_, err := hc.tp.ContainerEACL(hc.Context(), layer.PrmContainerEACL{ContainerID: info.BktInfo.CID})
|
||||||
require.ErrorContains(t, err, "not found")
|
require.ErrorContains(t, err, "not found")
|
||||||
|
|
||||||
chains, err := hc.h.ape.(*apeMock).ListChains(engine.NamespaceTarget(""))
|
chains, err := hc.h.ape.(*apeMock).ListChains(engine.ContainerTarget(info.BktInfo.CID.EncodeToString()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, chains, 2)
|
require.Len(t, chains, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutBucketObjectACLErrorAPE(t *testing.T) {
|
func TestPutObjectACLErrorAPE(t *testing.T) {
|
||||||
hc := prepareHandlerContext(t)
|
hc := prepareHandlerContext(t)
|
||||||
bktName, objName := "bucket-for-acl-ape", "object"
|
bktName, objName := "bucket-for-acl-ape", "object"
|
||||||
|
|
||||||
info := createBucket(hc, bktName)
|
info := createBucket(hc, bktName)
|
||||||
putObject(hc, bktName, objName)
|
|
||||||
|
putObjectWithHeadersAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, s3errors.ErrAccessControlListNotSupported)
|
||||||
|
putObjectWithHeaders(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate}) // only `private` canned acl is allowed, that is actually ignored
|
||||||
|
putObjectWithHeaders(hc, bktName, objName, nil)
|
||||||
|
|
||||||
aclBody := &AccessControlPolicy{}
|
aclBody := &AccessControlPolicy{}
|
||||||
putBucketACLAssertS3Error(hc, bktName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
|
||||||
|
|
||||||
putObjectACLAssertS3Error(hc, bktName, objName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
putObjectACLAssertS3Error(hc, bktName, objName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
||||||
getObjectACLAssertS3Error(hc, bktName, objName, s3errors.ErrAccessControlListNotSupported)
|
|
||||||
|
aclRes := getObjectACL(hc, bktName, objName)
|
||||||
|
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetBucketACLAPE(t *testing.T) {
|
func TestCreateObjectACLErrorAPE(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
bktName, objName, objNameCopy := "bucket-for-acl-ape", "object", "copy"
|
||||||
|
|
||||||
|
createBucket(hc, bktName)
|
||||||
|
|
||||||
|
putObject(hc, bktName, objName)
|
||||||
|
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPublic}}, http.StatusBadRequest)
|
||||||
|
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPrivate}}, http.StatusOK)
|
||||||
|
|
||||||
|
createMultipartUploadAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, s3errors.ErrAccessControlListNotSupported)
|
||||||
|
createMultipartUpload(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutObjectACLBackwardCompatibility(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
hc.config.aclEnabled = true
|
||||||
|
bktName, objName := "bucket-for-acl-ape", "object"
|
||||||
|
|
||||||
|
info := createBucket(hc, bktName)
|
||||||
|
|
||||||
|
putObjectWithHeadersBase(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate}, info.Box, nil)
|
||||||
|
putObjectWithHeadersBase(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, info.Box, nil)
|
||||||
|
|
||||||
|
aclRes := getObjectACL(hc, bktName, objName)
|
||||||
|
xmlName := xml.Name{
|
||||||
|
Space: "http://s3.amazonaws.com/doc/2006-03-01/",
|
||||||
|
Local: "Grantee",
|
||||||
|
}
|
||||||
|
require.ElementsMatch(t, aclRes.AccessControlList, []*Grant{
|
||||||
|
{
|
||||||
|
Grantee: &Grantee{XMLName: xmlName, ID: hex.EncodeToString(info.Key.PublicKey().Bytes())},
|
||||||
|
Permission: aclFullControl,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Grantee: &Grantee{XMLName: xmlName, URI: allUsersGroup},
|
||||||
|
Permission: aclFullControl,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
aclBody := &AccessControlPolicy{}
|
||||||
|
putObjectACLBase(hc, bktName, objName, info.Box, nil, aclBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBucketACLAPE(t *testing.T) {
|
||||||
hc := prepareHandlerContext(t)
|
hc := prepareHandlerContext(t)
|
||||||
bktName := "bucket-for-acl-ape"
|
bktName := "bucket-for-acl-ape"
|
||||||
|
|
||||||
info := createBucket(hc, bktName)
|
info := createBucket(hc, bktName)
|
||||||
|
|
||||||
|
aclBody := &AccessControlPolicy{}
|
||||||
|
putBucketACLAssertS3Error(hc, bktName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
||||||
|
|
||||||
aclRes := getBucketACL(hc, bktName)
|
aclRes := getBucketACL(hc, bktName)
|
||||||
checkPrivateBucketACL(t, aclRes, info.Key.PublicKey())
|
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
||||||
|
|
||||||
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPrivate})
|
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPrivate})
|
||||||
aclRes = getBucketACL(hc, bktName)
|
aclRes = getBucketACL(hc, bktName)
|
||||||
checkPrivateBucketACL(t, aclRes, info.Key.PublicKey())
|
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
||||||
|
|
||||||
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLReadOnly})
|
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLReadOnly})
|
||||||
aclRes = getBucketACL(hc, bktName)
|
aclRes = getBucketACL(hc, bktName)
|
||||||
checkPublicReadBucketACL(t, aclRes, info.Key.PublicKey())
|
checkPublicReadACL(t, aclRes, info.Key.PublicKey())
|
||||||
|
|
||||||
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPublic})
|
putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPublic})
|
||||||
aclRes = getBucketACL(hc, bktName)
|
aclRes = getBucketACL(hc, bktName)
|
||||||
checkPublicReadWriteBucketACL(t, aclRes, info.Key.PublicKey())
|
checkPublicReadWriteACL(t, aclRes, info.Key.PublicKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPrivateBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
func checkPrivateACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
||||||
checkBucketACLOwner(t, aclRes, ownerKey, 1)
|
checkACLOwner(t, aclRes, ownerKey, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPublicReadBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
func checkPublicReadACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
||||||
checkBucketACLOwner(t, aclRes, ownerKey, 2)
|
checkACLOwner(t, aclRes, ownerKey, 2)
|
||||||
|
|
||||||
require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI)
|
require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI)
|
||||||
require.Equal(t, aclRead, aclRes.AccessControlList[1].Permission)
|
require.Equal(t, aclRead, aclRes.AccessControlList[1].Permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPublicReadWriteBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
func checkPublicReadWriteACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) {
|
||||||
checkBucketACLOwner(t, aclRes, ownerKey, 3)
|
checkACLOwner(t, aclRes, ownerKey, 3)
|
||||||
|
|
||||||
require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI)
|
require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI)
|
||||||
require.Equal(t, aclWrite, aclRes.AccessControlList[1].Permission)
|
require.Equal(t, aclWrite, aclRes.AccessControlList[1].Permission)
|
||||||
|
@ -1386,7 +1437,7 @@ func checkPublicReadWriteBucketACL(t *testing.T, aclRes *AccessControlPolicy, ow
|
||||||
require.Equal(t, aclRead, aclRes.AccessControlList[2].Permission)
|
require.Equal(t, aclRead, aclRes.AccessControlList[2].Permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkBucketACLOwner(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey, ln int) {
|
func checkACLOwner(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey, ln int) {
|
||||||
ownerIDStr := hex.EncodeToString(ownerKey.Bytes())
|
ownerIDStr := hex.EncodeToString(ownerKey.Bytes())
|
||||||
ownerNameStr := ownerKey.Address()
|
ownerNameStr := ownerKey.Address()
|
||||||
|
|
||||||
|
@ -1409,6 +1460,7 @@ func TestBucketPolicy(t *testing.T) {
|
||||||
getBucketPolicy(hc, bktName, s3errors.ErrNoSuchBucketPolicy)
|
getBucketPolicy(hc, bktName, s3errors.ErrNoSuchBucketPolicy)
|
||||||
|
|
||||||
newPolicy := engineiam.Policy{
|
newPolicy := engineiam.Policy{
|
||||||
|
Version: "2012-10-17",
|
||||||
Statement: []engineiam.Statement{{
|
Statement: []engineiam.Statement{{
|
||||||
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||||
Effect: engineiam.DenyEffect,
|
Effect: engineiam.DenyEffect,
|
||||||
|
@ -1426,6 +1478,35 @@ func TestBucketPolicy(t *testing.T) {
|
||||||
require.Equal(t, newPolicy, bktPolicy)
|
require.Equal(t, newPolicy, bktPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteBucketWithPolicy(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
bktName := "bucket-for-policy"
|
||||||
|
bi := createTestBucket(hc, bktName)
|
||||||
|
|
||||||
|
newPolicy := engineiam.Policy{
|
||||||
|
Version: "2012-10-17",
|
||||||
|
Statement: []engineiam.Statement{{
|
||||||
|
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||||
|
Effect: engineiam.AllowEffect,
|
||||||
|
Action: engineiam.Action{"s3:PutObject"},
|
||||||
|
Resource: engineiam.Resource{"arn:aws:s3:::bucket-for-policy/*"},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
putBucketPolicy(hc, bktName, newPolicy)
|
||||||
|
|
||||||
|
require.Len(t, hc.h.ape.(*apeMock).policyMap, 1)
|
||||||
|
require.Len(t, hc.h.ape.(*apeMock).chainMap[engine.ContainerTarget(bi.CID.EncodeToString())], 4)
|
||||||
|
|
||||||
|
deleteBucket(t, hc, bktName, http.StatusNoContent)
|
||||||
|
|
||||||
|
require.Empty(t, hc.h.ape.(*apeMock).policyMap)
|
||||||
|
chains, err := hc.h.ape.(*apeMock).ListChains(engine.ContainerTarget(bi.CID.EncodeToString()))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, chains)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBucketPolicyUnmarshal(t *testing.T) {
|
func TestBucketPolicyUnmarshal(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -1661,9 +1742,12 @@ func putObjectACLBase(hc *handlerContext, bktName, objName string, box *accessbo
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectACLAssertS3Error(hc *handlerContext, bktName, objName string, code s3errors.ErrorCode) {
|
func getObjectACL(hc *handlerContext, bktName, objName string) *AccessControlPolicy {
|
||||||
w := getObjectACLBase(hc, bktName, objName)
|
w := getObjectACLBase(hc, bktName, objName)
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
|
res := &AccessControlPolicy{}
|
||||||
|
parseTestResponse(hc.t, w, res)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectACLBase(hc *handlerContext, bktName, objName string) *httptest.ResponseRecorder {
|
func getObjectACLBase(hc *handlerContext, bktName, objName string) *httptest.ResponseRecorder {
|
||||||
|
@ -1671,3 +1755,29 @@ func getObjectACLBase(hc *handlerContext, bktName, objName string) *httptest.Res
|
||||||
hc.Handler().GetObjectACLHandler(w, r)
|
hc.Handler().GetObjectACLHandler(w, r)
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func putObjectWithHeaders(hc *handlerContext, bktName, objName string, headers map[string]string) http.Header {
|
||||||
|
w := putObjectWithHeadersBase(hc, bktName, objName, headers, nil, nil)
|
||||||
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
|
return w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func putObjectWithHeadersAssertS3Error(hc *handlerContext, bktName, objName string, headers map[string]string, code s3errors.ErrorCode) {
|
||||||
|
w := putObjectWithHeadersBase(hc, bktName, objName, headers, nil, nil)
|
||||||
|
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
func putObjectWithHeadersBase(hc *handlerContext, bktName, objName string, headers map[string]string, box *accessbox.Box, data []byte) *httptest.ResponseRecorder {
|
||||||
|
body := bytes.NewReader(data)
|
||||||
|
w, r := prepareTestPayloadRequest(hc, bktName, objName, body)
|
||||||
|
|
||||||
|
for k, v := range headers {
|
||||||
|
r.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := middleware.SetBoxData(r.Context(), box)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
hc.Handler().PutObjectHandler(w, r)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ type (
|
||||||
BypassContentEncodingInChunks() bool
|
BypassContentEncodingInChunks() bool
|
||||||
MD5Enabled() bool
|
MD5Enabled() bool
|
||||||
ACLEnabled() bool
|
ACLEnabled() bool
|
||||||
|
RetryMaxAttempts() int
|
||||||
|
RetryMaxBackoff() time.Duration
|
||||||
|
RetryStrategy() RetryStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
FrostFSID interface {
|
FrostFSID interface {
|
||||||
|
@ -57,12 +60,19 @@ type (
|
||||||
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
||||||
APE interface {
|
APE interface {
|
||||||
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error
|
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error
|
||||||
DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error
|
DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error
|
||||||
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
|
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
|
||||||
SaveACLChains(ns string, chains []*chain.Chain) error
|
SaveACLChains(cid string, chains []*chain.Chain) error
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RetryStrategy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RetryStrategyExponential = "exponential"
|
||||||
|
RetryStrategyConstant = "constant"
|
||||||
|
)
|
||||||
|
|
||||||
var _ api.Handler = (*handler)(nil)
|
var _ api.Handler = (*handler)(nil)
|
||||||
|
|
||||||
// New creates new api.Handler using given logger and client.
|
// New creates new api.Handler using given logger and client.
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx = r.Context()
|
ctx = r.Context()
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
|
|
||||||
containsACL = containsACLHeaders(r)
|
cannedACLStatus = aclHeadersStatus(r)
|
||||||
)
|
)
|
||||||
|
|
||||||
src := r.Header.Get(api.AmzCopySource)
|
src := r.Header.Get(api.AmzCopySource)
|
||||||
|
@ -93,7 +93,14 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
apeEnabled := dstBktInfo.APEEnabled || settings.CannedACL != ""
|
||||||
|
if apeEnabled && cannedACLStatus == aclStatusYes {
|
||||||
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
||||||
|
if needUpdateEACLTable {
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -232,7 +239,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
if needUpdateEACLTable {
|
||||||
newEaclTable, err := h.getNewEAclTable(r, dstBktInfo, dstObjInfo)
|
newEaclTable, err := h.getNewEAclTable(r, dstBktInfo, dstObjInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
||||||
|
|
|
@ -22,6 +22,7 @@ type CopyMeta struct {
|
||||||
Tags map[string]string
|
Tags map[string]string
|
||||||
MetadataDirective string
|
MetadataDirective string
|
||||||
Metadata map[string]string
|
Metadata map[string]string
|
||||||
|
Headers map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCopyWithTaggingDirective(t *testing.T) {
|
func TestCopyWithTaggingDirective(t *testing.T) {
|
||||||
|
@ -279,6 +280,10 @@ func copyObject(hc *handlerContext, bktName, fromObject, toObject string, copyMe
|
||||||
}
|
}
|
||||||
r.Header.Set(api.AmzTagging, tagsQuery.Encode())
|
r.Header.Set(api.AmzTagging, tagsQuery.Encode())
|
||||||
|
|
||||||
|
for key, val := range copyMeta.Headers {
|
||||||
|
r.Header.Set(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
hc.Handler().CopyObjectHandler(w, r)
|
hc.Handler().CopyObjectHandler(w, r)
|
||||||
assertStatus(hc.t, w, statusCode)
|
assertStatus(hc.t, w, statusCode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,10 @@ func (h *handler) PutBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) DeleteBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) DeleteBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -184,8 +187,8 @@ func (h *handler) Preflight(w http.ResponseWriter, r *http.Request) {
|
||||||
if !checkSubslice(rule.AllowedHeaders, headers) {
|
if !checkSubslice(rule.AllowedHeaders, headers) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
w.Header().Set(api.AccessControlAllowOrigin, o)
|
w.Header().Set(api.AccessControlAllowOrigin, origin)
|
||||||
w.Header().Set(api.AccessControlAllowMethods, strings.Join(rule.AllowedMethods, ", "))
|
w.Header().Set(api.AccessControlAllowMethods, method)
|
||||||
if headers != nil {
|
if headers != nil {
|
||||||
w.Header().Set(api.AccessControlAllowHeaders, requestHeaders)
|
w.Header().Set(api.AccessControlAllowHeaders, requestHeaders)
|
||||||
}
|
}
|
||||||
|
@ -200,7 +203,10 @@ func (h *handler) Preflight(w http.ResponseWriter, r *http.Request) {
|
||||||
if o != wildcard {
|
if o != wildcard {
|
||||||
w.Header().Set(api.AccessControlAllowCredentials, "true")
|
w.Header().Set(api.AccessControlAllowCredentials, "true")
|
||||||
}
|
}
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCORSOriginWildcard(t *testing.T) {
|
func TestCORSOriginWildcard(t *testing.T) {
|
||||||
|
@ -39,3 +40,181 @@ func TestCORSOriginWildcard(t *testing.T) {
|
||||||
hc.Handler().GetBucketCorsHandler(w, r)
|
hc.Handler().GetBucketCorsHandler(w, r)
|
||||||
assertStatus(t, w, http.StatusOK)
|
assertStatus(t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreflight(t *testing.T) {
|
||||||
|
body := `
|
||||||
|
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||||
|
<CORSRule>
|
||||||
|
<AllowedMethod>GET</AllowedMethod>
|
||||||
|
<AllowedOrigin>http://www.example.com</AllowedOrigin>
|
||||||
|
<AllowedHeader>Authorization</AllowedHeader>
|
||||||
|
<ExposeHeader>x-amz-*</ExposeHeader>
|
||||||
|
<ExposeHeader>X-Amz-*</ExposeHeader>
|
||||||
|
<MaxAgeSeconds>600</MaxAgeSeconds>
|
||||||
|
</CORSRule>
|
||||||
|
</CORSConfiguration>
|
||||||
|
`
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
bktName := "bucket-preflight-test"
|
||||||
|
box, _ := createAccessBox(t)
|
||||||
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
|
ctx := middleware.SetBoxData(r.Context(), box)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
hc.Handler().CreateBucketHandler(w, r)
|
||||||
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
|
w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
|
||||||
|
ctx = middleware.SetBoxData(r.Context(), box)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
hc.Handler().PutBucketCorsHandler(w, r)
|
||||||
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
origin string
|
||||||
|
method string
|
||||||
|
headers string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
method: "GET",
|
||||||
|
headers: "Authorization",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty origin",
|
||||||
|
method: "GET",
|
||||||
|
headers: "Authorization",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty request method",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
headers: "Authorization",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Not allowed method",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
method: "PUT",
|
||||||
|
headers: "Authorization",
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Not allowed headers",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
method: "GET",
|
||||||
|
headers: "Authorization, Last-Modified",
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
w, r = prepareTestPayloadRequest(hc, bktName, "", nil)
|
||||||
|
r.Header.Set(api.Origin, tc.origin)
|
||||||
|
r.Header.Set(api.AccessControlRequestMethod, tc.method)
|
||||||
|
r.Header.Set(api.AccessControlRequestHeaders, tc.headers)
|
||||||
|
hc.Handler().Preflight(w, r)
|
||||||
|
assertStatus(t, w, tc.expectedStatus)
|
||||||
|
|
||||||
|
if tc.expectedStatus == http.StatusOK {
|
||||||
|
require.Equal(t, tc.origin, w.Header().Get(api.AccessControlAllowOrigin))
|
||||||
|
require.Equal(t, tc.method, w.Header().Get(api.AccessControlAllowMethods))
|
||||||
|
require.Equal(t, tc.headers, w.Header().Get(api.AccessControlAllowHeaders))
|
||||||
|
require.Equal(t, "x-amz-*, X-Amz-*", w.Header().Get(api.AccessControlExposeHeaders))
|
||||||
|
require.Equal(t, "true", w.Header().Get(api.AccessControlAllowCredentials))
|
||||||
|
require.Equal(t, "600", w.Header().Get(api.AccessControlMaxAge))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreflightWildcardOrigin(t *testing.T) {
|
||||||
|
body := `
|
||||||
|
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||||
|
<CORSRule>
|
||||||
|
<AllowedMethod>GET</AllowedMethod>
|
||||||
|
<AllowedMethod>PUT</AllowedMethod>
|
||||||
|
<AllowedOrigin>*</AllowedOrigin>
|
||||||
|
<AllowedHeader>*</AllowedHeader>
|
||||||
|
</CORSRule>
|
||||||
|
</CORSConfiguration>
|
||||||
|
`
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
bktName := "bucket-preflight-wildcard-test"
|
||||||
|
box, _ := createAccessBox(t)
|
||||||
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
|
ctx := middleware.SetBoxData(r.Context(), box)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
hc.Handler().CreateBucketHandler(w, r)
|
||||||
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
|
w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
|
||||||
|
ctx = middleware.SetBoxData(r.Context(), box)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
hc.Handler().PutBucketCorsHandler(w, r)
|
||||||
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
origin string
|
||||||
|
method string
|
||||||
|
headers string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid get",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
method: "GET",
|
||||||
|
headers: "Authorization, Last-Modified",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid put",
|
||||||
|
origin: "http://example.com",
|
||||||
|
method: "PUT",
|
||||||
|
headers: "Authorization, Content-Type",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty origin",
|
||||||
|
method: "GET",
|
||||||
|
headers: "Authorization, Last-Modified",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty request method",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
headers: "Authorization, Last-Modified",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Not allowed method",
|
||||||
|
origin: "http://www.example.com",
|
||||||
|
method: "DELETE",
|
||||||
|
headers: "Authorization, Last-Modified",
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
w, r = prepareTestPayloadRequest(hc, bktName, "", nil)
|
||||||
|
r.Header.Set(api.Origin, tc.origin)
|
||||||
|
r.Header.Set(api.AccessControlRequestMethod, tc.method)
|
||||||
|
r.Header.Set(api.AccessControlRequestHeaders, tc.headers)
|
||||||
|
hc.Handler().Preflight(w, r)
|
||||||
|
assertStatus(t, w, tc.expectedStatus)
|
||||||
|
|
||||||
|
if tc.expectedStatus == http.StatusOK {
|
||||||
|
require.Equal(t, tc.origin, w.Header().Get(api.AccessControlAllowOrigin))
|
||||||
|
require.Equal(t, tc.method, w.Header().Get(api.AccessControlAllowMethods))
|
||||||
|
require.Equal(t, tc.headers, w.Header().Get(api.AccessControlAllowHeaders))
|
||||||
|
require.Empty(t, w.Header().Get(api.AccessControlExposeHeaders))
|
||||||
|
require.Empty(t, w.Header().Get(api.AccessControlAllowCredentials))
|
||||||
|
require.Equal(t, "0", w.Header().Get(api.AccessControlMaxAge))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -276,6 +277,19 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
SessionToken: sessionToken,
|
SessionToken: sessionToken,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
h.logAndSendError(w, "couldn't delete bucket", reqInfo, err)
|
h.logAndSendError(w, "couldn't delete bucket", reqInfo, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chainIDs := []chain.ID{
|
||||||
|
getBucketChainID(chain.S3, bktInfo),
|
||||||
|
getBucketChainID(chain.Ingress, bktInfo),
|
||||||
|
getBucketCannedChainID(chain.S3, bktInfo.CID),
|
||||||
|
getBucketCannedChainID(chain.Ingress, bktInfo.CID),
|
||||||
|
}
|
||||||
|
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, chainIDs); err != nil {
|
||||||
|
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,6 +346,23 @@ func TestDeleteObjectSuspended(t *testing.T) {
|
||||||
require.False(t, existInMockedFrostFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
require.False(t, existInMockedFrostFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteObjectSuspendedNull(t *testing.T) {
|
||||||
|
tc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
||||||
|
bktInfo, objInfo := createBucketAndObject(tc, bktName, objName)
|
||||||
|
|
||||||
|
putBucketVersioning(t, tc, bktName, true)
|
||||||
|
putObject(tc, bktName, objName)
|
||||||
|
|
||||||
|
putBucketVersioning(t, tc, bktName, false)
|
||||||
|
|
||||||
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
||||||
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
||||||
|
|
||||||
|
require.False(t, existInMockedFrostFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeleteMarkers(t *testing.T) {
|
func TestDeleteMarkers(t *testing.T) {
|
||||||
tc := prepareHandlerContext(t)
|
tc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
@ -458,6 +475,16 @@ func putBucketVersioning(t *testing.T, tc *handlerContext, bktName string, enabl
|
||||||
assertStatus(t, w, http.StatusOK)
|
assertStatus(t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getBucketVersioning(hc *handlerContext, bktName string) *VersioningConfiguration {
|
||||||
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
|
hc.Handler().GetBucketVersioningHandler(w, r)
|
||||||
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
|
|
||||||
|
res := &VersioningConfiguration{}
|
||||||
|
parseTestResponse(hc.t, w, res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func deleteObject(t *testing.T, tc *handlerContext, bktName, objName, version string) (string, bool) {
|
func deleteObject(t *testing.T, tc *handlerContext, bktName, objName, version string) (string, bool) {
|
||||||
query := make(url.Values)
|
query := make(url.Values)
|
||||||
query.Add(api.QueryVersionID, version)
|
query.Add(api.QueryVersionID, version)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -234,24 +235,33 @@ func multipartUpload(hc *handlerContext, bktName, objName string, headers map[st
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMultipartUploadEncrypted(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
|
func createMultipartUploadEncrypted(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
|
||||||
return createMultipartUploadBase(hc, bktName, objName, true, headers)
|
return createMultipartUploadOkBase(hc, bktName, objName, true, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMultipartUpload(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
|
func createMultipartUpload(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
|
||||||
return createMultipartUploadBase(hc, bktName, objName, false, headers)
|
return createMultipartUploadOkBase(hc, bktName, objName, false, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMultipartUploadBase(hc *handlerContext, bktName, objName string, encrypted bool, headers map[string]string) *InitiateMultipartUploadResponse {
|
func createMultipartUploadOkBase(hc *handlerContext, bktName, objName string, encrypted bool, headers map[string]string) *InitiateMultipartUploadResponse {
|
||||||
|
w := createMultipartUploadBase(hc, bktName, objName, encrypted, headers)
|
||||||
|
multipartInitInfo := &InitiateMultipartUploadResponse{}
|
||||||
|
readResponse(hc.t, w, http.StatusOK, multipartInitInfo)
|
||||||
|
return multipartInitInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMultipartUploadAssertS3Error(hc *handlerContext, bktName, objName string, headers map[string]string, code errors.ErrorCode) {
|
||||||
|
w := createMultipartUploadBase(hc, bktName, objName, false, headers)
|
||||||
|
assertS3Error(hc.t, w, errors.GetAPIError(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMultipartUploadBase(hc *handlerContext, bktName, objName string, encrypted bool, headers map[string]string) *httptest.ResponseRecorder {
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
||||||
if encrypted {
|
if encrypted {
|
||||||
setEncryptHeaders(r)
|
setEncryptHeaders(r)
|
||||||
}
|
}
|
||||||
setHeaders(r, headers)
|
setHeaders(r, headers)
|
||||||
hc.Handler().CreateMultipartUploadHandler(w, r)
|
hc.Handler().CreateMultipartUploadHandler(w, r)
|
||||||
multipartInitInfo := &InitiateMultipartUploadResponse{}
|
return w
|
||||||
readResponse(hc.t, w, http.StatusOK, multipartInitInfo)
|
|
||||||
|
|
||||||
return multipartInitInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func completeMultipartUpload(hc *handlerContext, bktName, objName, uploadID string, partsETags []string) {
|
func completeMultipartUpload(hc *handlerContext, bktName, objName, uploadID string, partsETags []string) {
|
||||||
|
|
|
@ -130,6 +130,18 @@ func (c *configMock) ResolveNamespaceAlias(ns string) string {
|
||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configMock) RetryMaxAttempts() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *configMock) RetryMaxBackoff() time.Duration {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *configMock) RetryStrategy() RetryStrategy {
|
||||||
|
return RetryStrategyConstant
|
||||||
|
}
|
||||||
|
|
||||||
func prepareHandlerContext(t *testing.T) *handlerContext {
|
func prepareHandlerContext(t *testing.T) *handlerContext {
|
||||||
return prepareHandlerContextBase(t, layer.DefaultCachesConfigs(zap.NewExample()))
|
return prepareHandlerContextBase(t, layer.DefaultCachesConfigs(zap.NewExample()))
|
||||||
}
|
}
|
||||||
|
@ -267,7 +279,7 @@ func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chain
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range chain {
|
for i := range chain {
|
||||||
if err := a.AddChain(engine.NamespaceTarget(ns), chain[i]); err != nil {
|
if err := a.AddChain(engine.ContainerTarget(cnrID.EncodeToString()), chain[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,11 +287,17 @@ func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chain
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error {
|
||||||
if err := a.DeletePolicy(ns, cnrID); err != nil {
|
if err := a.DeletePolicy(ns, cnrID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return a.RemoveChain(engine.NamespaceTarget(ns), chainID)
|
for i := range chainIDs {
|
||||||
|
if err := a.RemoveChain(engine.ContainerTarget(cnrID.EncodeToString()), chainIDs[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
func (a *apeMock) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
@ -291,9 +309,9 @@ func (a *apeMock) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) SaveACLChains(ns string, chains []*chain.Chain) error {
|
func (a *apeMock) SaveACLChains(cid string, chains []*chain.Chain) error {
|
||||||
for i := range chains {
|
for i := range chains {
|
||||||
if err := a.AddChain(engine.NamespaceTarget(ns), chains[i]); err != nil {
|
if err := a.AddChain(engine.ContainerTarget(cid), chains[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,10 @@ func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set(api.ContainerZone, bktInfo.Zone)
|
w.Header().Set(api.ContainerZone, bktInfo.Zone)
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.WriteResponse(w, http.StatusOK, nil, middleware.MimeNone)
|
if err = middleware.WriteResponse(w, http.StatusOK, nil, middleware.MimeNone); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) setLockingHeaders(bktInfo *data.BucketInfo, lockInfo data.LockInfo, header http.Header) error {
|
func (h *handler) setLockingHeaders(bktInfo *data.BucketInfo, lockInfo data.LockInfo, header http.Header) error {
|
||||||
|
|
|
@ -103,6 +103,9 @@ const (
|
||||||
|
|
||||||
func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := middleware.GetReqInfo(r.Context())
|
reqInfo := middleware.GetReqInfo(r.Context())
|
||||||
|
uploadID := uuid.New()
|
||||||
|
cannedACLStatus := aclHeadersStatus(r)
|
||||||
|
additional := []zap.Field{zap.String("uploadID", uploadID.String())}
|
||||||
|
|
||||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,8 +113,17 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadID := uuid.New()
|
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||||
additional := []zap.Field{zap.String("uploadID", uploadID.String())}
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
||||||
|
if apeEnabled && cannedACLStatus == aclStatusYes {
|
||||||
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
p := &layer.CreateMultipartParams{
|
p := &layer.CreateMultipartParams{
|
||||||
Info: &layer.UploadInfoParams{
|
Info: &layer.UploadInfoParams{
|
||||||
|
@ -122,7 +134,8 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
Data: &layer.UploadData{},
|
Data: &layer.UploadData{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACLHeaders(r) {
|
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
||||||
|
if needUpdateEACLTable {
|
||||||
key, err := h.bearerTokenIssuerKey(r.Context())
|
key, err := h.bearerTokenIssuerKey(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "couldn't get gate key", reqInfo, err, additional...)
|
h.logAndSendError(w, "couldn't get gate key", reqInfo, err, additional...)
|
||||||
|
@ -266,7 +279,10 @@ func (h *handler) UploadPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(api.ETag, data.Quote(hash))
|
w.Header().Set(api.ETag, data.Quote(hash))
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -38,6 +38,49 @@ func TestMultipartUploadInvalidPart(t *testing.T) {
|
||||||
assertS3Error(hc.t, w, s3Errors.GetAPIError(s3Errors.ErrEntityTooSmall))
|
assertS3Error(hc.t, w, s3Errors.GetAPIError(s3Errors.ErrEntityTooSmall))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteMultipartAllParts(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
partSize := layer.UploadMinSize
|
||||||
|
objLen := 6 * partSize
|
||||||
|
|
||||||
|
bktName, bktName2, objName := "bucket", "bucket2", "object"
|
||||||
|
|
||||||
|
// unversioned bucket
|
||||||
|
createTestBucket(hc, bktName)
|
||||||
|
multipartUpload(hc, bktName, objName, nil, objLen, partSize)
|
||||||
|
deleteObject(t, hc, bktName, objName, emptyVersion)
|
||||||
|
require.Empty(t, hc.tp.Objects())
|
||||||
|
|
||||||
|
// encrypted multipart
|
||||||
|
multipartUploadEncrypted(hc, bktName, objName, nil, objLen, partSize)
|
||||||
|
deleteObject(t, hc, bktName, objName, emptyVersion)
|
||||||
|
require.Empty(t, hc.tp.Objects())
|
||||||
|
|
||||||
|
// versions bucket
|
||||||
|
createTestBucket(hc, bktName2)
|
||||||
|
putBucketVersioning(t, hc, bktName2, true)
|
||||||
|
multipartUpload(hc, bktName2, objName, nil, objLen, partSize)
|
||||||
|
_, hdr := getObject(hc, bktName2, objName)
|
||||||
|
versionID := hdr.Get("X-Amz-Version-Id")
|
||||||
|
deleteObject(t, hc, bktName2, objName, emptyVersion)
|
||||||
|
deleteObject(t, hc, bktName2, objName, versionID)
|
||||||
|
require.Empty(t, hc.tp.Objects())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSpecialMultipartName(t *testing.T) {
|
||||||
|
hc := prepareHandlerContextWithMinCache(t)
|
||||||
|
|
||||||
|
bktName, objName := "bucket", "bucket-settings"
|
||||||
|
|
||||||
|
createTestBucket(hc, bktName)
|
||||||
|
putBucketVersioning(t, hc, bktName, true)
|
||||||
|
|
||||||
|
createMultipartUpload(hc, bktName, objName, nil)
|
||||||
|
res := getBucketVersioning(hc, bktName)
|
||||||
|
require.Equal(t, enabledValue, res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMultipartReUploadPart(t *testing.T) {
|
func TestMultipartReUploadPart(t *testing.T) {
|
||||||
hc := prepareHandlerContext(t)
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
|
|
@ -94,11 +94,11 @@ func TestListObjectsWithOldTreeNodes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAllTreeObjectsOld(hc *handlerContext, bktInfo *data.BucketInfo) {
|
func makeAllTreeObjectsOld(hc *handlerContext, bktInfo *data.BucketInfo) {
|
||||||
nodes, err := hc.treeMock.GetSubTree(hc.Context(), bktInfo, "version", 0, 0)
|
nodes, err := hc.treeMock.GetSubTree(hc.Context(), bktInfo, "version", []uint64{0}, 0)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
|
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if node.GetNodeID() == 0 {
|
if node.GetNodeID()[0] == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
meta := make(map[string]string, len(node.GetMeta()))
|
meta := make(map[string]string, len(node.GetMeta()))
|
||||||
|
@ -108,7 +108,7 @@ func makeAllTreeObjectsOld(hc *handlerContext, bktInfo *data.BucketInfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hc.treeMock.MoveNode(hc.Context(), bktInfo, "version", node.GetNodeID(), node.GetParentID(), meta)
|
err = hc.treeMock.MoveNode(hc.Context(), bktInfo, "version", node.GetNodeID()[0], node.GetParentID()[0], meta)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,16 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/retryer"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
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/eacl"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws/retry"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -186,12 +190,31 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
err error
|
err error
|
||||||
newEaclTable *eacl.Table
|
newEaclTable *eacl.Table
|
||||||
sessionTokenEACL *session.Container
|
sessionTokenEACL *session.Container
|
||||||
containsACL = containsACLHeaders(r)
|
cannedACLStatus = aclHeadersStatus(r)
|
||||||
ctx = r.Context()
|
ctx = r.Context()
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
)
|
)
|
||||||
|
|
||||||
if containsACL {
|
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings, err := h.obj.GetBucketSettings(ctx, bktInfo)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not get bucket settings", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
||||||
|
if apeEnabled && cannedACLStatus == aclStatusYes {
|
||||||
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
||||||
|
if needUpdateEACLTable {
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(r.Context()); err != nil {
|
if sessionTokenEACL, err = getSessionTokenSetEACL(r.Context()); err != nil {
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -204,12 +227,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata := parseMetadata(r)
|
metadata := parseMetadata(r)
|
||||||
if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
||||||
metadata[api.ContentType] = contentType
|
metadata[api.ContentType] = contentType
|
||||||
|
@ -261,12 +278,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := h.obj.GetBucketSettings(ctx, bktInfo)
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not get bucket settings", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
params.Lock, err = formObjectLock(ctx, bktInfo, settings.LockConfiguration, r.Header)
|
params.Lock, err = formObjectLock(ctx, bktInfo, settings.LockConfiguration, r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not form object lock", reqInfo, err)
|
h.logAndSendError(w, "could not form object lock", reqInfo, err)
|
||||||
|
@ -292,7 +303,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
h.reqLogger(ctx).Error(logs.CouldntSendNotification, zap.Error(err))
|
h.reqLogger(ctx).Error(logs.CouldntSendNotification, zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
if needUpdateEACLTable {
|
||||||
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -337,7 +348,10 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
w.Header().Set(api.ETag, data.Quote(objInfo.ETag(h.cfg.MD5Enabled())))
|
w.Header().Set(api.ETag, data.Quote(objInfo.ETag(h.cfg.MD5Enabled())))
|
||||||
|
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) getBodyReader(r *http.Request) (io.ReadCloser, error) {
|
func (h *handler) getBodyReader(r *http.Request) (io.ReadCloser, error) {
|
||||||
|
@ -462,7 +476,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx = r.Context()
|
ctx = r.Context()
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
metadata = make(map[string]string)
|
metadata = make(map[string]string)
|
||||||
containsACL = containsACLHeaders(r)
|
cannedACLStatus = aclHeadersStatus(r)
|
||||||
)
|
)
|
||||||
|
|
||||||
policy, err := checkPostPolicy(r, reqInfo, metadata)
|
policy, err := checkPostPolicy(r, reqInfo, metadata)
|
||||||
|
@ -480,7 +494,26 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings, err := h.obj.GetBucketSettings(ctx, bktInfo)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not get bucket settings", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apeEnabled := bktInfo.APEEnabled || settings.CannedACL != ""
|
||||||
|
if apeEnabled && cannedACLStatus == aclStatusYes {
|
||||||
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
needUpdateEACLTable := !(apeEnabled || cannedACLStatus == aclStatusNo)
|
||||||
|
if needUpdateEACLTable {
|
||||||
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
if sessionTokenEACL, err = getSessionTokenSetEACL(ctx); err != nil {
|
||||||
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
h.logAndSendError(w, "could not get eacl session token from a box", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -507,12 +540,6 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bktInfo, err := h.obj.GetBucketInfo(ctx, reqInfo.BucketName)
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
params := &layer.PutObjectParams{
|
params := &layer.PutObjectParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
Object: reqInfo.ObjectName,
|
Object: reqInfo.ObjectName,
|
||||||
|
@ -579,9 +606,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings, err := h.obj.GetBucketSettings(ctx, bktInfo); err != nil {
|
if settings.VersioningEnabled() {
|
||||||
h.reqLogger(ctx).Warn(logs.CouldntGetBucketVersioning, zap.String("bucket name", reqInfo.BucketName), zap.Error(err))
|
|
||||||
} else if settings.VersioningEnabled() {
|
|
||||||
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +627,11 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
ETag: data.Quote(objInfo.ETag(h.cfg.MD5Enabled())),
|
ETag: data.Quote(objInfo.ETag(h.cfg.MD5Enabled())),
|
||||||
}
|
}
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
if _, err = w.Write(middleware.EncodeResponse(resp)); err != nil {
|
respData, err := middleware.EncodeResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "encode response", reqInfo, err)
|
||||||
|
}
|
||||||
|
if _, err = w.Write(respData); err != nil {
|
||||||
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -673,9 +702,33 @@ func checkPostPolicy(r *http.Request, reqInfo *middleware.ReqInfo, metadata map[
|
||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsACLHeaders(r *http.Request) bool {
|
type aclStatus int
|
||||||
return r.Header.Get(api.AmzACL) != "" || r.Header.Get(api.AmzGrantRead) != "" ||
|
|
||||||
r.Header.Get(api.AmzGrantFullControl) != "" || r.Header.Get(api.AmzGrantWrite) != ""
|
const (
|
||||||
|
// aclStatusNo means no acl headers at all.
|
||||||
|
aclStatusNo aclStatus = iota
|
||||||
|
// aclStatusYesAPECompatible means that only X-Amz-Acl present and equals to private.
|
||||||
|
aclStatusYesAPECompatible
|
||||||
|
// aclStatusYes means any other acl headers configuration.
|
||||||
|
aclStatusYes
|
||||||
|
)
|
||||||
|
|
||||||
|
func aclHeadersStatus(r *http.Request) aclStatus {
|
||||||
|
if r.Header.Get(api.AmzGrantRead) != "" ||
|
||||||
|
r.Header.Get(api.AmzGrantFullControl) != "" ||
|
||||||
|
r.Header.Get(api.AmzGrantWrite) != "" {
|
||||||
|
return aclStatusYes
|
||||||
|
}
|
||||||
|
|
||||||
|
cannedACL := r.Header.Get(api.AmzACL)
|
||||||
|
if cannedACL != "" {
|
||||||
|
if cannedACL == basicACLPrivate {
|
||||||
|
return aclStatusYesAPECompatible
|
||||||
|
}
|
||||||
|
return aclStatusYes
|
||||||
|
}
|
||||||
|
|
||||||
|
return aclStatusNo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) getNewEAclTable(r *http.Request, bktInfo *data.BucketInfo, objInfo *data.ObjectInfo) (*eacl.Table, error) {
|
func (h *handler) getNewEAclTable(r *http.Request, bktInfo *data.BucketInfo, objInfo *data.ObjectInfo) (*eacl.Table, error) {
|
||||||
|
@ -849,7 +902,7 @@ func (h *handler) createBucketHandlerPolicy(w http.ResponseWriter, r *http.Reque
|
||||||
h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID))
|
h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID))
|
||||||
|
|
||||||
chains := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
chains := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
||||||
if err = h.ape.SaveACLChains(reqInfo.Namespace, chains); err != nil {
|
if err = h.ape.SaveACLChains(bktInfo.CID.EncodeToString(), chains); err != nil {
|
||||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
|
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -867,13 +920,40 @@ func (h *handler) createBucketHandlerPolicy(w http.ResponseWriter, r *http.Reque
|
||||||
sp.Settings.Versioning = data.VersioningEnabled
|
sp.Settings.Versioning = data.VersioningEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = h.obj.PutBucketSettings(ctx, sp); err != nil {
|
err = retryer.MakeWithRetry(ctx, func() error {
|
||||||
|
return h.obj.PutBucketSettings(ctx, sp)
|
||||||
|
}, h.putBucketSettingsRetryer())
|
||||||
|
if err != nil {
|
||||||
h.logAndSendError(w, "couldn't save bucket settings", reqInfo, err,
|
h.logAndSendError(w, "couldn't save bucket settings", reqInfo, err,
|
||||||
zap.String("container_id", bktInfo.CID.EncodeToString()))
|
zap.String("container_id", bktInfo.CID.EncodeToString()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) putBucketSettingsRetryer() aws.RetryerV2 {
|
||||||
|
return retry.NewStandard(func(options *retry.StandardOptions) {
|
||||||
|
options.MaxAttempts = h.cfg.RetryMaxAttempts()
|
||||||
|
options.MaxBackoff = h.cfg.RetryMaxBackoff()
|
||||||
|
if h.cfg.RetryStrategy() == RetryStrategyExponential {
|
||||||
|
options.Backoff = retry.NewExponentialJitterBackoff(options.MaxBackoff)
|
||||||
|
} else {
|
||||||
|
options.Backoff = retry.BackoffDelayerFunc(func(int, error) (time.Duration, error) {
|
||||||
|
return options.MaxBackoff, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
options.Retryables = []retry.IsErrorRetryable{retry.IsErrorRetryableFunc(func(err error) aws.Ternary {
|
||||||
|
if stderrors.Is(err, tree.ErrNodeAccessDenied) {
|
||||||
|
return aws.TrueTernary
|
||||||
|
}
|
||||||
|
return aws.FalseTernary
|
||||||
|
})}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) createBucketHandlerACL(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) createBucketHandlerACL(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -942,7 +1022,10 @@ func (h *handler) createBucketHandlerACL(w http.ResponseWriter, r *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.WriteSuccessResponseHeadersOnly(w)
|
if err = middleware.WriteSuccessResponseHeadersOnly(w); err != nil {
|
||||||
|
h.logAndSendError(w, "write response", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const s3ActionPrefix = "s3:"
|
const s3ActionPrefix = "s3:"
|
||||||
|
|
|
@ -31,9 +31,12 @@ func (h *handler) reqLogger(ctx context.Context) *zap.Logger {
|
||||||
|
|
||||||
func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo *middleware.ReqInfo, err error, additional ...zap.Field) {
|
func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo *middleware.ReqInfo, err error, additional ...zap.Field) {
|
||||||
err = handleDeleteMarker(w, err)
|
err = handleDeleteMarker(w, err)
|
||||||
code := middleware.WriteErrorResponse(w, reqInfo, transformToS3Error(err))
|
if code, wrErr := middleware.WriteErrorResponse(w, reqInfo, transformToS3Error(err)); wrErr != nil {
|
||||||
|
additional = append(additional, zap.NamedError("write_response_error", wrErr))
|
||||||
|
} else {
|
||||||
|
additional = append(additional, zap.Int("status", code))
|
||||||
|
}
|
||||||
fields := []zap.Field{
|
fields := []zap.Field{
|
||||||
zap.Int("status", code),
|
|
||||||
zap.String("request_id", reqInfo.RequestID),
|
zap.String("request_id", reqInfo.RequestID),
|
||||||
zap.String("method", reqInfo.API),
|
zap.String("method", reqInfo.API),
|
||||||
zap.String("bucket", reqInfo.BucketName),
|
zap.String("bucket", reqInfo.BucketName),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||||
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||||
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
@ -220,7 +221,7 @@ func (t *TestFrostFS) ReadObject(ctx context.Context, prm PrmObjectRead) (*Objec
|
||||||
|
|
||||||
if obj, ok := t.objects[sAddr]; ok {
|
if obj, ok := t.objects[sAddr]; ok {
|
||||||
owner := getBearerOwner(ctx)
|
owner := getBearerOwner(ctx)
|
||||||
if !t.checkAccess(prm.Container, owner, eacl.OperationGet) {
|
if !t.checkAccess(prm.Container, owner, eacl.OperationGet, obj) {
|
||||||
return nil, ErrAccessDenied
|
return nil, ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,9 +323,9 @@ func (t *TestFrostFS) DeleteObject(ctx context.Context, prm PrmObjectDelete) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := t.objects[addr.EncodeToString()]; ok {
|
if obj, ok := t.objects[addr.EncodeToString()]; ok {
|
||||||
owner := getBearerOwner(ctx)
|
owner := getBearerOwner(ctx)
|
||||||
if !t.checkAccess(prm.Container, owner, eacl.OperationDelete) {
|
if !t.checkAccess(prm.Container, owner, eacl.OperationDelete, obj) {
|
||||||
return ErrAccessDenied
|
return ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +377,7 @@ func (t *TestFrostFS) ContainerEACL(_ context.Context, prm PrmContainerEACL) (*e
|
||||||
return table, nil
|
return table, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID, op eacl.Operation) bool {
|
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID, op eacl.Operation, obj *object.Object) bool {
|
||||||
cnr, ok := t.containers[cnrID.EncodeToString()]
|
cnr, ok := t.containers[cnrID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
|
@ -392,22 +393,51 @@ func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID, op eacl.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rec := range table.Records() {
|
for _, rec := range table.Records() {
|
||||||
if rec.Operation() == op && len(rec.Filters()) == 0 {
|
if rec.Operation() != op {
|
||||||
for _, trgt := range rec.Targets() {
|
continue
|
||||||
if trgt.Role() == eacl.RoleOthers {
|
}
|
||||||
return rec.Action() == eacl.ActionAllow
|
|
||||||
}
|
if !matchTarget(rec, owner) {
|
||||||
var targetOwner user.ID
|
continue
|
||||||
for _, pk := range eacl.TargetECDSAKeys(&trgt) {
|
}
|
||||||
user.IDFromKey(&targetOwner, *pk)
|
|
||||||
if targetOwner.Equals(owner) {
|
if matchFilter(rec.Filters(), obj) {
|
||||||
return rec.Action() == eacl.ActionAllow
|
return rec.Action() == eacl.ActionAllow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchTarget(rec eacl.Record, owner user.ID) bool {
|
||||||
|
for _, trgt := range rec.Targets() {
|
||||||
|
if trgt.Role() == eacl.RoleOthers {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
var targetOwner user.ID
|
||||||
|
for _, pk := range eacl.TargetECDSAKeys(&trgt) {
|
||||||
|
user.IDFromKey(&targetOwner, *pk)
|
||||||
|
if targetOwner.Equals(owner) {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFilter(filters []eacl.Filter, obj *object.Object) bool {
|
||||||
|
objID, _ := obj.ID()
|
||||||
|
for _, f := range filters {
|
||||||
|
fv2 := f.ToV2()
|
||||||
|
if fv2.GetMatchType() != acl.MatchTypeStringEqual ||
|
||||||
|
fv2.GetHeaderType() != acl.HeaderTypeObject ||
|
||||||
|
fv2.GetKey() != acl.FilterObjectID ||
|
||||||
|
fv2.GetValue() != objID.EncodeToString() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,13 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
stderrors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -15,6 +18,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
|
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
@ -659,17 +663,26 @@ func getRandomOID() (oid.ID, error) {
|
||||||
|
|
||||||
func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings *data.BucketSettings, obj *VersionedObject) *VersionedObject {
|
func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings *data.BucketSettings, obj *VersionedObject) *VersionedObject {
|
||||||
if len(obj.VersionID) != 0 || settings.Unversioned() {
|
if len(obj.VersionID) != 0 || settings.Unversioned() {
|
||||||
var nodeVersion *data.NodeVersion
|
var nodeVersions []*data.NodeVersion
|
||||||
if nodeVersion, obj.Error = n.getNodeVersionToDelete(ctx, bkt, obj); obj.Error != nil {
|
if nodeVersions, obj.Error = n.getNodeVersionsToDelete(ctx, bkt, obj); obj.Error != nil {
|
||||||
return n.handleNotFoundError(bkt, obj)
|
return n.handleNotFoundError(bkt, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.DeleteMarkVersion, obj.Error = n.removeOldVersion(ctx, bkt, nodeVersion, obj); obj.Error != nil {
|
for _, nodeVersion := range nodeVersions {
|
||||||
return n.handleObjectDeleteErrors(ctx, bkt, obj, nodeVersion.ID)
|
if obj.DeleteMarkVersion, obj.Error = n.removeOldVersion(ctx, bkt, nodeVersion, obj); obj.Error != nil {
|
||||||
|
if !client.IsErrObjectAlreadyRemoved(obj.Error) && !client.IsErrObjectNotFound(obj.Error) {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
n.reqLogger(ctx).Debug(logs.CouldntDeleteObjectFromStorageContinueDeleting,
|
||||||
|
zap.Stringer("cid", bkt.CID), zap.String("oid", obj.VersionID), zap.Error(obj.Error))
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Error = n.treeService.RemoveVersion(ctx, bkt, nodeVersion.ID); obj.Error != nil {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.Error = n.treeService.RemoveVersion(ctx, bkt, nodeVersion.ID)
|
n.cache.DeleteObjectName(bkt.CID, bkt.Name, obj.Name)
|
||||||
n.cache.CleanListCacheEntriesContainingObject(obj.Name, bkt.CID)
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,20 +695,30 @@ func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings
|
||||||
if settings.VersioningSuspended() {
|
if settings.VersioningSuspended() {
|
||||||
obj.VersionID = data.UnversionedObjectVersionID
|
obj.VersionID = data.UnversionedObjectVersionID
|
||||||
|
|
||||||
var nullVersionToDelete *data.NodeVersion
|
var nodeVersions []*data.NodeVersion
|
||||||
if lastVersion.IsUnversioned {
|
if nodeVersions, obj.Error = n.getNodeVersionsToDelete(ctx, bkt, obj); obj.Error != nil {
|
||||||
if !lastVersion.IsDeleteMarker {
|
|
||||||
nullVersionToDelete = lastVersion
|
|
||||||
}
|
|
||||||
} else if nullVersionToDelete, obj.Error = n.getNodeVersionToDelete(ctx, bkt, obj); obj.Error != nil {
|
|
||||||
if !isNotFoundError(obj.Error) {
|
if !isNotFoundError(obj.Error) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if nullVersionToDelete != nil {
|
for _, nodeVersion := range nodeVersions {
|
||||||
if obj.DeleteMarkVersion, obj.Error = n.removeOldVersion(ctx, bkt, nullVersionToDelete, obj); obj.Error != nil {
|
if nodeVersion.ID == lastVersion.ID && nodeVersion.IsDeleteMarker {
|
||||||
return n.handleObjectDeleteErrors(ctx, bkt, obj, nullVersionToDelete.ID)
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !nodeVersion.IsDeleteMarker {
|
||||||
|
if obj.DeleteMarkVersion, obj.Error = n.removeOldVersion(ctx, bkt, nodeVersion, obj); obj.Error != nil {
|
||||||
|
if !client.IsErrObjectAlreadyRemoved(obj.Error) && !client.IsErrObjectNotFound(obj.Error) {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
n.reqLogger(ctx).Debug(logs.CouldntDeleteObjectFromStorageContinueDeleting,
|
||||||
|
zap.Stringer("cid", bkt.CID), zap.String("oid", obj.VersionID), zap.Error(obj.Error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Error = n.treeService.RemoveVersion(ctx, bkt, nodeVersion.ID); obj.Error != nil {
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -743,36 +766,70 @@ func (n *layer) handleNotFoundError(bkt *data.BucketInfo, obj *VersionedObject)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) handleObjectDeleteErrors(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject, nodeID uint64) *VersionedObject {
|
|
||||||
if !client.IsErrObjectAlreadyRemoved(obj.Error) && !client.IsErrObjectNotFound(obj.Error) {
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
n.reqLogger(ctx).Debug(logs.CouldntDeleteObjectFromStorageContinueDeleting,
|
|
||||||
zap.Stringer("cid", bkt.CID), zap.String("oid", obj.VersionID), zap.Error(obj.Error))
|
|
||||||
|
|
||||||
obj.Error = n.treeService.RemoveVersion(ctx, bkt, nodeID)
|
|
||||||
if obj.Error == nil {
|
|
||||||
n.cache.DeleteObjectName(bkt.CID, bkt.Name, obj.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNotFoundError(err error) bool {
|
func isNotFoundError(err error) bool {
|
||||||
return errors.IsS3Error(err, errors.ErrNoSuchKey) ||
|
return errors.IsS3Error(err, errors.ErrNoSuchKey) ||
|
||||||
errors.IsS3Error(err, errors.ErrNoSuchVersion)
|
errors.IsS3Error(err, errors.ErrNoSuchVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) getNodeVersionToDelete(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) (*data.NodeVersion, error) {
|
func (n *layer) getNodeVersionsToDelete(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) ([]*data.NodeVersion, error) {
|
||||||
objVersion := &ObjectVersion{
|
var versionsToDelete []*data.NodeVersion
|
||||||
BktInfo: bkt,
|
versions, err := n.treeService.GetVersions(ctx, bkt, obj.Name)
|
||||||
ObjectName: obj.Name,
|
if err != nil {
|
||||||
VersionID: obj.VersionID,
|
if stderrors.Is(err, ErrNodeNotFound) {
|
||||||
NoErrorOnDeleteMarker: true,
|
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.getNodeVersion(ctx, objVersion)
|
if len(versions) == 0 {
|
||||||
|
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", s3errors.GetAPIError(s3errors.ErrNoSuchVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(versions, func(i, j int) bool {
|
||||||
|
return versions[i].Timestamp < versions[j].Timestamp
|
||||||
|
})
|
||||||
|
|
||||||
|
var matchFn func(nv *data.NodeVersion) bool
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case obj.VersionID == data.UnversionedObjectVersionID:
|
||||||
|
matchFn = func(nv *data.NodeVersion) bool {
|
||||||
|
return nv.IsUnversioned
|
||||||
|
}
|
||||||
|
case len(obj.VersionID) == 0:
|
||||||
|
latest := versions[len(versions)-1]
|
||||||
|
if latest.IsUnversioned {
|
||||||
|
matchFn = func(nv *data.NodeVersion) bool {
|
||||||
|
return nv.IsUnversioned
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchFn = func(nv *data.NodeVersion) bool {
|
||||||
|
return nv.ID == latest.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
matchFn = func(nv *data.NodeVersion) bool {
|
||||||
|
return nv.OID.EncodeToString() == obj.VersionID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var oids []string
|
||||||
|
for _, v := range versions {
|
||||||
|
if matchFn(v) {
|
||||||
|
versionsToDelete = append(versionsToDelete, v)
|
||||||
|
if !v.IsDeleteMarker {
|
||||||
|
oids = append(oids, v.OID.EncodeToString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(versionsToDelete) == 0 {
|
||||||
|
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", s3errors.GetAPIError(s3errors.ErrNoSuchVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
n.reqLogger(ctx).Debug(logs.GetTreeNodeToDelete, zap.Stringer("cid", bkt.CID), zap.Strings("oids", oids))
|
||||||
|
|
||||||
|
return versionsToDelete, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) getLastNodeVersion(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) (*data.NodeVersion, error) {
|
func (n *layer) getLastNodeVersion(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) (*data.NodeVersion, error) {
|
||||||
|
@ -791,9 +848,40 @@ func (n *layer) removeOldVersion(ctx context.Context, bkt *data.BucketInfo, node
|
||||||
return obj.VersionID, nil
|
return obj.VersionID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nodeVersion.IsCombined {
|
||||||
|
return "", n.removeCombinedObject(ctx, bkt, nodeVersion)
|
||||||
|
}
|
||||||
|
|
||||||
return "", n.objectDelete(ctx, bkt, nodeVersion.OID)
|
return "", n.objectDelete(ctx, bkt, nodeVersion.OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *layer) removeCombinedObject(ctx context.Context, bkt *data.BucketInfo, nodeVersion *data.NodeVersion) error {
|
||||||
|
combinedObj, err := n.objectGet(ctx, bkt, nodeVersion.OID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get combined object '%s': %w", nodeVersion.OID.EncodeToString(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts []*data.PartInfo
|
||||||
|
if err = json.Unmarshal(combinedObj.Payload(), &parts); err != nil {
|
||||||
|
return fmt.Errorf("unmarshal combined object parts: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
if err = n.objectDelete(ctx, bkt, part.OID); err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !client.IsErrObjectAlreadyRemoved(err) && !client.IsErrObjectNotFound(err) {
|
||||||
|
return fmt.Errorf("couldn't delete part '%s': %w", part.OID.EncodeToString(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n.reqLogger(ctx).Warn(logs.CouldntDeletePart, zap.String("cid", bkt.CID.EncodeToString()),
|
||||||
|
zap.String("oid", part.OID.EncodeToString()), zap.Int("part number", part.Number), zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.objectDelete(ctx, bkt, nodeVersion.OID)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteObjects from the storage.
|
// DeleteObjects from the storage.
|
||||||
func (n *layer) DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*VersionedObject {
|
func (n *layer) DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*VersionedObject {
|
||||||
for i, obj := range p.Objects {
|
for i, obj := range p.Objects {
|
||||||
|
|
|
@ -384,7 +384,7 @@ func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.Bucke
|
||||||
meta, err := n.objectHead(ctx, bkt, node.OID)
|
meta, err := n.objectHead(ctx, bkt, node.OID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrObjectNotFound(err) {
|
if client.IsErrObjectNotFound(err) {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchKey), err.Error())
|
return nil, fmt.Errorf("%w: %s; %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchKey), err.Error(), node.OID.EncodeToString())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,9 @@ func Auth(center Center, log *zap.Logger) Func {
|
||||||
if _, ok := err.(apiErrors.Error); !ok {
|
if _, ok := err.(apiErrors.Error); !ok {
|
||||||
err = apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
err = apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
WriteErrorResponse(w, GetReqInfo(r.Context()), err)
|
if _, wrErr := WriteErrorResponse(w, GetReqInfo(r.Context()), err); wrErr != nil {
|
||||||
|
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,7 +99,9 @@ func FrostfsIDValidation(frostfsID FrostFSIDValidator, log *zap.Logger) Func {
|
||||||
|
|
||||||
if err = validateBearerToken(frostfsID, bd.Gate.BearerToken); err != nil {
|
if err = validateBearerToken(frostfsID, bd.Gate.BearerToken); err != nil {
|
||||||
reqLogOrDefault(ctx, log).Error(logs.FrostfsIDValidationFailed, zap.Error(err))
|
reqLogOrDefault(ctx, log).Error(logs.FrostfsIDValidationFailed, zap.Error(err))
|
||||||
WriteErrorResponse(w, GetReqInfo(r.Context()), err)
|
if _, wrErr := WriteErrorResponse(w, GetReqInfo(r.Context()), err); wrErr != nil {
|
||||||
|
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ const (
|
||||||
|
|
||||||
// bucket operations.
|
// bucket operations.
|
||||||
|
|
||||||
OptionsOperation = "Options"
|
OptionsBucketOperation = "OptionsBucket"
|
||||||
HeadBucketOperation = "HeadBucket"
|
HeadBucketOperation = "HeadBucket"
|
||||||
ListMultipartUploadsOperation = "ListMultipartUploads"
|
ListMultipartUploadsOperation = "ListMultipartUploads"
|
||||||
GetBucketLocationOperation = "GetBucketLocation"
|
GetBucketLocationOperation = "GetBucketLocation"
|
||||||
|
@ -50,6 +50,7 @@ const (
|
||||||
|
|
||||||
// object operations.
|
// object operations.
|
||||||
|
|
||||||
|
OptionsObjectOperation = "OptionsObject"
|
||||||
HeadObjectOperation = "HeadObject"
|
HeadObjectOperation = "HeadObject"
|
||||||
ListPartsOperation = "ListParts"
|
ListPartsOperation = "ListParts"
|
||||||
GetObjectACLOperation = "GetObjectACL"
|
GetObjectACLOperation = "GetObjectACL"
|
||||||
|
|
|
@ -103,7 +103,7 @@ func stats(f http.HandlerFunc, resolveCID cidResolveFunc, appMetrics *metrics.Ap
|
||||||
|
|
||||||
func requestTypeFromAPI(api string) metrics.RequestType {
|
func requestTypeFromAPI(api string) metrics.RequestType {
|
||||||
switch api {
|
switch api {
|
||||||
case OptionsOperation, HeadObjectOperation, HeadBucketOperation:
|
case OptionsBucketOperation, OptionsObjectOperation, HeadObjectOperation, HeadBucketOperation:
|
||||||
return metrics.HEADRequest
|
return metrics.HEADRequest
|
||||||
case CreateMultipartUploadOperation, UploadPartCopyOperation, UploadPartOperation, CompleteMultipartUploadOperation,
|
case CreateMultipartUploadOperation, UploadPartCopyOperation, UploadPartOperation, CompleteMultipartUploadOperation,
|
||||||
PutObjectACLOperation, PutObjectTaggingOperation, CopyObjectOperation, PutObjectRetentionOperation, PutObjectLegalHoldOperation,
|
PutObjectACLOperation, PutObjectTaggingOperation, CopyObjectOperation, PutObjectRetentionOperation, PutObjectLegalHoldOperation,
|
||||||
|
|
|
@ -47,7 +47,9 @@ func PolicyCheck(cfg PolicyConfig) Func {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
if err := policyCheck(r, cfg); err != nil {
|
if err := policyCheck(r, cfg); err != nil {
|
||||||
reqLogOrDefault(ctx, cfg.Log).Error(logs.PolicyValidationFailed, zap.Error(err))
|
reqLogOrDefault(ctx, cfg.Log).Error(logs.PolicyValidationFailed, zap.Error(err))
|
||||||
WriteErrorResponse(w, GetReqInfo(ctx), err)
|
if _, wrErr := WriteErrorResponse(w, GetReqInfo(ctx), err); wrErr != nil {
|
||||||
|
reqLogOrDefault(ctx, cfg.Log).Error(logs.FailedToWriteResponse, zap.Error(wrErr))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,13 +60,39 @@ func PolicyCheck(cfg PolicyConfig) Func {
|
||||||
|
|
||||||
func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
reqType, bktName, objName := getBucketObject(r, cfg.Domains)
|
reqType, bktName, objName := getBucketObject(r, cfg.Domains)
|
||||||
req, err := getPolicyRequest(r, cfg.FrostfsID, reqType, bktName, objName, cfg.Log)
|
req, userKey, userGroups, err := getPolicyRequest(r, cfg.FrostfsID, reqType, bktName, objName, cfg.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bktInfo *data.BucketInfo
|
||||||
|
if reqType != noneType && !strings.HasSuffix(req.Operation(), CreateBucketOperation) {
|
||||||
|
bktInfo, err = cfg.BucketResolver(r.Context(), bktName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reqInfo := GetReqInfo(r.Context())
|
reqInfo := GetReqInfo(r.Context())
|
||||||
target := engine.NewRequestTargetWithNamespace(reqInfo.Namespace)
|
target := engine.NewRequestTargetWithNamespace(reqInfo.Namespace)
|
||||||
|
if bktInfo != nil {
|
||||||
|
cnrTarget := engine.ContainerTarget(bktInfo.CID.EncodeToString())
|
||||||
|
target.Container = &cnrTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
if userKey != nil {
|
||||||
|
entityName := fmt.Sprintf("%s:%s", reqInfo.Namespace, userKey.Address())
|
||||||
|
uTarget := engine.UserTarget(entityName)
|
||||||
|
target.User = &uTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
gts := make([]engine.Target, len(userGroups))
|
||||||
|
for i, group := range userGroups {
|
||||||
|
entityName := fmt.Sprintf("%s:%s", reqInfo.Namespace, group)
|
||||||
|
gts[i] = engine.GroupTarget(entityName)
|
||||||
|
}
|
||||||
|
target.Groups = gts
|
||||||
|
|
||||||
st, found, err := cfg.Storage.IsAllowed(chain.S3, target, req)
|
st, found, err := cfg.Storage.IsAllowed(chain.S3, target, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -81,9 +109,9 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
isAPE, err := isAPEBehavior(r.Context(), req, cfg, reqType, bktName)
|
isAPE := !cfg.Settings.ACLEnabled()
|
||||||
if err != nil {
|
if bktInfo != nil {
|
||||||
return err
|
isAPE = bktInfo.APEEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if isAPE && cfg.Settings.PolicyDenyByDefault() {
|
if isAPE && cfg.Settings.PolicyDenyByDefault() {
|
||||||
|
@ -93,38 +121,25 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAPEBehavior(ctx context.Context, req *testutil.Request, cfg PolicyConfig, reqType ReqType, bktName string) (bool, error) {
|
func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string, log *zap.Logger) (*testutil.Request, *keys.PublicKey, []string, error) {
|
||||||
if reqType == noneType ||
|
|
||||||
strings.HasSuffix(req.Operation(), CreateBucketOperation) {
|
|
||||||
return !cfg.Settings.ACLEnabled(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
bktInfo, err := cfg.BucketResolver(ctx, bktName) // we cannot use reqInfo.BucketName because it hasn't been set yet
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bktInfo.APEEnabled, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string, log *zap.Logger) (*testutil.Request, error) {
|
|
||||||
var (
|
var (
|
||||||
owner string
|
owner string
|
||||||
groups []string
|
groups []string
|
||||||
|
pk *keys.PublicKey
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
bd, err := GetBoxData(ctx)
|
bd, err := GetBoxData(ctx)
|
||||||
if err == nil && bd.Gate.BearerToken != nil {
|
if err == nil && bd.Gate.BearerToken != nil {
|
||||||
pk, err := keys.NewPublicKeyFromBytes(bd.Gate.BearerToken.SigningKeyBytes(), elliptic.P256())
|
pk, err = keys.NewPublicKeyFromBytes(bd.Gate.BearerToken.SigningKeyBytes(), elliptic.P256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse pubclic key from btoken: %w", err)
|
return nil, nil, nil, fmt.Errorf("parse pubclic key from btoken: %w", err)
|
||||||
}
|
}
|
||||||
owner = pk.Address()
|
owner = pk.Address()
|
||||||
|
|
||||||
groups, err = frostfsid.GetUserGroupIDs(pk.GetScriptHash())
|
groups, err = frostfsid.GetUserGroupIDs(pk.GetScriptHash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get group ids: %w", err)
|
return nil, nil, nil, fmt.Errorf("get group ids: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +160,7 @@ func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqT
|
||||||
s3.PropertyKeyOwner: owner,
|
s3.PropertyKeyOwner: owner,
|
||||||
common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups),
|
common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups),
|
||||||
},
|
},
|
||||||
), nil
|
), pk, groups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReqType int
|
type ReqType int
|
||||||
|
@ -176,11 +191,11 @@ func getBucketObject(r *http.Request, domains []string) (reqType ReqType, bktNam
|
||||||
return noneType, "", ""
|
return noneType, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if ind := strings.IndexByte(bktObj, '/'); ind != -1 {
|
if ind := strings.IndexByte(bktObj, '/'); ind != -1 && bktObj[ind+1:] != "" {
|
||||||
return objectType, bktObj[:ind], bktObj[ind+1:]
|
return objectType, bktObj[:ind], bktObj[ind+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return bucketType, bktObj, ""
|
return bucketType, strings.TrimSuffix(bktObj, "/"), ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineOperation(r *http.Request, reqType ReqType) (operation string) {
|
func determineOperation(r *http.Request, reqType ReqType) (operation string) {
|
||||||
|
@ -200,7 +215,7 @@ func determineBucketOperation(r *http.Request) string {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodOptions:
|
case http.MethodOptions:
|
||||||
return OptionsOperation
|
return OptionsBucketOperation
|
||||||
case http.MethodHead:
|
case http.MethodHead:
|
||||||
return HeadBucketOperation
|
return HeadBucketOperation
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
|
@ -303,6 +318,8 @@ func determineBucketOperation(r *http.Request) string {
|
||||||
func determineObjectOperation(r *http.Request) string {
|
func determineObjectOperation(r *http.Request) string {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
|
case http.MethodOptions:
|
||||||
|
return OptionsObjectOperation
|
||||||
case http.MethodHead:
|
case http.MethodHead:
|
||||||
return HeadObjectOperation
|
return HeadObjectOperation
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
|
|
82
api/middleware/policy_test.go
Normal file
82
api/middleware/policy_test.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReqTypeDetermination(t *testing.T) {
|
||||||
|
bkt, obj, domain := "test-bucket", "test-object", "domain"
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
target string
|
||||||
|
host string
|
||||||
|
domains []string
|
||||||
|
expectedType ReqType
|
||||||
|
expectedBktName string
|
||||||
|
expectedObjName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "bucket request, path-style",
|
||||||
|
target: "/" + bkt,
|
||||||
|
expectedType: bucketType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bucket request with slash, path-style",
|
||||||
|
target: "/" + bkt + "/",
|
||||||
|
expectedType: bucketType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "object request, path-style",
|
||||||
|
target: "/" + bkt + "/" + obj,
|
||||||
|
expectedType: objectType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
expectedObjName: obj,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "object request with slash, path-style",
|
||||||
|
target: "/" + bkt + "/" + obj + "/",
|
||||||
|
expectedType: objectType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
expectedObjName: obj + "/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "none type request",
|
||||||
|
target: "/",
|
||||||
|
expectedType: noneType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bucket request, virtual-hosted style",
|
||||||
|
target: "/",
|
||||||
|
host: bkt + "." + domain,
|
||||||
|
domains: []string{"some-domain", domain},
|
||||||
|
expectedType: bucketType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "object request, virtual-hosted style",
|
||||||
|
target: "/" + obj,
|
||||||
|
host: bkt + "." + domain,
|
||||||
|
domains: []string{"some-domain", domain},
|
||||||
|
expectedType: objectType,
|
||||||
|
expectedBktName: bkt,
|
||||||
|
expectedObjName: obj,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
r := httptest.NewRequest(http.MethodPut, tc.target, nil)
|
||||||
|
r.Host = tc.host
|
||||||
|
|
||||||
|
reqType, bktName, objName := getBucketObject(r, tc.domains)
|
||||||
|
require.Equal(t, tc.expectedType, reqType)
|
||||||
|
require.Equal(t, tc.expectedBktName, bktName)
|
||||||
|
require.Equal(t, tc.expectedObjName, objName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -118,7 +118,8 @@ var s3ErrorResponseMap = map[string]string{
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteErrorResponse writes error headers.
|
// WriteErrorResponse writes error headers.
|
||||||
func WriteErrorResponse(w http.ResponseWriter, reqInfo *ReqInfo, err error) int {
|
// returns http error code and error in case of failure of response writing.
|
||||||
|
func WriteErrorResponse(w http.ResponseWriter, reqInfo *ReqInfo, err error) (int, error) {
|
||||||
code := http.StatusInternalServerError
|
code := http.StatusInternalServerError
|
||||||
|
|
||||||
if e, ok := err.(errors.Error); ok {
|
if e, ok := err.(errors.Error); ok {
|
||||||
|
@ -134,9 +135,14 @@ func WriteErrorResponse(w http.ResponseWriter, reqInfo *ReqInfo, err error) int
|
||||||
|
|
||||||
// Generates error response.
|
// Generates error response.
|
||||||
errorResponse := getAPIErrorResponse(reqInfo, err)
|
errorResponse := getAPIErrorResponse(reqInfo, err)
|
||||||
encodedErrorResponse := EncodeResponse(errorResponse)
|
encodedErrorResponse, err := EncodeResponse(errorResponse)
|
||||||
WriteResponse(w, code, encodedErrorResponse, MimeXML)
|
if err != nil {
|
||||||
return code
|
return 0, fmt.Errorf("encode response: %w", err)
|
||||||
|
}
|
||||||
|
if err = WriteResponse(w, code, encodedErrorResponse, MimeXML); err != nil {
|
||||||
|
return 0, fmt.Errorf("write response: %w", err)
|
||||||
|
}
|
||||||
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write http common headers.
|
// Write http common headers.
|
||||||
|
@ -157,7 +163,7 @@ func removeSensitiveHeaders(h http.Header) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteResponse writes given statusCode and response into w (with mType header if set).
|
// WriteResponse writes given statusCode and response into w (with mType header if set).
|
||||||
func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
|
func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) error {
|
||||||
setCommonHeaders(w)
|
setCommonHeaders(w)
|
||||||
if mType != MimeNone {
|
if mType != MimeNone {
|
||||||
w.Header().Set(hdrContentType, string(mType))
|
w.Header().Set(hdrContentType, string(mType))
|
||||||
|
@ -165,37 +171,46 @@ func WriteResponse(w http.ResponseWriter, statusCode int, response []byte, mType
|
||||||
w.Header().Set(hdrContentLength, strconv.Itoa(len(response)))
|
w.Header().Set(hdrContentLength, strconv.Itoa(len(response)))
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
if response == nil {
|
if response == nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteResponseBody(w, response)
|
return WriteResponseBody(w, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteResponseBody writes response into w.
|
// WriteResponseBody writes response into w.
|
||||||
func WriteResponseBody(w http.ResponseWriter, response []byte) {
|
func WriteResponseBody(w http.ResponseWriter, response []byte) error {
|
||||||
_, _ = w.Write(response)
|
if _, err := w.Write(response); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if flusher, ok := w.(http.Flusher); ok {
|
if flusher, ok := w.(http.Flusher); ok {
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeResponse encodes the response headers into XML format.
|
// EncodeResponse encodes the response headers into XML format.
|
||||||
func EncodeResponse(response interface{}) []byte {
|
func EncodeResponse(response interface{}) ([]byte, error) {
|
||||||
var bytesBuffer bytes.Buffer
|
var bytesBuffer bytes.Buffer
|
||||||
bytesBuffer.WriteString(xml.Header)
|
bytesBuffer.WriteString(xml.Header)
|
||||||
_ = xml.
|
if err := xml.NewEncoder(&bytesBuffer).Encode(response); err != nil {
|
||||||
NewEncoder(&bytesBuffer).
|
return nil, err
|
||||||
Encode(response)
|
}
|
||||||
return bytesBuffer.Bytes()
|
|
||||||
|
return bytesBuffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeResponseNoHeader encodes response without setting xml.Header.
|
// EncodeResponseNoHeader encodes response without setting xml.Header.
|
||||||
// Should be used with periodicXMLWriter which sends xml.Header to the client
|
// Should be used with periodicXMLWriter which sends xml.Header to the client
|
||||||
// with whitespaces to keep connection alive.
|
// with whitespaces to keep connection alive.
|
||||||
func EncodeResponseNoHeader(response interface{}) []byte {
|
func EncodeResponseNoHeader(response interface{}) ([]byte, error) {
|
||||||
var bytesBuffer bytes.Buffer
|
var bytesBuffer bytes.Buffer
|
||||||
_ = xml.NewEncoder(&bytesBuffer).Encode(response)
|
if err := xml.NewEncoder(&bytesBuffer).Encode(response); err != nil {
|
||||||
return bytesBuffer.Bytes()
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesBuffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeToResponse encodes the response into ResponseWriter.
|
// EncodeToResponse encodes the response into ResponseWriter.
|
||||||
|
@ -227,8 +242,8 @@ func EncodeToResponseNoHeader(w http.ResponseWriter, response interface{}) error
|
||||||
|
|
||||||
// WriteSuccessResponseHeadersOnly writes HTTP (200) OK response with no data
|
// WriteSuccessResponseHeadersOnly writes HTTP (200) OK response with no data
|
||||||
// to the client.
|
// to the client.
|
||||||
func WriteSuccessResponseHeadersOnly(w http.ResponseWriter) {
|
func WriteSuccessResponseHeadersOnly(w http.ResponseWriter) error {
|
||||||
WriteResponse(w, http.StatusOK, nil, MimeNone)
|
return WriteResponse(w, http.StatusOK, nil, MimeNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error -- Returns S3 error string.
|
// Error -- Returns S3 error string.
|
||||||
|
|
|
@ -178,14 +178,24 @@ func errorResponseHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := s3middleware.GetReqInfo(ctx)
|
reqInfo := s3middleware.GetReqInfo(ctx)
|
||||||
|
|
||||||
desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path)
|
desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path)
|
||||||
s3middleware.WriteErrorResponse(w, reqInfo, errors.Error{
|
_, wrErr := s3middleware.WriteErrorResponse(w, reqInfo, errors.Error{
|
||||||
Code: "UnknownAPIRequest",
|
Code: "UnknownAPIRequest",
|
||||||
Description: desc,
|
Description: desc,
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
})
|
})
|
||||||
|
|
||||||
if log := s3middleware.GetReqLog(ctx); log != nil {
|
if log := s3middleware.GetReqLog(ctx); log != nil {
|
||||||
log.Error(logs.RequestUnmatched, zap.String("method", reqInfo.API), zap.String("http method", r.Method), zap.String("url", r.RequestURI))
|
fields := []zap.Field{
|
||||||
|
zap.String("method", reqInfo.API),
|
||||||
|
zap.String("http method", r.Method),
|
||||||
|
zap.String("url", r.RequestURI),
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrErr != nil {
|
||||||
|
fields = append(fields, zap.NamedError("write_response_error", wrErr))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Error(logs.RequestUnmatched, fields...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +217,7 @@ func bucketRouter(h Handler, log *zap.Logger) chi.Router {
|
||||||
|
|
||||||
bktRouter.Mount("/", objectRouter(h, log))
|
bktRouter.Mount("/", objectRouter(h, log))
|
||||||
|
|
||||||
bktRouter.Options("/", h.Preflight)
|
bktRouter.Options("/", named(s3middleware.OptionsBucketOperation, h.Preflight))
|
||||||
|
|
||||||
bktRouter.Head("/", named(s3middleware.HeadBucketOperation, h.HeadBucketHandler))
|
bktRouter.Head("/", named(s3middleware.HeadBucketOperation, h.HeadBucketHandler))
|
||||||
|
|
||||||
|
@ -353,6 +363,8 @@ func objectRouter(h Handler, l *zap.Logger) chi.Router {
|
||||||
objRouter := chi.NewRouter()
|
objRouter := chi.NewRouter()
|
||||||
objRouter.Use(s3middleware.AddObjectName(l))
|
objRouter.Use(s3middleware.AddObjectName(l))
|
||||||
|
|
||||||
|
objRouter.Options("/*", named(s3middleware.OptionsObjectOperation, h.Preflight))
|
||||||
|
|
||||||
objRouter.Head("/*", named(s3middleware.HeadObjectOperation, h.HeadObjectHandler))
|
objRouter.Head("/*", named(s3middleware.HeadObjectOperation, h.HeadObjectHandler))
|
||||||
|
|
||||||
// GET method handlers
|
// GET method handlers
|
||||||
|
|
|
@ -196,8 +196,10 @@ func TestPolicyChecker(t *testing.T) {
|
||||||
func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
|
func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
|
||||||
chiRouter := prepareRouter(t)
|
chiRouter := prepareRouter(t)
|
||||||
bktName, objName := "bucket", "object"
|
bktName, objName := "bucket", "object"
|
||||||
|
createBucket(chiRouter, "", bktName)
|
||||||
|
|
||||||
policy := engineiam.Policy{
|
policy := engineiam.Policy{
|
||||||
|
Version: "2012-10-17",
|
||||||
Statement: []engineiam.Statement{{
|
Statement: []engineiam.Statement{{
|
||||||
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||||
Effect: engineiam.AllowEffect,
|
Effect: engineiam.AllowEffect,
|
||||||
|
@ -269,7 +271,7 @@ func TestACLAPE(t *testing.T) {
|
||||||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
||||||
|
|
||||||
// Allow operations and check
|
// Allow operations and check
|
||||||
allowOperations(router, ns, []string{"s3:CreateBucket", "s3:ListBuckets"})
|
allowOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"})
|
||||||
createBucket(router, ns, bktName)
|
createBucket(router, ns, bktName)
|
||||||
listBuckets(router, ns)
|
listBuckets(router, ns)
|
||||||
})
|
})
|
||||||
|
@ -295,7 +297,7 @@ func TestACLAPE(t *testing.T) {
|
||||||
listBuckets(router, ns)
|
listBuckets(router, ns)
|
||||||
|
|
||||||
// Deny operations and check
|
// Deny operations and check
|
||||||
denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListBuckets"})
|
denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"})
|
||||||
createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied)
|
createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied)
|
||||||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
@ -353,6 +355,7 @@ func denyOperations(router *routerMock, ns string, operations []string) {
|
||||||
|
|
||||||
func addPolicy(router *routerMock, ns string, id string, effect engineiam.Effect, operations []string) {
|
func addPolicy(router *routerMock, ns string, id string, effect engineiam.Effect, operations []string) {
|
||||||
policy := engineiam.Policy{
|
policy := engineiam.Policy{
|
||||||
|
Version: "2012-10-17",
|
||||||
Statement: []engineiam.Statement{{
|
Statement: []engineiam.Statement{{
|
||||||
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||||
Effect: effect,
|
Effect: effect,
|
||||||
|
|
|
@ -82,11 +82,6 @@ type FrostFS interface {
|
||||||
TimeToEpoch(context.Context, time.Time) (uint64, uint64, error)
|
TimeToEpoch(context.Context, time.Time) (uint64, uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrostFSID represents interface to interact with frostfsid contract.
|
|
||||||
type FrostFSID interface {
|
|
||||||
RegisterPublicKey(ns string, key *keys.PublicKey) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Agent contains client communicating with FrostFS and logger.
|
// Agent contains client communicating with FrostFS and logger.
|
||||||
type Agent struct {
|
type Agent struct {
|
||||||
frostFS FrostFS
|
frostFS FrostFS
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -170,7 +170,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
if rpcAddress == "" {
|
if rpcAddress == "" {
|
||||||
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
||||||
}
|
}
|
||||||
cfg := frostfsid.Config{
|
cfg := contract.Config{
|
||||||
RPCAddress: rpcAddress,
|
RPCAddress: rpcAddress,
|
||||||
Contract: frostFSID,
|
Contract: frostFSID,
|
||||||
ProxyContract: viper.GetString(frostfsIDProxyFlag),
|
ProxyContract: viper.GetString(frostfsIDProxyFlag),
|
||||||
|
@ -182,7 +182,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return wrapFrostFSIDInitError(err)
|
return wrapFrostFSIDInitError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = frostfsIDClient.RegisterPublicKey(viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
|
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
|
||||||
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -106,7 +106,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
if rpcAddress == "" {
|
if rpcAddress == "" {
|
||||||
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
||||||
}
|
}
|
||||||
cfg := frostfsid.Config{
|
cfg := contract.Config{
|
||||||
RPCAddress: rpcAddress,
|
RPCAddress: rpcAddress,
|
||||||
Contract: frostFSID,
|
Contract: frostFSID,
|
||||||
ProxyContract: viper.GetString(frostfsIDProxyFlag),
|
ProxyContract: viper.GetString(frostfsIDProxyFlag),
|
||||||
|
@ -118,7 +118,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return wrapFrostFSIDInitError(err)
|
return wrapFrostFSIDInitError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = frostfsIDClient.RegisterPublicKey(viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
|
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
|
||||||
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
|
@ -145,10 +145,10 @@ func getLogger() *zap.Logger {
|
||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg frostfsid.Config) (authmate.FrostFSID, error) {
|
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg contract.Config) (*contract.FrostFSID, error) {
|
||||||
log.Debug(logs.PrepareFrostfsIDClient)
|
log.Debug(logs.PrepareFrostfsIDClient)
|
||||||
|
|
||||||
cli, err := frostfsid.New(ctx, cfg)
|
cli, err := contract.New(ctx, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,15 @@ func createFrostFSID(ctx context.Context, log *zap.Logger, cfg frostfsid.Config)
|
||||||
return cli, nil
|
return cli, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerPublicKey(cli *contract.FrostFSID, namespace string, key *keys.PublicKey) error {
|
||||||
|
err := cli.Wait(cli.CreateSubject(namespace, key))
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseObjectAttrs(attributes string) ([]object.Attribute, error) {
|
func parseObjectAttrs(attributes string) ([]object.Attribute, error) {
|
||||||
if len(attributes) == 0 {
|
if len(attributes) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
|
ffidcontract "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy/contract"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
||||||
|
@ -105,6 +106,9 @@ type (
|
||||||
defaultNamespaces []string
|
defaultNamespaces []string
|
||||||
authorizedControlAPIKeys [][]byte
|
authorizedControlAPIKeys [][]byte
|
||||||
policyDenyByDefault bool
|
policyDenyByDefault bool
|
||||||
|
retryMaxAttempts int
|
||||||
|
retryMaxBackoff time.Duration
|
||||||
|
retryStrategy handler.RetryStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
maxClientsConfig struct {
|
maxClientsConfig struct {
|
||||||
|
@ -230,6 +234,9 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger, key *keys.PrivateK
|
||||||
s.setMD5Enabled(v.GetBool(cfgMD5Enabled))
|
s.setMD5Enabled(v.GetBool(cfgMD5Enabled))
|
||||||
s.setAuthorizedControlAPIKeys(append(fetchAuthorizedKeys(log, v), key.PublicKey()))
|
s.setAuthorizedControlAPIKeys(append(fetchAuthorizedKeys(log, v), key.PublicKey()))
|
||||||
s.setPolicyDenyByDefault(v.GetBool(cfgPolicyDenyByDefault))
|
s.setPolicyDenyByDefault(v.GetBool(cfgPolicyDenyByDefault))
|
||||||
|
s.setRetryMaxAttempts(fetchRetryMaxAttempts(v))
|
||||||
|
s.setRetryMaxBackoff(fetchRetryMaxBackoff(v))
|
||||||
|
s.setRetryStrategy(fetchRetryStrategy(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *appSettings) updateNamespacesSettings(v *viper.Viper, log *zap.Logger) {
|
func (s *appSettings) updateNamespacesSettings(v *viper.Viper, log *zap.Logger) {
|
||||||
|
@ -424,6 +431,42 @@ func (s *appSettings) setPolicyDenyByDefault(policyDenyByDefault bool) {
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) setRetryMaxAttempts(maxAttempts int) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.retryMaxAttempts = maxAttempts
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) RetryMaxAttempts() int {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.retryMaxAttempts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) setRetryMaxBackoff(maxBackoff time.Duration) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.retryMaxBackoff = maxBackoff
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) RetryMaxBackoff() time.Duration {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.retryMaxBackoff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) setRetryStrategy(strategy handler.RetryStrategy) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.retryStrategy = strategy
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *appSettings) RetryStrategy() handler.RetryStrategy {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.retryStrategy
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) initAPI(ctx context.Context) {
|
func (a *App) initAPI(ctx context.Context) {
|
||||||
a.initLayer(ctx)
|
a.initLayer(ctx)
|
||||||
a.initHandler()
|
a.initHandler()
|
||||||
|
@ -453,8 +496,7 @@ func (a *App) initMetrics() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initFrostfsID(ctx context.Context) {
|
func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
var err error
|
cli, err := ffidcontract.New(ctx, ffidcontract.Config{
|
||||||
a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{
|
|
||||||
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||||
Contract: a.cfg.GetString(cfgFrostfsIDContract),
|
Contract: a.cfg.GetString(cfgFrostfsIDContract),
|
||||||
ProxyContract: a.cfg.GetString(cfgProxyContract),
|
ProxyContract: a.cfg.GetString(cfgProxyContract),
|
||||||
|
@ -463,6 +505,15 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.frostfsid, err = frostfsid.NewFrostFSID(frostfsid.Config{
|
||||||
|
Cache: cache.NewFrostfsIDCache(getFrostfsIDCacheConfig(a.cfg, a.log)),
|
||||||
|
FrostFSID: cli,
|
||||||
|
Logger: a.log,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initPolicyStorage(ctx context.Context) {
|
func (a *App) initPolicyStorage(ctx context.Context) {
|
||||||
|
@ -950,6 +1001,15 @@ func getMorphPolicyCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
return cacheCfg
|
return cacheCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getFrostfsIDCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
|
cacheCfg := cache.DefaultFrostfsIDConfig(l)
|
||||||
|
|
||||||
|
cacheCfg.Lifetime = fetchCacheLifetime(v, l, cfgFrostfsIDCacheLifetime, cacheCfg.Lifetime)
|
||||||
|
cacheCfg.Size = fetchCacheSize(v, l, cfgFrostfsIDCacheSize, cacheCfg.Size)
|
||||||
|
|
||||||
|
return cacheCfg
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) initHandler() {
|
func (a *App) initHandler() {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,10 @@ const (
|
||||||
defaultConstraintName = "default"
|
defaultConstraintName = "default"
|
||||||
|
|
||||||
defaultNamespace = ""
|
defaultNamespace = ""
|
||||||
|
|
||||||
|
defaultRetryMaxAttempts = 4
|
||||||
|
defaultRetryMaxBackoff = 30 * time.Second
|
||||||
|
defaultRetryStrategy = handler.RetryStrategyExponential
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -114,6 +118,8 @@ const ( // Settings.
|
||||||
cfgAccessControlCacheSize = "cache.accesscontrol.size"
|
cfgAccessControlCacheSize = "cache.accesscontrol.size"
|
||||||
cfgMorphPolicyCacheLifetime = "cache.morph_policy.lifetime"
|
cfgMorphPolicyCacheLifetime = "cache.morph_policy.lifetime"
|
||||||
cfgMorphPolicyCacheSize = "cache.morph_policy.size"
|
cfgMorphPolicyCacheSize = "cache.morph_policy.size"
|
||||||
|
cfgFrostfsIDCacheLifetime = "cache.frostfsid.lifetime"
|
||||||
|
cfgFrostfsIDCacheSize = "cache.frostfsid.size"
|
||||||
|
|
||||||
cfgAccessBoxCacheRemovingCheckInterval = "cache.accessbox.removing_check_interval"
|
cfgAccessBoxCacheRemovingCheckInterval = "cache.accessbox.removing_check_interval"
|
||||||
|
|
||||||
|
@ -174,6 +180,11 @@ const ( // Settings.
|
||||||
cfgWebWriteTimeout = "web.write_timeout"
|
cfgWebWriteTimeout = "web.write_timeout"
|
||||||
cfgWebIdleTimeout = "web.idle_timeout"
|
cfgWebIdleTimeout = "web.idle_timeout"
|
||||||
|
|
||||||
|
// Retry.
|
||||||
|
cfgRetryMaxAttempts = "retry.max_attempts"
|
||||||
|
cfgRetryMaxBackoff = "retry.max_backoff"
|
||||||
|
cfgRetryStrategy = "retry.strategy"
|
||||||
|
|
||||||
// Namespaces.
|
// Namespaces.
|
||||||
cfgNamespacesConfig = "namespaces.config"
|
cfgNamespacesConfig = "namespaces.config"
|
||||||
|
|
||||||
|
@ -307,6 +318,33 @@ func fetchSoftMemoryLimit(cfg *viper.Viper) int64 {
|
||||||
return int64(softMemoryLimit)
|
return int64(softMemoryLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchRetryMaxAttempts(cfg *viper.Viper) int {
|
||||||
|
val := cfg.GetInt(cfgRetryMaxAttempts)
|
||||||
|
if val <= 0 {
|
||||||
|
val = defaultRetryMaxAttempts
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchRetryMaxBackoff(cfg *viper.Viper) time.Duration {
|
||||||
|
val := cfg.GetDuration(cfgRetryMaxBackoff)
|
||||||
|
if val <= 0 {
|
||||||
|
val = defaultRetryMaxBackoff
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchRetryStrategy(cfg *viper.Viper) handler.RetryStrategy {
|
||||||
|
val := handler.RetryStrategy(cfg.GetString(cfgRetryStrategy))
|
||||||
|
if val != handler.RetryStrategyExponential && val != handler.RetryStrategyConstant {
|
||||||
|
val = defaultRetryStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
func fetchDefaultPolicy(l *zap.Logger, cfg *viper.Viper) netmap.PlacementPolicy {
|
func fetchDefaultPolicy(l *zap.Logger, cfg *viper.Viper) netmap.PlacementPolicy {
|
||||||
var policy netmap.PlacementPolicy
|
var policy netmap.PlacementPolicy
|
||||||
|
|
||||||
|
@ -735,6 +773,10 @@ func newSettings() *viper.Viper {
|
||||||
// resolve
|
// resolve
|
||||||
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
||||||
|
|
||||||
|
// retry
|
||||||
|
v.SetDefault(cfgRetryMaxAttempts, defaultRetryMaxAttempts)
|
||||||
|
v.SetDefault(cfgRetryMaxBackoff, defaultRetryMaxBackoff)
|
||||||
|
|
||||||
// Bind flags
|
// Bind flags
|
||||||
if err := bindFlags(v, flags); err != nil {
|
if err := bindFlags(v, flags); err != nil {
|
||||||
panic(fmt.Errorf("bind flags: %w", err))
|
panic(fmt.Errorf("bind flags: %w", err))
|
||||||
|
|
|
@ -104,6 +104,9 @@ S3_GW_CACHE_ACCESSCONTROL_SIZE=100000
|
||||||
# Cache which stores list of policy chains
|
# Cache which stores list of policy chains
|
||||||
S3_GW_CACHE_MORPH_POLICY_LIFETIME=1m
|
S3_GW_CACHE_MORPH_POLICY_LIFETIME=1m
|
||||||
S3_GW_CACHE_MORPH_POLICY_SIZE=10000
|
S3_GW_CACHE_MORPH_POLICY_SIZE=10000
|
||||||
|
# Cache which stores frostfsid subject info
|
||||||
|
S3_GW_CACHE_FROSTFSID_LIFETIME=1m
|
||||||
|
S3_GW_CACHE_FROSTFSID_SIZE=10000
|
||||||
|
|
||||||
# NATS
|
# NATS
|
||||||
S3_GW_NATS_ENABLED=true
|
S3_GW_NATS_ENABLED=true
|
||||||
|
@ -214,3 +217,12 @@ S3_GW_PROXY_CONTRACT=proxy.frostfs
|
||||||
|
|
||||||
# Namespaces configuration
|
# Namespaces configuration
|
||||||
S3_GW_NAMESPACES_CONFIG=namespaces.json
|
S3_GW_NAMESPACES_CONFIG=namespaces.json
|
||||||
|
|
||||||
|
# Retry strategy configuration.
|
||||||
|
# Max amount of request attempts. Currently only for updating bucket settings request.
|
||||||
|
S3_GW_RETRY_MAX_ATTEMPTS=4
|
||||||
|
# Max delay before next attempt.
|
||||||
|
S3_GW_RETRY_MAX_BACKOFF=30s
|
||||||
|
# Backoff strategy. `exponential` and `constant` are allowed.
|
||||||
|
S3_GW_RETRY_STRATEGY=exponential
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,10 @@ cache:
|
||||||
morph_policy:
|
morph_policy:
|
||||||
lifetime: 1m
|
lifetime: 1m
|
||||||
size: 10000
|
size: 10000
|
||||||
|
# Cache which stores frostfsid subject info
|
||||||
|
frostfsid:
|
||||||
|
lifetime: 1m
|
||||||
|
size: 10000
|
||||||
|
|
||||||
nats:
|
nats:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
@ -253,3 +257,12 @@ proxy:
|
||||||
|
|
||||||
namespaces:
|
namespaces:
|
||||||
config: namespaces.json
|
config: namespaces.json
|
||||||
|
|
||||||
|
# Retry strategy configuration.
|
||||||
|
retry:
|
||||||
|
# Max amount of request attempts. Currently only for updating bucket settings request.
|
||||||
|
max_attempts: 4
|
||||||
|
# Max delay before next attempt.
|
||||||
|
max_backoff: 30s
|
||||||
|
# Backoff strategy. `exponential` and `constant` are allowed.
|
||||||
|
strategy: exponential
|
||||||
|
|
|
@ -1,73 +1,58 @@
|
||||||
# S3 API support
|
# S3 API support
|
||||||
|
|
||||||
Reference:
|
Reference:
|
||||||
|
|
||||||
* [AWS S3 API Reference](https://docs.aws.amazon.com/AmazonS3/latest/API/s3-api.pdf)
|
* [AWS S3 API Reference](https://docs.aws.amazon.com/AmazonS3/latest/API/s3-api.pdf)
|
||||||
|
|
||||||
| | Legend |
|
| | Legend |
|
||||||
|----|-------------------------------------------|
|
|-----|-------------------------------------------|
|
||||||
| 🟢 | Supported |
|
| 🟢 | Supported |
|
||||||
| 🟡 | Partially supported |
|
| 🟡 | Partially supported |
|
||||||
| 🔵 | Not supported yet, but will be in future |
|
| 🔵 | Not supported yet, but will be in future |
|
||||||
| 🔴 | Not applicable or will never be supported |
|
| 🔴 | Not applicable or will never be supported |
|
||||||
|
|
||||||
## Object
|
## Object
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------------|-----------------------------------------|
|
|-----|------------------------|-----------------------------------------|
|
||||||
| 🟢 | CopyObject | Done on gateway side |
|
| 🟢 | CopyObject | Done on gateway side |
|
||||||
| 🟢 | DeleteObject | |
|
| 🟢 | DeleteObject | |
|
||||||
| 🟢 | DeleteObjects | aka DeleteMultipleObjects |
|
| 🟢 | DeleteObjects | aka DeleteMultipleObjects |
|
||||||
| 🟢 | GetObject | |
|
| 🟢 | GetObject | |
|
||||||
| 🔴 | GetObjectTorrent | We don't plan implementing BT gateway |
|
| 🔴 | GetObjectTorrent | We don't plan implementing BT gateway |
|
||||||
| 🟢 | HeadObject | |
|
| 🟢 | HeadObject | |
|
||||||
| 🟢 | ListParts | Parts loaded with MultipartUpload |
|
| 🟢 | ListParts | Parts loaded with MultipartUpload |
|
||||||
| 🟢 | ListObjects | |
|
| 🟢 | ListObjects | |
|
||||||
| 🟢 | ListObjectsV2 | |
|
| 🟢 | ListObjectsV2 | |
|
||||||
| 🟢 | PutObject | Content-MD5 header deprecated |
|
| 🟢 | PutObject | Content-MD5 header deprecated |
|
||||||
| 🔵 | SelectObjectContent | Need to have some Lambda to execute SQL |
|
| 🔵 | SelectObjectContent | Need to have some Lambda to execute SQL |
|
||||||
| 🔵 | WriteGetObjectResponse | Waiting for Lambda to be developed |
|
| 🔵 | WriteGetObjectResponse | Waiting for Lambda to be developed |
|
||||||
| 🟢 | GetObjectAttributes | |
|
| 🟢 | GetObjectAttributes | |
|
||||||
|
|
||||||
## ACL
|
## ACL
|
||||||
|
|
||||||
For now there are some limitations:
|
For now there are some limitations:
|
||||||
* [Bucket policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html) supports only one `Principal` per `Statement`.
|
|
||||||
Principal must be `"AWS": "*"` (to refer all users) or `"CanonicalUser": "0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf"` (hex encoded public key of desired user).
|
|
||||||
* Resource in bucket policy is an array. Each item MUST contain bucket name, CAN contain object name (wildcards are not supported):
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Resource": [
|
|
||||||
"arn:aws:s3:::bucket",
|
|
||||||
"arn:aws:s3:::bucket/some/object"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* AWS conditions and wildcard are not supported in [resources](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-arn-format.html)
|
|
||||||
* Only `CanonicalUser` (with hex encoded public key) and `All Users Group` are supported in [ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html)
|
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|--------------|-----------------|
|
|-----|--------------|-----------------------------------|
|
||||||
| 🟡 | GetObjectAcl | See Limitations |
|
| 🟢 | GetObjectAcl | Objects can have only private acl |
|
||||||
| 🟡 | PutObjectAcl | See Limitations |
|
| 🔴 | PutObjectAcl | Use PutBucketPolicy instead |
|
||||||
|
|
||||||
## Locking
|
## Locking
|
||||||
|
|
||||||
For now there are some limitations:
|
For now there are some limitations:
|
||||||
|
|
||||||
* Retention period can't be shortened, only extended.
|
* Retention period can't be shortened, only extended.
|
||||||
* You can't delete locks or object with unexpired lock.
|
* You can't delete locks or object with unexpired lock.
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|-----|----------------------------|---------------------------|
|
|-----|----------------------------|-------------------------------|
|
||||||
| 🟡 | GetObjectLegalHold | |
|
| 🟡 | GetObjectLegalHold | |
|
||||||
| 🟢 | GetObjectLockConfiguration | GetBucketObjectLockConfig |
|
| 🟢 | GetObjectLockConfiguration | aka GetBucketObjectLockConfig |
|
||||||
| 🟡 | GetObjectRetention | |
|
| 🟡 | GetObjectRetention | |
|
||||||
| 🟡 | PutObjectLegalHold | |
|
| 🟡 | PutObjectLegalHold | |
|
||||||
| 🟢 | PutObjectLockConfiguration | PutBucketObjectLockConfig |
|
| 🟢 | PutObjectLockConfiguration | aka PutBucketObjectLockConfig |
|
||||||
| 🟡 | PutObjectRetention | |
|
| 🟡 | PutObjectRetention | |
|
||||||
|
|
||||||
## Multipart
|
## Multipart
|
||||||
|
|
||||||
|
@ -75,185 +60,185 @@ CompleteMultipartUpload operations may take long time to complete. Gateway
|
||||||
sends whitespace characters to keep connection with the client alive. In this
|
sends whitespace characters to keep connection with the client alive. In this
|
||||||
case, gateway is unable to set proper HTTP headers like `X-Amz-Version-Id`.
|
case, gateway is unable to set proper HTTP headers like `X-Amz-Version-Id`.
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|-------------------------|----------|
|
|-----|-------------------------|----------|
|
||||||
| 🟢 | AbortMultipartUpload | |
|
| 🟢 | AbortMultipartUpload | |
|
||||||
| 🟢 | CompleteMultipartUpload | |
|
| 🟢 | CompleteMultipartUpload | |
|
||||||
| 🟢 | CreateMultipartUpload | |
|
| 🟢 | CreateMultipartUpload | |
|
||||||
| 🟢 | ListMultipartUploads | |
|
| 🟢 | ListMultipartUploads | |
|
||||||
| 🟢 | ListParts | |
|
| 🟢 | ListParts | |
|
||||||
| 🟢 | UploadPart | |
|
| 🟢 | UploadPart | |
|
||||||
| 🟢 | UploadPartCopy | |
|
| 🟢 | UploadPartCopy | |
|
||||||
|
|
||||||
## Tagging
|
## Tagging
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------|----------|
|
|-----|---------------------|----------|
|
||||||
| 🟢 | DeleteObjectTagging | |
|
| 🟢 | DeleteObjectTagging | |
|
||||||
| 🟢 | GetObjectTagging | |
|
| 🟢 | GetObjectTagging | |
|
||||||
| 🟢 | PutObjectTagging | |
|
| 🟢 | PutObjectTagging | |
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
See also `GetObject` and other method parameters.
|
See also `GetObject` and other method parameters.
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|--------------------|--------------------------|
|
|-----|--------------------|--------------------------|
|
||||||
| 🟢 | ListObjectVersions | ListBucketObjectVersions |
|
| 🟢 | ListObjectVersions | ListBucketObjectVersions |
|
||||||
| 🔵 | RestoreObject | |
|
| 🔵 | RestoreObject | |
|
||||||
|
|
||||||
## Bucket
|
## Bucket
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|----------------------|-----------|
|
|-----|----------------------|-----------|
|
||||||
| 🟢 | CreateBucket | PutBucket |
|
| 🟢 | CreateBucket | PutBucket |
|
||||||
| 🟢 | DeleteBucket | |
|
| 🟢 | DeleteBucket | |
|
||||||
| 🟢 | GetBucketLocation | |
|
| 🟢 | GetBucketLocation | |
|
||||||
| 🟢 | HeadBucket | |
|
| 🟢 | HeadBucket | |
|
||||||
| 🟢 | ListBuckets | |
|
| 🟢 | ListBuckets | |
|
||||||
| 🔵 | PutPublicAccessBlock | |
|
| 🔵 | PutPublicAccessBlock | |
|
||||||
|
|
||||||
## Acceleration
|
## Acceleration
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|----------------------------------|---------------------|
|
|-----|----------------------------------|---------------------|
|
||||||
| 🔴 | GetBucketAccelerateConfiguration | GetBucketAccelerate |
|
| 🔴 | GetBucketAccelerateConfiguration | GetBucketAccelerate |
|
||||||
| 🔴 | PutBucketAccelerateConfiguration | |
|
| 🔴 | PutBucketAccelerateConfiguration | |
|
||||||
|
|
||||||
## ACL
|
## ACL
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|--------------|---------------------|
|
|-----|--------------|------------------------------|
|
||||||
| 🟡 | GetBucketAcl | See ACL limitations |
|
| 🟡 | GetBucketAcl | Only canned acl is supported |
|
||||||
| 🟡 | PutBucketAcl | See ACL Limitations |
|
| 🟡 | PutBucketAcl | Only canned acl is supported |
|
||||||
|
|
||||||
## Analytics
|
## Analytics
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------------------------|----------|
|
|-----|------------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketAnalyticsConfiguration | |
|
| 🔵 | DeleteBucketAnalyticsConfiguration | |
|
||||||
| 🔵 | GetBucketAnalyticsConfiguration | |
|
| 🔵 | GetBucketAnalyticsConfiguration | |
|
||||||
| 🔵 | ListBucketAnalyticsConfigurations | |
|
| 🔵 | ListBucketAnalyticsConfigurations | |
|
||||||
| 🔵 | PutBucketAnalyticsConfiguration | |
|
| 🔵 | PutBucketAnalyticsConfiguration | |
|
||||||
|
|
||||||
## CORS
|
## CORS
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------|----------|
|
|-----|------------------|----------|
|
||||||
| 🟢 | DeleteBucketCors | |
|
| 🟢 | DeleteBucketCors | |
|
||||||
| 🟢 | GetBucketCors | |
|
| 🟢 | GetBucketCors | |
|
||||||
| 🟢 | PutBucketCors | |
|
| 🟢 | PutBucketCors | |
|
||||||
|
|
||||||
## Encryption
|
## Encryption
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------------|----------|
|
|-----|------------------------|----------|
|
||||||
| 🔵 | DeleteBucketEncryption | |
|
| 🔵 | DeleteBucketEncryption | |
|
||||||
| 🔵 | GetBucketEncryption | |
|
| 🔵 | GetBucketEncryption | |
|
||||||
| 🔵 | PutBucketEncryption | |
|
| 🔵 | PutBucketEncryption | |
|
||||||
|
|
||||||
## Inventory
|
## Inventory
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------------------------|----------|
|
|-----|------------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketInventoryConfiguration | |
|
| 🔵 | DeleteBucketInventoryConfiguration | |
|
||||||
| 🔵 | GetBucketInventoryConfiguration | |
|
| 🔵 | GetBucketInventoryConfiguration | |
|
||||||
| 🔵 | ListBucketInventoryConfigurations | |
|
| 🔵 | ListBucketInventoryConfigurations | |
|
||||||
| 🔵 | PutBucketInventoryConfiguration | |
|
| 🔵 | PutBucketInventoryConfiguration | |
|
||||||
|
|
||||||
## Lifecycle
|
## Lifecycle
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------------------|----------|
|
|-----|---------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketLifecycle | |
|
| 🔵 | DeleteBucketLifecycle | |
|
||||||
| 🔵 | GetBucketLifecycle | |
|
| 🔵 | GetBucketLifecycle | |
|
||||||
| 🔵 | GetBucketLifecycleConfiguration | |
|
| 🔵 | GetBucketLifecycleConfiguration | |
|
||||||
| 🔵 | PutBucketLifecycle | |
|
| 🔵 | PutBucketLifecycle | |
|
||||||
| 🔵 | PutBucketLifecycleConfiguration | |
|
| 🔵 | PutBucketLifecycleConfiguration | |
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------|----------|
|
|-----|------------------|----------|
|
||||||
| 🔵 | GetBucketLogging | |
|
| 🔵 | GetBucketLogging | |
|
||||||
| 🔵 | PutBucketLogging | |
|
| 🔵 | PutBucketLogging | |
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|----------------------------------|----------|
|
|-----|----------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketMetricsConfiguration | |
|
| 🔵 | DeleteBucketMetricsConfiguration | |
|
||||||
| 🔵 | GetBucketMetricsConfiguration | |
|
| 🔵 | GetBucketMetricsConfiguration | |
|
||||||
| 🔵 | ListBucketMetricsConfigurations | |
|
| 🔵 | ListBucketMetricsConfigurations | |
|
||||||
| 🔵 | PutBucketMetricsConfiguration | |
|
| 🔵 | PutBucketMetricsConfiguration | |
|
||||||
|
|
||||||
## Notifications
|
## Notifications
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|------------------------------------|---------------|
|
|-----|------------------------------------|---------------|
|
||||||
| 🔵 | GetBucketNotification | |
|
| 🔵 | GetBucketNotification | |
|
||||||
| 🔵 | GetBucketNotificationConfiguration | |
|
| 🔵 | GetBucketNotificationConfiguration | |
|
||||||
| 🔵 | ListenBucketNotification | non-standard? |
|
| 🔵 | ListenBucketNotification | non-standard? |
|
||||||
| 🔵 | PutBucketNotification | |
|
| 🔵 | PutBucketNotification | |
|
||||||
| 🔵 | PutBucketNotificationConfiguration | |
|
| 🔵 | PutBucketNotificationConfiguration | |
|
||||||
|
|
||||||
## Ownership controls
|
## Ownership controls
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|-------------------------------|----------|
|
|-----|-------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketOwnershipControls | |
|
| 🔵 | DeleteBucketOwnershipControls | |
|
||||||
| 🔵 | GetBucketOwnershipControls | |
|
| 🔵 | GetBucketOwnershipControls | |
|
||||||
| 🔵 | PutBucketOwnershipControls | |
|
| 🔵 | PutBucketOwnershipControls | |
|
||||||
|
|
||||||
## Policy and replication
|
## Policy and replication
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|-------------------------|-----------------------------|
|
|-----|-------------------------|------------------------------|
|
||||||
| 🔵 | DeleteBucketPolicy | |
|
| 🟢 | DeleteBucketPolicy | |
|
||||||
| 🔵 | DeleteBucketReplication | |
|
| 🔵 | DeleteBucketReplication | |
|
||||||
| 🔵 | DeletePublicAccessBlock | |
|
| 🔵 | DeletePublicAccessBlock | |
|
||||||
| 🟡 | GetBucketPolicy | See ACL limitations |
|
| 🟢 | GetBucketPolicy | |
|
||||||
| 🔵 | GetBucketPolicyStatus | |
|
| 🔵 | GetBucketPolicyStatus | |
|
||||||
| 🔵 | GetBucketReplication | |
|
| 🔵 | GetBucketReplication | |
|
||||||
| 🟢 | PostPolicyBucket | Upload file using POST form |
|
| 🟢 | PostPolicyBucket | Upload file using POST form |
|
||||||
| 🟡 | PutBucketPolicy | See ACL limitations |
|
| 🟡 | PutBucketPolicy | Conditions are not supported |
|
||||||
| 🔵 | PutBucketReplication | |
|
| 🔵 | PutBucketReplication | |
|
||||||
|
|
||||||
## Request payment
|
## Request payment
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|-------------------------|----------|
|
|-----|-------------------------|----------|
|
||||||
| 🔴 | GetBucketRequestPayment | |
|
| 🔴 | GetBucketRequestPayment | |
|
||||||
| 🔴 | PutBucketRequestPayment | |
|
| 🔴 | PutBucketRequestPayment | |
|
||||||
|
|
||||||
## Tagging
|
## Tagging
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------|----------|
|
|-----|---------------------|----------|
|
||||||
| 🟢 | DeleteBucketTagging | |
|
| 🟢 | DeleteBucketTagging | |
|
||||||
| 🟢 | GetBucketTagging | |
|
| 🟢 | GetBucketTagging | |
|
||||||
| 🟢 | PutBucketTagging | |
|
| 🟢 | PutBucketTagging | |
|
||||||
|
|
||||||
## Tiering
|
## Tiering
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------------------------------|----------|
|
|-----|---------------------------------------------|----------|
|
||||||
| 🔵 | DeleteBucketIntelligentTieringConfiguration | |
|
| 🔵 | DeleteBucketIntelligentTieringConfiguration | |
|
||||||
| 🔵 | GetBucketIntelligentTieringConfiguration | |
|
| 🔵 | GetBucketIntelligentTieringConfiguration | |
|
||||||
| 🔵 | ListBucketIntelligentTieringConfigurations | |
|
| 🔵 | ListBucketIntelligentTieringConfigurations | |
|
||||||
| 🔵 | PutBucketIntelligentTieringConfiguration | |
|
| 🔵 | PutBucketIntelligentTieringConfiguration | |
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------|----------|
|
|-----|---------------------|----------|
|
||||||
| 🟢 | GetBucketVersioning | |
|
| 🟢 | GetBucketVersioning | |
|
||||||
| 🟢 | PutBucketVersioning | |
|
| 🟢 | PutBucketVersioning | |
|
||||||
|
|
||||||
## Website
|
## Website
|
||||||
|
|
||||||
| | Method | Comments |
|
| | Method | Comments |
|
||||||
|----|---------------------|----------|
|
|-----|---------------------|----------|
|
||||||
| 🔵 | DeleteBucketWebsite | |
|
| 🔵 | DeleteBucketWebsite | |
|
||||||
| 🔵 | GetBucketWebsite | |
|
| 🔵 | GetBucketWebsite | |
|
||||||
| 🔵 | PutBucketWebsite | |
|
| 🔵 | PutBucketWebsite | |
|
||||||
|
|
|
@ -193,6 +193,7 @@ There are some custom types used for brevity:
|
||||||
| `policy` | [Policy contract configuration](#policy-section) |
|
| `policy` | [Policy contract configuration](#policy-section) |
|
||||||
| `proxy` | [Proxy contract configuration](#proxy-section) |
|
| `proxy` | [Proxy contract configuration](#proxy-section) |
|
||||||
| `namespaces` | [Namespaces configuration](#namespaces-section) |
|
| `namespaces` | [Namespaces configuration](#namespaces-section) |
|
||||||
|
| `retry` | [Retry configuration](#retry-section) |
|
||||||
|
|
||||||
### General section
|
### General section
|
||||||
|
|
||||||
|
@ -418,6 +419,9 @@ cache:
|
||||||
morph_policy:
|
morph_policy:
|
||||||
lifetime: 30s
|
lifetime: 30s
|
||||||
size: 10000
|
size: 10000
|
||||||
|
frostfsid:
|
||||||
|
lifetime: 1m
|
||||||
|
size: 10000
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Type | Default value | Description |
|
| Parameter | Type | Default value | Description |
|
||||||
|
@ -431,6 +435,7 @@ cache:
|
||||||
| `accessbox` | [Accessbox cache config](#accessbox-subsection) | `lifetime: 10m`<br>`size: 100` | Cache which stores access box with tokens by its address. |
|
| `accessbox` | [Accessbox cache config](#accessbox-subsection) | `lifetime: 10m`<br>`size: 100` | Cache which stores access box with tokens by its address. |
|
||||||
| `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 100000` | Cache which stores owner to cache operation mapping. |
|
| `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 100000` | Cache which stores owner to cache operation mapping. |
|
||||||
| `morph_policy` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores list of policy chains. |
|
| `morph_policy` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores list of policy chains. |
|
||||||
|
| `frostfsid` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores FrostfsID subject info. |
|
||||||
|
|
||||||
#### `cache` subsection
|
#### `cache` subsection
|
||||||
|
|
||||||
|
@ -731,3 +736,21 @@ To override config values for default namespaces use namespace names that are pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# `retry` section
|
||||||
|
|
||||||
|
Retry strategy configuration.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
retry:
|
||||||
|
max_attempts: 4
|
||||||
|
max_backoff: 30s
|
||||||
|
strategy: exponential
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|
|---------------|------------|---------------|---------------|--------------------------------------------------------------------------------------|
|
||||||
|
| `max_attemps` | `int` | yes | `4` | Max amount of request attempts. Currently only for updating bucket settings request. |
|
||||||
|
| `max_backoff` | `duration` | yes | `30s` | Max delay before next attempt. |
|
||||||
|
| `strategy` | `string` | yes | `exponential` | Backoff strategy. `exponential` and `constant` are allowed. |
|
||||||
|
|
||||||
|
|
69
go.mod
69
go.mod
|
@ -1,37 +1,38 @@
|
||||||
module git.frostfs.info/TrueCloudLab/frostfs-s3-gw
|
module git.frostfs.info/TrueCloudLab/frostfs-s3-gw
|
||||||
|
|
||||||
go 1.20
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240717110908-4e13f713f156
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718142345-fba909b12ec6
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240226094215-c960b1b08831
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240412130734-0e69e485115a
|
||||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
||||||
github.com/aws/aws-sdk-go v1.44.6
|
github.com/aws/aws-sdk-go v1.44.6
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.18.1
|
||||||
github.com/bluele/gcache v0.0.2
|
github.com/bluele/gcache v0.0.2
|
||||||
github.com/go-chi/chi/v5 v5.0.8
|
github.com/go-chi/chi/v5 v5.0.8
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.6.0
|
||||||
github.com/minio/sio v0.3.0
|
github.com/minio/sio v0.3.0
|
||||||
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d
|
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d
|
||||||
github.com/nspcc-dev/neo-go v0.104.1-0.20231206061802-441eb8aa86be
|
github.com/nspcc-dev/neo-go v0.106.2
|
||||||
github.com/panjf2000/ants/v2 v2.5.0
|
github.com/panjf2000/ants/v2 v2.5.0
|
||||||
github.com/prometheus/client_golang v1.15.1
|
github.com/prometheus/client_golang v1.19.0
|
||||||
github.com/prometheus/client_model v0.3.0
|
github.com/prometheus/client_model v0.5.0
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.15.0
|
github.com/spf13/viper v1.15.0
|
||||||
github.com/ssgreg/journald v1.0.0
|
github.com/ssgreg/journald v1.0.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
github.com/urfave/cli/v2 v2.3.0
|
||||||
go.opentelemetry.io/otel v1.16.0
|
go.opentelemetry.io/otel v1.16.0
|
||||||
go.opentelemetry.io/otel/trace v1.16.0
|
go.opentelemetry.io/otel/trace v1.16.0
|
||||||
go.uber.org/zap v1.26.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.25.0
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
|
||||||
google.golang.org/grpc v1.59.0
|
google.golang.org/grpc v1.62.0
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.34.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -40,6 +41,7 @@ require (
|
||||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
|
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
|
||||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 // indirect
|
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||||
|
github.com/aws/smithy-go v1.13.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
@ -49,37 +51,38 @@ require (
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.2.4 // indirect
|
github.com/go-logr/logr v1.2.4 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.1 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
|
||||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
|
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mailru/easyjson v0.7.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/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||||
github.com/nats-io/nats-server/v2 v2.7.1 // indirect
|
github.com/nats-io/nats-server/v2 v2.7.1 // indirect
|
||||||
github.com/nats-io/nkeys v0.3.0 // indirect
|
github.com/nats-io/nkeys v0.3.0 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c // 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-20231127165613-b35f351f0ba0 // indirect
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
|
github.com/nspcc-dev/rfc6979 v0.2.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/common v0.42.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
github.com/prometheus/procfs v0.9.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/spf13/afero v1.9.3 // indirect
|
github.com/spf13/afero v1.9.3 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
||||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||||
github.com/urfave/cli v1.22.5 // indirect
|
github.com/urfave/cli v1.22.5 // indirect
|
||||||
|
go.etcd.io/bbolt v1.3.9 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // 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 v1.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
|
||||||
|
@ -88,14 +91,14 @@ require (
|
||||||
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.27.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/term v0.13.0 // indirect
|
golang.org/x/term v0.22.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
200
go.sum
200
go.sum
|
@ -36,20 +36,20 @@ 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.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02 h1:SAoUNpK1KBcY9NwP3ZZwDMXB5bvGCQiHxpXCw6wdpAI=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240717110908-4e13f713f156 h1:sZ0XjBmCKP0W/p9ncP3UnGOvipKBfKq+EGwnEIi1+vQ=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240717110908-4e13f713f156/go.mod h1:+HRxsiuD0fZ1927c8MPqPD2BdDoJYmuJOC4pMqwJ9rE=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b h1:zdbOxyqkxRyOLc7/2oNFu5tBwwg0Q6+0tJM3RkAxHlE=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd h1:fujTUMMn0wnpEKNDWLejFL916EPuaYD1MdZpk1ZokU8=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b/go.mod h1:YMFtNZy2MgeiSwt0t8lqk8dYBGzlbhmV1cbbstJJ6oY=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
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-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||||
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 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-observability v0.0.0-20230531082742-c97d21411eb6/go.mod h1:W8Nn08/l6aQ7UlIbpF7FsQou7TVpcRD1ZT1KG4TrFhE=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b h1:nLIWYXe4e1fWgpKeMfVke/CNBn388egh4fArFdvhfHw=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718142345-fba909b12ec6 h1:WaxISIkMtT399B3qI91R33FH672xTMeH8gLo2ngGuvM=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b/go.mod h1:XcgrbZ88XfvhAMxmZCQJ0dv6FyRSq6Mg2J7nN8uuO0k=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718142345-fba909b12ec6/go.mod h1:G6+uqTZcnyOrz43wj5qeG1XRQ31Io/x2Y7gT1tspLbI=
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
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/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240226094215-c960b1b08831 h1:yK2iGQlg5kMmU47ZHor/g52mVS1xEgJSRQ4Olp76Cg8=
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240412130734-0e69e485115a h1:wbndKvHbwDQiSMQWL75RxiTZCeUyCi7NUj1lsfdAGkc=
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240226094215-c960b1b08831/go.mod h1:YVL7yFaT0QNSpA0z+RHudLvrLwT+lsFYGyBSVc1ustI=
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240412130734-0e69e485115a/go.mod h1:H/AW85RtYxVTbcgwHW76DqXeKlsiCIOeNXHPqyDBrfQ=
|
||||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
|
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/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
|
||||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=
|
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=
|
||||||
|
@ -64,8 +64,14 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||||
github.com/aws/aws-sdk-go v1.44.6 h1:Y+uHxmZfhRTLX2X3khkdxCoTZAyGEX21aOUHe1U6geg=
|
github.com/aws/aws-sdk-go v1.44.6 h1:Y+uHxmZfhRTLX2X3khkdxCoTZAyGEX21aOUHe1U6geg=
|
||||||
github.com/aws/aws-sdk-go v1.44.6/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.44.6/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||||
|
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||||
|
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
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/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
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/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
|
@ -87,6 +93,10 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/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-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
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/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-20190314233015-f79a8a8ca69d/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 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
@ -104,6 +114,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.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/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
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=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
@ -119,7 +132,8 @@ 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-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
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.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
|
||||||
|
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -146,9 +160,10 @@ 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.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
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.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
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/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
@ -162,7 +177,9 @@ github.com/google/go-cmp v0.5.2/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.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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
@ -178,25 +195,26 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
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 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
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/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-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
@ -211,26 +229,31 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
||||||
|
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
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.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
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/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
|
github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
|
||||||
|
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||||
github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus=
|
github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus=
|
||||||
github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw=
|
github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
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/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
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/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
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/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 h1:vU9tpM3apjYlLLeY23zRWJ9Zktr5jp+mloR942LEOpY=
|
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 h1:vU9tpM3apjYlLLeY23zRWJ9Zktr5jp+mloR942LEOpY=
|
||||||
|
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
||||||
github.com/nats-io/nats-server/v2 v2.7.1 h1:SDj8R0PJPVekw3EgHxGtTfJUuMbsuaul1nwWFI3xTyk=
|
github.com/nats-io/nats-server/v2 v2.7.1 h1:SDj8R0PJPVekw3EgHxGtTfJUuMbsuaul1nwWFI3xTyk=
|
||||||
github.com/nats-io/nats-server/v2 v2.7.1/go.mod h1:tckmrt0M6bVaDT3kmh9UrIq/CBOBBse+TpXQi5ldaa8=
|
github.com/nats-io/nats-server/v2 v2.7.1/go.mod h1:tckmrt0M6bVaDT3kmh9UrIq/CBOBBse+TpXQi5ldaa8=
|
||||||
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d h1:GRSmEJutHkdoxKsRypP575IIdoXe7Bm6yHQF6GcDBnA=
|
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d h1:GRSmEJutHkdoxKsRypP575IIdoXe7Bm6yHQF6GcDBnA=
|
||||||
|
@ -239,14 +262,23 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
||||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c h1:OOQeE613BH93ICPq3eke5N78gWNeMjcBWkmD2NKyXVg=
|
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-20231123160306-3374ff1e7a3c/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
|
||||||
github.com/nspcc-dev/neo-go v0.104.1-0.20231206061802-441eb8aa86be h1:nZ2Hi5JSXdq3JXDi/8lms1UXQDAA5LVGpOpcrf2bRVA=
|
github.com/nspcc-dev/neo-go v0.106.2 h1:KXSJ2J5Oacc7LrX3r4jvnC8ihKqHs5NB21q4f2S3r9o=
|
||||||
github.com/nspcc-dev/neo-go v0.104.1-0.20231206061802-441eb8aa86be/go.mod h1:dsu8+VDMgGF7QNtPFBU4seE3pxSq8fYCuk3A6he4+ZQ=
|
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-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
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-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
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.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
|
||||||
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
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 v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
|
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/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||||
|
@ -255,18 +287,19 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
@ -296,24 +329,24 @@ 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.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.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
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/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
||||||
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
||||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
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/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
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/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||||
|
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
@ -339,11 +372,12 @@ go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLk
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
|
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.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
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/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -353,8 +387,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -365,8 +399,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-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-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-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
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/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=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -390,8 +424,11 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/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/net v0.0.0-20180724234803-3673e40ba225/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -412,9 +449,11 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
@ -423,8 +462,8 @@ 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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -445,10 +484,10 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -457,7 +496,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -471,8 +513,10 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -487,12 +531,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -501,12 +545,13 @@ 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||||
|
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
@ -554,10 +599,14 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-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-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.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
@ -622,12 +671,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/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 v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f h1:Vn+VyHU5guc9KjB5KrjI2q0wCOWEOIh0OEsleqakHJg=
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
|
||||||
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY=
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -648,8 +697,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||||
google.golang.org/grpc v1.36.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.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
|
||||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -663,18 +712,25 @@ 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-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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
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.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/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 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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
@ -689,3 +745,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
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=
|
||||||
|
|
84
internal/frostfs/frostfsid/contract/frostfsid.go
Normal file
84
internal/frostfs/frostfsid/contract/frostfsid.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package contract
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
|
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FrostFSID struct {
|
||||||
|
cli *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
// RPCAddress is an endpoint to connect to neo rpc.
|
||||||
|
RPCAddress string
|
||||||
|
|
||||||
|
// Contract is hash of contract or its name in NNS.
|
||||||
|
Contract string
|
||||||
|
|
||||||
|
// ProxyContract is hash of proxy contract or its name in NNS to interact with frostfsid.
|
||||||
|
ProxyContract string
|
||||||
|
|
||||||
|
// Key is used to interact with frostfsid contract.
|
||||||
|
// If this is nil than random key will be generated.
|
||||||
|
Key *keys.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
||||||
|
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := cfg.Key
|
||||||
|
if key == nil {
|
||||||
|
if key, err = keys.NewPrivateKey(); err != nil {
|
||||||
|
return nil, fmt.Errorf("generate anon private key for frostfsid: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("init rpc client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var opt client.Options
|
||||||
|
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("init frostfsid client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &FrostFSID{
|
||||||
|
cli: cli,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetSubjectExtended(userHash util.Uint160) (*client.SubjectExtended, error) {
|
||||||
|
return f.cli.GetSubjectExtended(userHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetSubjectKeyByName(namespace, name string) (*keys.PublicKey, error) {
|
||||||
|
return f.cli.GetSubjectKeyByName(namespace, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) CreateSubject(namespace string, key *keys.PublicKey) (util.Uint256, uint32, error) {
|
||||||
|
return f.cli.CreateSubject(namespace, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) Wait(tx util.Uint256, vub uint32, err error) error {
|
||||||
|
_, err = f.cli.Wait(tx, vub, err)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -1,128 +1,128 @@
|
||||||
package frostfsid
|
package frostfsid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FrostFSID struct {
|
type FrostFSID struct {
|
||||||
cli *client.Client
|
frostfsid *contract.FrostFSID
|
||||||
|
cache *cache.FrostfsIDCache
|
||||||
|
log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// RPCAddress is an endpoint to connect to neo rpc.
|
Cache *cache.FrostfsIDCache
|
||||||
RPCAddress string
|
FrostFSID *contract.FrostFSID
|
||||||
|
Logger *zap.Logger
|
||||||
// Contract is hash of contract or its name in NNS.
|
|
||||||
Contract string
|
|
||||||
|
|
||||||
// ProxyContract is hash of proxy contract or its name in NNS to interact with frostfsid.
|
|
||||||
ProxyContract string
|
|
||||||
|
|
||||||
// Key is used to interact with frostfsid contract.
|
|
||||||
// If this is nil than random key will be generated.
|
|
||||||
Key *keys.PrivateKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ api.FrostFSID = (*FrostFSID)(nil)
|
_ api.FrostFSID = (*FrostFSID)(nil)
|
||||||
_ authmate.FrostFSID = (*FrostFSID)(nil)
|
_ handler.FrostFSID = (*FrostFSID)(nil)
|
||||||
_ handler.FrostFSID = (*FrostFSID)(nil)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
// NewFrostFSID creates new FrostfsID wrapper.
|
||||||
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
func NewFrostFSID(cfg Config) (*FrostFSID, error) {
|
||||||
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
switch {
|
||||||
if err != nil {
|
case cfg.FrostFSID == nil:
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, errors.New("missing frostfsid client")
|
||||||
}
|
case cfg.Cache == nil:
|
||||||
|
return nil, errors.New("missing frostfsid cache")
|
||||||
key := cfg.Key
|
case cfg.Logger == nil:
|
||||||
if key == nil {
|
return nil, errors.New("missing frostfsid logger")
|
||||||
if key, err = keys.NewPrivateKey(); err != nil {
|
|
||||||
return nil, fmt.Errorf("generate anon private key for frostfsid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("init rpc client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var opt client.Options
|
|
||||||
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("init frostfsid client: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &FrostFSID{
|
return &FrostFSID{
|
||||||
cli: cli,
|
frostfsid: cfg.FrostFSID,
|
||||||
|
cache: cfg.Cache,
|
||||||
|
log: cfg.Logger,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
||||||
_, err := f.cli.GetSubjectByKey(key)
|
_, err := f.getSubject(key.GetScriptHash())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FrostFSID) RegisterPublicKey(ns string, key *keys.PublicKey) error {
|
|
||||||
_, err := f.cli.Wait(f.cli.CreateSubject(ns, key))
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
|
||||||
key, err := f.cli.GetSubjectKeyByName(namespace, name)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.Address(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FrostFSID) GetUserKey(account, name string) (string, error) {
|
|
||||||
key, err := f.cli.GetSubjectKeyByName(account, name)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex.EncodeToString(key.Bytes()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
||||||
subjExt, err := f.cli.GetSubjectExtended(userHash)
|
subj, err := f.getSubject(userHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not found") {
|
if strings.Contains(err.Error(), "not found") {
|
||||||
|
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]string, len(subjExt.Groups))
|
res := make([]string, len(subj.Groups))
|
||||||
for i, group := range subjExt.Groups {
|
for i, group := range subj.Groups {
|
||||||
res[i] = strconv.FormatInt(group.ID, 10)
|
res[i] = strconv.FormatInt(group.ID, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {
|
||||||
|
if subj := f.cache.GetSubject(addr); subj != nil {
|
||||||
|
return subj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
subj, err := f.frostfsid.GetSubjectExtended(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.cache.PutSubject(addr, subj); err != nil {
|
||||||
|
f.log.Warn(logs.CouldntCacheSubject, zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return subj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
||||||
|
userKey, err := f.getUserKey(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return userKey.Address(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetUserKey(namespace, name string) (string, error) {
|
||||||
|
userKey, err := f.getUserKey(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.EncodeToString(userKey.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) getUserKey(namespace, name string) (*keys.PublicKey, error) {
|
||||||
|
if userKey := f.cache.GetUserKey(namespace, name); userKey != nil {
|
||||||
|
return userKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userKey, err := f.frostfsid.GetSubjectKeyByName(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.cache.PutUserKey(namespace, name, userKey); err != nil {
|
||||||
|
f.log.Warn(logs.CouldntCacheUserKey, zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return userKey, nil
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,11 @@ type Config struct {
|
||||||
Key *keys.PrivateKey
|
Key *keys.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
batchSize = 100
|
||||||
|
iteratorChainsByPrefix = "iteratorChainsByPrefix"
|
||||||
|
)
|
||||||
|
|
||||||
var _ policy.Contract = (*Client)(nil)
|
var _ policy.Contract = (*Client)(nil)
|
||||||
|
|
||||||
// New creates new Policy contract wrapper.
|
// New creates new Policy contract wrapper.
|
||||||
|
@ -114,7 +119,8 @@ func (c *Client) RemoveChain(kind policycontract.Kind, entity string, name []byt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error) {
|
func (c *Client) ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error) {
|
||||||
items, err := c.policyContract.ListChainsByPrefix(big.NewInt(int64(kind)), entity, name)
|
items, err := commonclient.ReadIteratorItems(c.actor, batchSize, c.contractHash, iteratorChainsByPrefix,
|
||||||
|
big.NewInt(int64(kind)), entity, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -25,7 +27,7 @@ type MorphRuleChainStorageConfig struct {
|
||||||
Log *zap.Logger
|
Log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ engine.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
var _ engine.MorphRuleChainStorageReader = (*MorphRuleChainStorage)(nil)
|
||||||
|
|
||||||
const bucketPolicyPrefix = 'b'
|
const bucketPolicyPrefix = 'b'
|
||||||
|
|
||||||
|
@ -37,11 +39,11 @@ func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleCha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) AddMorphRuleChain(chain.Name, engine.Target, *chain.Chain) (util.Uint256, uint32, error) {
|
func (c *MorphRuleChainStorage) GetAdmin() (util.Uint160, error) {
|
||||||
panic("should never be called")
|
panic("should never be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) RemoveMorphRuleChain(chain.Name, engine.Target, chain.ID) (util.Uint256, uint32, error) {
|
func (c *MorphRuleChainStorage) ListTargetsIterator(engine.TargetType) (uuid.UUID, result.Iterator, error) {
|
||||||
panic("should never be called")
|
panic("should never be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,23 +76,25 @@ func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error {
|
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error {
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3})
|
||||||
|
|
||||||
tx := c.contract.StartTx()
|
tx := c.contract.StartTx()
|
||||||
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
|
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
|
||||||
|
|
||||||
for i := range chains {
|
for i := range chains {
|
||||||
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes())
|
tx.AddChain(policycontract.Container, cnrID.EncodeToString(), chains[i].ID, chains[i].Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.contract.SendTx(tx)
|
return c.contract.SendTx(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error {
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3})
|
||||||
|
|
||||||
tx := c.contract.StartTx()
|
tx := c.contract.StartTx()
|
||||||
tx.RemoveChain(policycontract.Namespace, ns, chainID)
|
for _, chainID := range chainIDs {
|
||||||
|
tx.RemoveChain(policycontract.Container, cnrID.EncodeToString(), chainID)
|
||||||
|
}
|
||||||
tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
||||||
|
|
||||||
return c.contract.SendTx(tx)
|
return c.contract.SendTx(tx)
|
||||||
|
@ -100,25 +104,29 @@ func (c *MorphRuleChainStorage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte
|
||||||
return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) SaveACLChains(ns string, chains []*chain.Chain) error {
|
func (c *MorphRuleChainStorage) SaveACLChains(cid string, chains []*chain.Chain) error {
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.S3})
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.Ingress})
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.Ingress})
|
||||||
|
|
||||||
tx := c.contract.StartTx()
|
tx := c.contract.StartTx()
|
||||||
for i := range chains {
|
for i := range chains {
|
||||||
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes())
|
tx.AddChain(policycontract.Container, cid, chains[i].ID, chains[i].Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.contract.SendTx(tx)
|
return c.contract.SendTx(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKind(target engine.Target) policycontract.Kind {
|
func getKind(target engine.Target) policycontract.Kind {
|
||||||
var kind policycontract.Kind = policycontract.Container
|
switch target.Type {
|
||||||
if target.Type != engine.Container {
|
case engine.Container:
|
||||||
kind = policycontract.Namespace
|
return policycontract.Container
|
||||||
|
case engine.User:
|
||||||
|
return 'u'
|
||||||
|
case engine.Group:
|
||||||
|
return 'g'
|
||||||
|
default:
|
||||||
|
return policycontract.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
return kind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketPolicyName(cnrID cid.ID) []byte {
|
func getBucketPolicyName(cnrID cid.ID) []byte {
|
||||||
|
|
|
@ -70,8 +70,8 @@ func (s *Storage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, policy
|
||||||
return s.morph.PutBucketPolicy(ns, cnrID, policy, policyChains)
|
return s.morph.PutBucketPolicy(ns, cnrID, policy, policyChains)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
func (s *Storage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error {
|
||||||
return s.morph.DeleteBucketPolicy(ns, cnrID, chainID)
|
return s.morph.DeleteBucketPolicy(ns, cnrID, chainIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
func (s *Storage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
|
|
@ -19,16 +19,16 @@ type GetNodeByPathResponseInfoWrapper struct {
|
||||||
response *grpcService.GetNodeByPathResponse_Info
|
response *grpcService.GetNodeByPathResponse_Info
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetNodeByPathResponseInfoWrapper) GetNodeID() uint64 {
|
func (n GetNodeByPathResponseInfoWrapper) GetNodeID() []uint64 {
|
||||||
return n.response.GetNodeId()
|
return []uint64{n.response.GetNodeId()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetNodeByPathResponseInfoWrapper) GetParentID() uint64 {
|
func (n GetNodeByPathResponseInfoWrapper) GetParentID() []uint64 {
|
||||||
return n.response.GetParentId()
|
return []uint64{n.response.GetParentId()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetNodeByPathResponseInfoWrapper) GetTimestamp() uint64 {
|
func (n GetNodeByPathResponseInfoWrapper) GetTimestamp() []uint64 {
|
||||||
return n.response.GetTimestamp()
|
return []uint64{n.response.GetTimestamp()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta {
|
func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta {
|
||||||
|
@ -43,15 +43,21 @@ type GetSubTreeResponseBodyWrapper struct {
|
||||||
response *grpcService.GetSubTreeResponse_Body
|
response *grpcService.GetSubTreeResponse_Body
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetSubTreeResponseBodyWrapper) GetNodeID() uint64 {
|
func (n GetSubTreeResponseBodyWrapper) GetNodeID() []uint64 {
|
||||||
return n.response.GetNodeId()
|
return n.response.GetNodeId()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetSubTreeResponseBodyWrapper) GetParentID() uint64 {
|
func (n GetSubTreeResponseBodyWrapper) GetParentID() []uint64 {
|
||||||
return n.response.GetParentId()
|
resp := n.response.GetParentId()
|
||||||
|
if resp == nil {
|
||||||
|
// storage sends nil that should be interpreted as []uint64{0}
|
||||||
|
// due to protobuf compatibility, see 'GetSubTree' function
|
||||||
|
return []uint64{0}
|
||||||
|
}
|
||||||
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetSubTreeResponseBodyWrapper) GetTimestamp() uint64 {
|
func (n GetSubTreeResponseBodyWrapper) GetTimestamp() []uint64 {
|
||||||
return n.response.GetTimestamp()
|
return n.response.GetTimestamp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,13 +102,21 @@ func (w *PoolWrapper) GetNodes(ctx context.Context, prm *tree.GetNodesParams) ([
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) ([]tree.NodeResponse, error) {
|
func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) ([]tree.NodeResponse, error) {
|
||||||
poolPrm := treepool.GetSubTreeParams{
|
poolPrm := treepool.GetSubTreeParams{
|
||||||
CID: bktInfo.CID,
|
CID: bktInfo.CID,
|
||||||
TreeID: treeID,
|
TreeID: treeID,
|
||||||
RootID: rootID,
|
RootID: rootID,
|
||||||
Depth: depth,
|
Depth: depth,
|
||||||
BearerToken: getBearer(ctx, bktInfo),
|
BearerToken: getBearer(ctx, bktInfo),
|
||||||
|
Order: treepool.AscendingOrder,
|
||||||
|
}
|
||||||
|
if len(rootID) == 1 && rootID[0] == 0 {
|
||||||
|
// storage node interprets 'nil' value as []uint64{0}
|
||||||
|
// gate wants to send 'nil' value instead of []uint64{0}, because
|
||||||
|
// it provides compatibility with previous tree service api where
|
||||||
|
// single uint64(0) value is dropped from signature
|
||||||
|
poolPrm.RootID = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
subTreeReader, err := w.p.GetSubTree(ctx, poolPrm)
|
subTreeReader, err := w.p.GetSubTree(ctx, poolPrm)
|
||||||
|
@ -162,13 +176,21 @@ func (s *SubTreeStreamImpl) Next() (tree.NodeResponse, error) {
|
||||||
return s.Next()
|
return s.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PoolWrapper) GetSubTreeStream(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) (tree.SubTreeStream, error) {
|
func (w *PoolWrapper) GetSubTreeStream(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) (tree.SubTreeStream, error) {
|
||||||
poolPrm := treepool.GetSubTreeParams{
|
poolPrm := treepool.GetSubTreeParams{
|
||||||
CID: bktInfo.CID,
|
CID: bktInfo.CID,
|
||||||
TreeID: treeID,
|
TreeID: treeID,
|
||||||
RootID: rootID,
|
RootID: rootID,
|
||||||
Depth: depth,
|
Depth: depth,
|
||||||
BearerToken: getBearer(ctx, bktInfo),
|
BearerToken: getBearer(ctx, bktInfo),
|
||||||
|
Order: treepool.AscendingOrder,
|
||||||
|
}
|
||||||
|
if len(rootID) == 1 && rootID[0] == 0 {
|
||||||
|
// storage node interprets 'nil' value as []uint64{0}
|
||||||
|
// gate wants to send 'nil' value instead of []uint64{0}, because
|
||||||
|
// it provides compatibility with previous tree service api where
|
||||||
|
// single uint64(0) value is dropped from signature
|
||||||
|
poolPrm.RootID = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
subTreeReader, err := w.p.GetSubTree(ctx, poolPrm)
|
subTreeReader, err := w.p.GetSubTree(ctx, poolPrm)
|
||||||
|
|
|
@ -66,7 +66,6 @@ const (
|
||||||
SomeACLNotFullyMapped = "some acl not fully mapped" // Warn in ../../api/handler/acl.go
|
SomeACLNotFullyMapped = "some acl not fully mapped" // Warn in ../../api/handler/acl.go
|
||||||
CouldntDeleteObject = "couldn't delete object" // Error in ../../api/layer/layer.go
|
CouldntDeleteObject = "couldn't delete object" // Error in ../../api/layer/layer.go
|
||||||
NotificatorIsDisabledS3WontProduceNotificationEvents = "notificator is disabled, s3 won't produce notification events" // Warn in ../../api/handler/api.go
|
NotificatorIsDisabledS3WontProduceNotificationEvents = "notificator is disabled, s3 won't produce notification events" // Warn in ../../api/handler/api.go
|
||||||
CouldntGetBucketVersioning = "couldn't get bucket versioning" // Warn in ../../api/handler/put.go
|
|
||||||
BucketIsCreated = "bucket is created" // Info in ../../api/handler/put.go
|
BucketIsCreated = "bucket is created" // Info in ../../api/handler/put.go
|
||||||
CouldntDeleteNotificationConfigurationObject = "couldn't delete notification configuration object" // Error in ../../api/layer/notifications.go
|
CouldntDeleteNotificationConfigurationObject = "couldn't delete notification configuration object" // Error in ../../api/layer/notifications.go
|
||||||
CouldNotParseContainerObjectLockEnabledAttribute = "could not parse container object lock enabled attribute" // Error in ../../api/layer/container.go
|
CouldNotParseContainerObjectLockEnabledAttribute = "could not parse container object lock enabled attribute" // Error in ../../api/layer/container.go
|
||||||
|
@ -88,6 +87,7 @@ const (
|
||||||
FailedToSubmitTaskToPool = "failed to submit task to pool" // Warn in ../../api/layer/object.go
|
FailedToSubmitTaskToPool = "failed to submit task to pool" // Warn in ../../api/layer/object.go
|
||||||
CouldNotFetchObjectMeta = "could not fetch object meta" // Warn in ../../api/layer/object.go
|
CouldNotFetchObjectMeta = "could not fetch object meta" // Warn in ../../api/layer/object.go
|
||||||
GetTreeNode = "get tree node" // Debug in ../../api/layer/tagging.go
|
GetTreeNode = "get tree node" // Debug in ../../api/layer/tagging.go
|
||||||
|
GetTreeNodeToDelete = "get tree node to delete" // Debug in ../../api/layer/tagging.go
|
||||||
CouldntPutBucketInfoIntoCache = "couldn't put bucket info into cache" // Warn in ../../api/layer/cache.go
|
CouldntPutBucketInfoIntoCache = "couldn't put bucket info into cache" // Warn in ../../api/layer/cache.go
|
||||||
CouldntAddObjectToCache = "couldn't add object to cache" // Warn in ../../api/layer/cache.go
|
CouldntAddObjectToCache = "couldn't add object to cache" // Warn in ../../api/layer/cache.go
|
||||||
CouldntCacheAccessControlOperation = "couldn't cache access control operation" // Warn in ../../api/layer/cache.go
|
CouldntCacheAccessControlOperation = "couldn't cache access control operation" // Warn in ../../api/layer/cache.go
|
||||||
|
@ -149,4 +149,17 @@ const (
|
||||||
FailedToGenerateRequestID = "failed to generate request id"
|
FailedToGenerateRequestID = "failed to generate request id"
|
||||||
InvalidBucketObjectLockEnabledHeader = "invalid X-Amz-Bucket-Object-Lock-Enabled header"
|
InvalidBucketObjectLockEnabledHeader = "invalid X-Amz-Bucket-Object-Lock-Enabled header"
|
||||||
InvalidTreeKV = "invalid tree service meta KV"
|
InvalidTreeKV = "invalid tree service meta KV"
|
||||||
|
FailedToWriteResponse = "failed to write response"
|
||||||
|
PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied"
|
||||||
|
CouldntCacheSubject = "couldn't cache subject info"
|
||||||
|
UserGroupsListIsEmpty = "user groups list is empty, subject not found"
|
||||||
|
CouldntCacheUserKey = "couldn't cache user key"
|
||||||
|
FoundSeveralBucketCorsNodes = "found several bucket cors nodes, latest be used"
|
||||||
|
FoundSeveralNotificationConfigurationNodes = "found several notification configuration nodes, latest be used"
|
||||||
|
FoundSeveralObjectTaggingNodes = "found several object tagging nodes, latest be used"
|
||||||
|
FoundSeveralBucketTaggingNodes = "found several bucket tagging nodes, latest be used"
|
||||||
|
FoundSeveralBucketSettingsNodes = "found several bucket settings nodes, latest be used"
|
||||||
|
UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts"
|
||||||
|
FoundSeveralSystemNodes = "found several system nodes, latest be used"
|
||||||
|
FailedToParsePartInfo = "failed to parse part info"
|
||||||
)
|
)
|
||||||
|
|
52
pkg/retryer/retryer.go
Normal file
52
pkg/retryer/retryer.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package retryer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeWithRetry(ctx context.Context, fn func() error, retryer aws.RetryerV2) (err error) {
|
||||||
|
var attemptNum int
|
||||||
|
|
||||||
|
maxAttempts := retryer.MaxAttempts()
|
||||||
|
|
||||||
|
for {
|
||||||
|
attemptNum++
|
||||||
|
|
||||||
|
err = fn()
|
||||||
|
|
||||||
|
if !retryer.IsErrorRetryable(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attemptNum >= maxAttempts {
|
||||||
|
return fmt.Errorf("max retry attempts exausted, max %d: %w", maxAttempts, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retryDelay, reqErr := retryer.RetryDelay(attemptNum, err)
|
||||||
|
if reqErr != nil {
|
||||||
|
return reqErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqErr = sleepWithContext(ctx, retryDelay); reqErr != nil {
|
||||||
|
return reqErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepWithContext(ctx context.Context, dur time.Duration) error {
|
||||||
|
t := time.NewTimer(dur)
|
||||||
|
defer t.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
break
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
59
pkg/retryer/retryer_test.go
Normal file
59
pkg/retryer/retryer_test.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package retryer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws/retry"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRetryer(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
retryer := retry.NewStandard(func(options *retry.StandardOptions) {
|
||||||
|
options.MaxAttempts = 3
|
||||||
|
options.Backoff = retry.BackoffDelayerFunc(func(int, error) (time.Duration, error) { return 0, nil })
|
||||||
|
options.Retryables = []retry.IsErrorRetryable{retry.IsErrorRetryableFunc(func(err error) aws.Ternary {
|
||||||
|
if errors.Is(err, tree.ErrNodeAccessDenied) {
|
||||||
|
return aws.TrueTernary
|
||||||
|
}
|
||||||
|
return aws.FalseTernary
|
||||||
|
})}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no retryable", func(t *testing.T) {
|
||||||
|
count := 0
|
||||||
|
err := MakeWithRetry(ctx, func() error {
|
||||||
|
count++
|
||||||
|
if count == 1 {
|
||||||
|
return tree.ErrNodeNotFound
|
||||||
|
}
|
||||||
|
return tree.ErrNodeAccessDenied
|
||||||
|
}, retryer)
|
||||||
|
require.ErrorIs(t, err, tree.ErrNodeNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("retry", func(t *testing.T) {
|
||||||
|
count := 0
|
||||||
|
err := MakeWithRetry(ctx, func() error {
|
||||||
|
count++
|
||||||
|
if count < 3 {
|
||||||
|
return tree.ErrNodeAccessDenied
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, retryer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("retry exhausted", func(t *testing.T) {
|
||||||
|
err := MakeWithRetry(ctx, func() error {
|
||||||
|
return tree.ErrNodeAccessDenied
|
||||||
|
}, retryer)
|
||||||
|
require.ErrorIs(t, err, tree.ErrNodeAccessDenied)
|
||||||
|
})
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"
|
||||||
controlSvc "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control/server"
|
controlSvc "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control/server"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
@ -23,13 +24,30 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PolicyData struct {
|
type PolicyData struct {
|
||||||
Namespace string
|
Kind policycontract.Kind
|
||||||
Chain *chain.Chain
|
Name string
|
||||||
|
Chain *chain.Chain
|
||||||
}
|
}
|
||||||
|
|
||||||
type PolicyInfo struct {
|
type PolicyInfo struct {
|
||||||
Namespace string
|
Kind policycontract.Kind
|
||||||
ChainID chain.ID
|
Name string
|
||||||
|
ChainID chain.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func kindToTarget(k policycontract.Kind) control.PolicyTarget {
|
||||||
|
switch k {
|
||||||
|
case policycontract.Container:
|
||||||
|
return control.PolicyTarget_CONTAINER
|
||||||
|
case policycontract.Namespace:
|
||||||
|
return control.PolicyTarget_NAMESPACE
|
||||||
|
case 'u':
|
||||||
|
return control.PolicyTarget_USER
|
||||||
|
case 'g':
|
||||||
|
return control.PolicyTarget_GROUP
|
||||||
|
default:
|
||||||
|
return control.PolicyTarget_TARGET_UNDEFINED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, addr string, key *keys.PrivateKey) (*Client, error) {
|
func New(ctx context.Context, addr string, key *keys.PrivateKey) (*Client, error) {
|
||||||
|
@ -70,8 +88,9 @@ func (c *Client) PutPolicies(ctx context.Context, policies []PolicyData) error {
|
||||||
chainDatas := make([]*control.PutPoliciesRequest_ChainData, len(policies))
|
chainDatas := make([]*control.PutPoliciesRequest_ChainData, len(policies))
|
||||||
for i := range policies {
|
for i := range policies {
|
||||||
chainDatas[i] = &control.PutPoliciesRequest_ChainData{
|
chainDatas[i] = &control.PutPoliciesRequest_ChainData{
|
||||||
Namespace: policies[i].Namespace,
|
Target: kindToTarget(policies[i].Kind),
|
||||||
Chain: policies[i].Chain.Bytes(),
|
Name: policies[i].Name,
|
||||||
|
Chain: policies[i].Chain.Bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +112,9 @@ func (c *Client) RemovePolicies(ctx context.Context, policies []PolicyInfo) erro
|
||||||
chainInfos := make([]*control.RemovePoliciesRequest_ChainInfo, len(policies))
|
chainInfos := make([]*control.RemovePoliciesRequest_ChainInfo, len(policies))
|
||||||
for i := range policies {
|
for i := range policies {
|
||||||
chainInfos[i] = &control.RemovePoliciesRequest_ChainInfo{
|
chainInfos[i] = &control.RemovePoliciesRequest_ChainInfo{
|
||||||
Namespace: policies[i].Namespace,
|
Target: kindToTarget(policies[i].Kind),
|
||||||
ChainID: []byte(policies[i].ChainID),
|
Name: policies[i].Name,
|
||||||
|
ChainID: []byte(policies[i].ChainID),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +132,12 @@ func (c *Client) RemovePolicies(ctx context.Context, policies []PolicyInfo) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetPolicy(ctx context.Context, namespace string, chainID chain.ID) (*chain.Chain, error) {
|
func (c *Client) GetPolicy(ctx context.Context, kind policycontract.Kind, name string, chainID chain.ID) (*chain.Chain, error) {
|
||||||
req := &control.GetPolicyRequest{
|
req := &control.GetPolicyRequest{
|
||||||
Body: &control.GetPolicyRequest_Body{
|
Body: &control.GetPolicyRequest_Body{
|
||||||
Namespace: namespace,
|
Target: kindToTarget(kind),
|
||||||
ChainID: []byte(chainID),
|
Name: name,
|
||||||
|
ChainID: []byte(chainID),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,10 +158,11 @@ func (c *Client) GetPolicy(ctx context.Context, namespace string, chainID chain.
|
||||||
return &policyChain, nil
|
return &policyChain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ListPolicies(ctx context.Context, namespace string) ([]chain.ID, error) {
|
func (c *Client) ListPolicies(ctx context.Context, kind policycontract.Kind, name string) ([]chain.ID, error) {
|
||||||
req := &control.ListPoliciesRequest{
|
req := &control.ListPoliciesRequest{
|
||||||
Body: &control.ListPoliciesRequest_Body{
|
Body: &control.ListPoliciesRequest_Body{
|
||||||
Namespace: namespace,
|
Target: kindToTarget(kind),
|
||||||
|
Name: name,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,14 +140,39 @@ func (s *Server) putPolicy(data *control.PutPoliciesRequest_ChainData) error {
|
||||||
return status.Error(codes.InvalidArgument, "missing chain id")
|
return status.Error(codes.InvalidArgument, "missing chain id")
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(data.GetNamespace())
|
t, err := s.parseTarget(data.Target, data.Name)
|
||||||
if _, err := s.chainStorage.AddOverride(chain.S3, engine.NamespaceTarget(ns), &overrideChain); err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := s.chainStorage.AddOverride(chain.S3, t, &overrideChain); err != nil {
|
||||||
return status.Error(codes.Internal, err.Error())
|
return status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) parseTarget(target control.PolicyTarget, name string) (engine.Target, error) {
|
||||||
|
var (
|
||||||
|
t engine.Target
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
switch target {
|
||||||
|
case control.PolicyTarget_NAMESPACE:
|
||||||
|
ns := s.settings.ResolveNamespaceAlias(name)
|
||||||
|
t = engine.NamespaceTarget(ns)
|
||||||
|
case control.PolicyTarget_CONTAINER:
|
||||||
|
t = engine.ContainerTarget(name)
|
||||||
|
case control.PolicyTarget_USER:
|
||||||
|
t = engine.UserTarget(name)
|
||||||
|
case control.PolicyTarget_GROUP:
|
||||||
|
t = engine.GroupTarget(name)
|
||||||
|
default:
|
||||||
|
err = status.Error(codes.InvalidArgument, fmt.Sprintf("invalid target: %s", target.String()))
|
||||||
|
}
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
// RemovePolicies removes existing policies.
|
// RemovePolicies removes existing policies.
|
||||||
//
|
//
|
||||||
// If request is unsigned or signed by disallowed key, permission error returns.
|
// If request is unsigned or signed by disallowed key, permission error returns.
|
||||||
|
@ -169,8 +194,11 @@ func (s *Server) RemovePolicies(_ context.Context, req *control.RemovePoliciesRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) removePolicy(info *control.RemovePoliciesRequest_ChainInfo) error {
|
func (s *Server) removePolicy(info *control.RemovePoliciesRequest_ChainInfo) error {
|
||||||
ns := s.settings.ResolveNamespaceAlias(info.GetNamespace())
|
t, err := s.parseTarget(info.Target, info.Name)
|
||||||
err := s.chainStorage.RemoveOverride(chain.S3, engine.NamespaceTarget(ns), chain.ID(info.GetChainID()))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.chainStorage.RemoveOverride(chain.S3, t, chain.ID(info.GetChainID()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isNotFoundError(err) {
|
if isNotFoundError(err) {
|
||||||
return status.Error(codes.NotFound, err.Error())
|
return status.Error(codes.NotFound, err.Error())
|
||||||
|
@ -184,16 +212,20 @@ func (s *Server) removePolicy(info *control.RemovePoliciesRequest_ChainInfo) err
|
||||||
//
|
//
|
||||||
// If request is unsigned or signed by disallowed key, permission error returns.
|
// If request is unsigned or signed by disallowed key, permission error returns.
|
||||||
func (s *Server) GetPolicy(_ context.Context, req *control.GetPolicyRequest) (*control.GetPolicyResponse, error) {
|
func (s *Server) GetPolicy(_ context.Context, req *control.GetPolicyRequest) (*control.GetPolicyResponse, error) {
|
||||||
s.log.Info(logs.ControlAPIGetPolicy, zap.String("namespace", req.GetBody().GetNamespace()),
|
s.log.Info(logs.ControlAPIGetPolicy, zap.Stringer("target", req.GetBody().GetTarget()), zap.String("name", req.GetBody().GetName()),
|
||||||
zap.Binary("chainId", req.GetBody().GetChainID()), zap.String("key", hex.EncodeToString(req.Signature.Key)))
|
zap.Binary("chainId", req.GetBody().GetChainID()), zap.String("key", hex.EncodeToString(req.Signature.Key)))
|
||||||
|
|
||||||
|
t, err := s.parseTarget(req.GetBody().GetTarget(), req.GetBody().GetName())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// verify request
|
// verify request
|
||||||
if err := s.isValidRequest(req); err != nil {
|
if err := s.isValidRequest(req); err != nil {
|
||||||
return nil, status.Error(codes.PermissionDenied, err.Error())
|
return nil, status.Error(codes.PermissionDenied, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
overrideChain, err := s.chainStorage.GetOverride(chain.S3, t, chain.ID(req.GetBody().GetChainID()))
|
||||||
overrideChain, err := s.chainStorage.GetOverride(chain.S3, engine.NamespaceTarget(ns), chain.ID(req.GetBody().GetChainID()))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
@ -205,16 +237,20 @@ func (s *Server) GetPolicy(_ context.Context, req *control.GetPolicyRequest) (*c
|
||||||
//
|
//
|
||||||
// If request is unsigned or signed by disallowed key, permission error returns.
|
// If request is unsigned or signed by disallowed key, permission error returns.
|
||||||
func (s *Server) ListPolicies(_ context.Context, req *control.ListPoliciesRequest) (*control.ListPoliciesResponse, error) {
|
func (s *Server) ListPolicies(_ context.Context, req *control.ListPoliciesRequest) (*control.ListPoliciesResponse, error) {
|
||||||
s.log.Info(logs.ControlAPIListPolicies, zap.String("namespace", req.GetBody().GetNamespace()),
|
s.log.Info(logs.ControlAPIListPolicies, zap.Stringer("target", req.GetBody().GetTarget()), zap.String("name", req.GetBody().GetName()),
|
||||||
zap.String("key", hex.EncodeToString(req.Signature.Key)))
|
zap.String("key", hex.EncodeToString(req.Signature.Key)))
|
||||||
|
|
||||||
|
t, err := s.parseTarget(req.GetBody().GetTarget(), req.GetBody().GetName())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// verify request
|
// verify request
|
||||||
if err := s.isValidRequest(req); err != nil {
|
if err := s.isValidRequest(req); err != nil {
|
||||||
return nil, status.Error(codes.PermissionDenied, err.Error())
|
return nil, status.Error(codes.PermissionDenied, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
chains, err := s.chainStorage.ListOverrides(chain.S3, t)
|
||||||
chains, err := s.chainStorage.ListOverrides(chain.S3, engine.NamespaceTarget(ns))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.28.1
|
// protoc-gen-go v1.30.0
|
||||||
// protoc v3.21.9
|
// protoc v3.21.12
|
||||||
// source: pkg/service/control/service.proto
|
// source: pkg/service/control/service.proto
|
||||||
|
|
||||||
package control
|
package control
|
||||||
|
@ -77,6 +77,67 @@ func (HealthStatus) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{0}
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Policy target to store chains.
|
||||||
|
type PolicyTarget int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Undefined target, invalid to use.
|
||||||
|
PolicyTarget_TARGET_UNDEFINED PolicyTarget = 0
|
||||||
|
// Container target for bucket policies.
|
||||||
|
PolicyTarget_CONTAINER PolicyTarget = 1
|
||||||
|
// Namespace target for namespace policies.
|
||||||
|
PolicyTarget_NAMESPACE PolicyTarget = 2
|
||||||
|
// User target for namespace user policies.
|
||||||
|
PolicyTarget_USER PolicyTarget = 3
|
||||||
|
// Group target for namespace target policies.
|
||||||
|
PolicyTarget_GROUP PolicyTarget = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for PolicyTarget.
|
||||||
|
var (
|
||||||
|
PolicyTarget_name = map[int32]string{
|
||||||
|
0: "TARGET_UNDEFINED",
|
||||||
|
1: "CONTAINER",
|
||||||
|
2: "NAMESPACE",
|
||||||
|
3: "USER",
|
||||||
|
4: "GROUP",
|
||||||
|
}
|
||||||
|
PolicyTarget_value = map[string]int32{
|
||||||
|
"TARGET_UNDEFINED": 0,
|
||||||
|
"CONTAINER": 1,
|
||||||
|
"NAMESPACE": 2,
|
||||||
|
"USER": 3,
|
||||||
|
"GROUP": 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x PolicyTarget) Enum() *PolicyTarget {
|
||||||
|
p := new(PolicyTarget)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x PolicyTarget) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PolicyTarget) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_pkg_service_control_service_proto_enumTypes[1].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PolicyTarget) Type() protoreflect.EnumType {
|
||||||
|
return &file_pkg_service_control_service_proto_enumTypes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x PolicyTarget) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use PolicyTarget.Descriptor instead.
|
||||||
|
func (PolicyTarget) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
// Signature of some message.
|
// Signature of some message.
|
||||||
type Signature struct {
|
type Signature struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
|
@ -794,10 +855,12 @@ type PutPoliciesRequest_ChainData struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
Target PolicyTarget `protobuf:"varint,1,opt,name=target,proto3,enum=s3gw.control.PolicyTarget" json:"target,omitempty"`
|
||||||
|
// Policy name.
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
// Chain rules.
|
// Chain rules.
|
||||||
Chain []byte `protobuf:"bytes,2,opt,name=chain,proto3" json:"chain,omitempty"`
|
Chain []byte `protobuf:"bytes,3,opt,name=chain,proto3" json:"chain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PutPoliciesRequest_ChainData) Reset() {
|
func (x *PutPoliciesRequest_ChainData) Reset() {
|
||||||
|
@ -832,9 +895,16 @@ func (*PutPoliciesRequest_ChainData) Descriptor() ([]byte, []int) {
|
||||||
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{3, 0}
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{3, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PutPoliciesRequest_ChainData) GetNamespace() string {
|
func (x *PutPoliciesRequest_ChainData) GetTarget() PolicyTarget {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Namespace
|
return x.Target
|
||||||
|
}
|
||||||
|
return PolicyTarget_TARGET_UNDEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PutPoliciesRequest_ChainData) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -936,10 +1006,12 @@ type RemovePoliciesRequest_ChainInfo struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
Target PolicyTarget `protobuf:"varint,1,opt,name=target,proto3,enum=s3gw.control.PolicyTarget" json:"target,omitempty"`
|
||||||
|
// Policy name.
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
// Chain id to remove.
|
// Chain id to remove.
|
||||||
ChainID []byte `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"`
|
ChainID []byte `protobuf:"bytes,3,opt,name=chainID,proto3" json:"chainID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemovePoliciesRequest_ChainInfo) Reset() {
|
func (x *RemovePoliciesRequest_ChainInfo) Reset() {
|
||||||
|
@ -974,9 +1046,16 @@ func (*RemovePoliciesRequest_ChainInfo) Descriptor() ([]byte, []int) {
|
||||||
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{5, 0}
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{5, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemovePoliciesRequest_ChainInfo) GetNamespace() string {
|
func (x *RemovePoliciesRequest_ChainInfo) GetTarget() PolicyTarget {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Namespace
|
return x.Target
|
||||||
|
}
|
||||||
|
return PolicyTarget_TARGET_UNDEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RemovePoliciesRequest_ChainInfo) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -1078,10 +1157,12 @@ type GetPolicyRequest_Body struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
Target PolicyTarget `protobuf:"varint,1,opt,name=target,proto3,enum=s3gw.control.PolicyTarget" json:"target,omitempty"`
|
||||||
// Chain id to remove.
|
// Policy name.
|
||||||
ChainID []byte `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"`
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
// Chain id to get.
|
||||||
|
ChainID []byte `protobuf:"bytes,3,opt,name=chainID,proto3" json:"chainID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetPolicyRequest_Body) Reset() {
|
func (x *GetPolicyRequest_Body) Reset() {
|
||||||
|
@ -1116,9 +1197,16 @@ func (*GetPolicyRequest_Body) Descriptor() ([]byte, []int) {
|
||||||
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{7, 0}
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{7, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetPolicyRequest_Body) GetNamespace() string {
|
func (x *GetPolicyRequest_Body) GetTarget() PolicyTarget {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Namespace
|
return x.Target
|
||||||
|
}
|
||||||
|
return PolicyTarget_TARGET_UNDEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetPolicyRequest_Body) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -1183,8 +1271,10 @@ type ListPoliciesRequest_Body struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
Target PolicyTarget `protobuf:"varint,1,opt,name=target,proto3,enum=s3gw.control.PolicyTarget" json:"target,omitempty"`
|
||||||
|
// Policy name.
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListPoliciesRequest_Body) Reset() {
|
func (x *ListPoliciesRequest_Body) Reset() {
|
||||||
|
@ -1219,9 +1309,16 @@ func (*ListPoliciesRequest_Body) Descriptor() ([]byte, []int) {
|
||||||
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{9, 0}
|
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{9, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListPoliciesRequest_Body) GetNamespace() string {
|
func (x *ListPoliciesRequest_Body) GetTarget() PolicyTarget {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Namespace
|
return x.Target
|
||||||
|
}
|
||||||
|
return PolicyTarget_TARGET_UNDEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListPoliciesRequest_Body) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -1305,7 +1402,7 @@ var file_pkg_service_control_service_proto_rawDesc = []byte{
|
||||||
0x0d, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
|
0x0d, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||||
0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||||
0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x9b,
|
0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc5,
|
||||||
0x02, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
0x02, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||||
|
@ -1314,136 +1411,153 @@ var file_pkg_service_control_service_proto_rawDesc = []byte{
|
||||||
0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
|
0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||||
0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69,
|
0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69,
|
||||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x3f, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e,
|
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x69, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e,
|
||||||
0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
|
0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01,
|
||||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
|
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||||
0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
0x0c, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x1a, 0x52, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79,
|
0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x18, 0x01,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x61,
|
||||||
0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52,
|
0x69, 0x6e, 0x1a, 0x52, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x68,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61,
|
0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a,
|
||||||
0x52, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x22, 0x90, 0x01, 0x0a,
|
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x75,
|
||||||
0x13, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01,
|
0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x69,
|
||||||
0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
0x6e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x13, 0x50, 0x75, 0x74, 0x50, 0x6f,
|
||||||
0x6c, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73,
|
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79,
|
0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73,
|
||||||
0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
|
0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x75, 0x74, 0x50,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
|
||||||
0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69,
|
0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69,
|
||||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x06, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22,
|
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
||||||
0xa8, 0x02, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69,
|
0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67,
|
||||||
0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x62, 0x6f, 0x64,
|
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
|
||||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63,
|
0x65, 0x1a, 0x06, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22, 0xd2, 0x02, 0x0a, 0x15, 0x52, 0x65,
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c,
|
0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64,
|
0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61,
|
0x0b, 0x32, 0x28, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67,
|
0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52,
|
||||||
0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
|
|
||||||
0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x43,
|
|
||||||
0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x6e,
|
|
||||||
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
|
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61,
|
|
||||||
0x69, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69,
|
|
||||||
0x6e, 0x49, 0x44, 0x1a, 0x55, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x4d, 0x0a, 0x0a, 0x63,
|
|
||||||
0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
|
||||||
0x2d, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52,
|
|
||||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71,
|
|
||||||
0x75, 0x65, 0x73, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a,
|
|
||||||
0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x16, 0x52,
|
|
||||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73,
|
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
|
||||||
0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
|
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04,
|
|
||||||
0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
|
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65,
|
|
||||||
0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x06, 0x0a, 0x04, 0x42,
|
|
||||||
0x6f, 0x64, 0x79, 0x22, 0xc2, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
|
|
||||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79,
|
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f,
|
|
||||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52,
|
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64,
|
||||||
0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02,
|
0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||||
0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73,
|
0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73,
|
||||||
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x3e, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79,
|
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x6d, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69,
|
||||||
0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
|
0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18,
|
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e,
|
||||||
0x0a, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||||
0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x22, 0xa2, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
|
0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38,
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
|
||||||
0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73,
|
0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07,
|
||||||
0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x50,
|
0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x1a, 0x55, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12,
|
||||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f,
|
0x4d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20,
|
||||||
|
0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||||
|
0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
|
||||||
|
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e,
|
||||||
|
0x66, 0x6f, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x96,
|
||||||
|
0x01, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
|
||||||
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x62, 0x6f, 0x64,
|
||||||
|
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63,
|
||||||
|
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c,
|
||||||
|
0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f,
|
||||||
0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e,
|
0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e,
|
||||||
0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33,
|
0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33,
|
||||||
0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61,
|
0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61,
|
||||||
0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a,
|
0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a,
|
||||||
0x1c, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e,
|
0x06, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22, 0xec, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0xae, 0x01,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x04,
|
||||||
0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x33, 0x67,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
|
0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52,
|
||||||
0x6f, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52,
|
0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64,
|
0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e,
|
||||||
0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02,
|
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x68, 0x0a, 0x04,
|
||||||
0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73,
|
0x42, 0x6f, 0x64, 0x79, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01,
|
||||||
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x24, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79,
|
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||||
0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
|
0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xae,
|
0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07,
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
|
0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e,
|
0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x22, 0xa2, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x6f,
|
||||||
0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
|
0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x04,
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04,
|
0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x33, 0x67,
|
||||||
0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
|
0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c,
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63,
|
0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79,
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65,
|
0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
|
||||||
0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x22, 0x0a, 0x04, 0x42,
|
0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77,
|
||||||
0x6f, 0x64, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x73, 0x18,
|
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
|
||||||
0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x73, 0x2a,
|
0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x1c, 0x0a,
|
||||||
0x57, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01,
|
||||||
0x1b, 0x0a, 0x17, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0xd8, 0x01, 0x0a, 0x13,
|
||||||
0x5f, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
|
0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45,
|
0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e,
|
0x0b, 0x32, 0x26, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x32, 0xba, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e,
|
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71,
|
||||||
0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0b, 0x48,
|
0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12,
|
||||||
0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x73, 0x33, 0x67,
|
0x35, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
|
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||||
0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73,
|
0x6c, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67,
|
||||||
0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c,
|
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x4e, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x32,
|
||||||
0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a,
|
||||||
0x52, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x20,
|
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x6f,
|
||||||
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50, 0x75,
|
0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67,
|
||||||
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x1a, 0x21, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e,
|
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xae, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50,
|
||||||
0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c,
|
0x3b, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e,
|
||||||
0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e,
|
0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c, 0x69, 0x73,
|
||||||
0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63,
|
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x33, 0x67,
|
0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09,
|
||||||
0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53,
|
||||||
0x12, 0x4c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x2e,
|
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
|
||||||
0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74,
|
0x75, 0x72, 0x65, 0x1a, 0x22, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x63,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
|
0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x63,
|
||||||
0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74,
|
0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x73, 0x2a, 0x57, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55,
|
0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x17, 0x48, 0x45, 0x41, 0x4c, 0x54,
|
||||||
0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x21,
|
0x48, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e,
|
||||||
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c, 0x69,
|
0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47,
|
||||||
0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x11, 0x0a,
|
||||||
0x74, 0x1a, 0x22, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
0x0d, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03,
|
||||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73,
|
0x2a, 0x57, 0x0a, 0x0c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x2e, 0x66, 0x72, 0x6f,
|
0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x55, 0x4e, 0x44, 0x45, 0x46,
|
||||||
0x73, 0x74, 0x66, 0x73, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x54, 0x72, 0x75, 0x65, 0x43, 0x6c,
|
0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49,
|
||||||
0x6f, 0x75, 0x64, 0x4c, 0x61, 0x62, 0x2f, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2d, 0x73,
|
0x4e, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x50, 0x41,
|
||||||
0x33, 0x2d, 0x67, 0x77, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
0x43, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x03, 0x12, 0x09,
|
||||||
0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x0a, 0x05, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x04, 0x32, 0xba, 0x03, 0x0a, 0x0e, 0x43, 0x6f,
|
||||||
|
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0b,
|
||||||
|
0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x73, 0x33,
|
||||||
|
0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
||||||
|
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e,
|
||||||
|
0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61,
|
||||||
|
0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
|
0x12, 0x52, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12,
|
||||||
|
0x20, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x50,
|
||||||
|
0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
|
0x74, 0x1a, 0x21, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
|
0x2e, 0x50, 0x75, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||||
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f,
|
||||||
|
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f,
|
||||||
|
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x6c, 0x69,
|
||||||
|
0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x33,
|
||||||
|
0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||||
|
0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
|
0x65, 0x12, 0x4c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e,
|
||||||
|
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65,
|
||||||
|
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f,
|
||||||
|
0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x47, 0x65,
|
||||||
|
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
|
0x55, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12,
|
||||||
|
0x21, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c,
|
||||||
|
0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
|
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||||
|
0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
||||||
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x2e, 0x66, 0x72,
|
||||||
|
0x6f, 0x73, 0x74, 0x66, 0x73, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x54, 0x72, 0x75, 0x65, 0x43,
|
||||||
|
0x6c, 0x6f, 0x75, 0x64, 0x4c, 0x61, 0x62, 0x2f, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2d,
|
||||||
|
0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||||
|
0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1458,73 +1572,78 @@ func file_pkg_service_control_service_proto_rawDescGZIP() []byte {
|
||||||
return file_pkg_service_control_service_proto_rawDescData
|
return file_pkg_service_control_service_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_pkg_service_control_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_pkg_service_control_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_pkg_service_control_service_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
|
var file_pkg_service_control_service_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
|
||||||
var file_pkg_service_control_service_proto_goTypes = []interface{}{
|
var file_pkg_service_control_service_proto_goTypes = []interface{}{
|
||||||
(HealthStatus)(0), // 0: s3gw.control.HealthStatus
|
(HealthStatus)(0), // 0: s3gw.control.HealthStatus
|
||||||
(*Signature)(nil), // 1: s3gw.control.Signature
|
(PolicyTarget)(0), // 1: s3gw.control.PolicyTarget
|
||||||
(*HealthCheckRequest)(nil), // 2: s3gw.control.HealthCheckRequest
|
(*Signature)(nil), // 2: s3gw.control.Signature
|
||||||
(*HealthCheckResponse)(nil), // 3: s3gw.control.HealthCheckResponse
|
(*HealthCheckRequest)(nil), // 3: s3gw.control.HealthCheckRequest
|
||||||
(*PutPoliciesRequest)(nil), // 4: s3gw.control.PutPoliciesRequest
|
(*HealthCheckResponse)(nil), // 4: s3gw.control.HealthCheckResponse
|
||||||
(*PutPoliciesResponse)(nil), // 5: s3gw.control.PutPoliciesResponse
|
(*PutPoliciesRequest)(nil), // 5: s3gw.control.PutPoliciesRequest
|
||||||
(*RemovePoliciesRequest)(nil), // 6: s3gw.control.RemovePoliciesRequest
|
(*PutPoliciesResponse)(nil), // 6: s3gw.control.PutPoliciesResponse
|
||||||
(*RemovePoliciesResponse)(nil), // 7: s3gw.control.RemovePoliciesResponse
|
(*RemovePoliciesRequest)(nil), // 7: s3gw.control.RemovePoliciesRequest
|
||||||
(*GetPolicyRequest)(nil), // 8: s3gw.control.GetPolicyRequest
|
(*RemovePoliciesResponse)(nil), // 8: s3gw.control.RemovePoliciesResponse
|
||||||
(*GetPolicyResponse)(nil), // 9: s3gw.control.GetPolicyResponse
|
(*GetPolicyRequest)(nil), // 9: s3gw.control.GetPolicyRequest
|
||||||
(*ListPoliciesRequest)(nil), // 10: s3gw.control.ListPoliciesRequest
|
(*GetPolicyResponse)(nil), // 10: s3gw.control.GetPolicyResponse
|
||||||
(*ListPoliciesResponse)(nil), // 11: s3gw.control.ListPoliciesResponse
|
(*ListPoliciesRequest)(nil), // 11: s3gw.control.ListPoliciesRequest
|
||||||
(*HealthCheckRequest_Body)(nil), // 12: s3gw.control.HealthCheckRequest.Body
|
(*ListPoliciesResponse)(nil), // 12: s3gw.control.ListPoliciesResponse
|
||||||
(*HealthCheckResponse_Body)(nil), // 13: s3gw.control.HealthCheckResponse.Body
|
(*HealthCheckRequest_Body)(nil), // 13: s3gw.control.HealthCheckRequest.Body
|
||||||
(*PutPoliciesRequest_ChainData)(nil), // 14: s3gw.control.PutPoliciesRequest.ChainData
|
(*HealthCheckResponse_Body)(nil), // 14: s3gw.control.HealthCheckResponse.Body
|
||||||
(*PutPoliciesRequest_Body)(nil), // 15: s3gw.control.PutPoliciesRequest.Body
|
(*PutPoliciesRequest_ChainData)(nil), // 15: s3gw.control.PutPoliciesRequest.ChainData
|
||||||
(*PutPoliciesResponse_Body)(nil), // 16: s3gw.control.PutPoliciesResponse.Body
|
(*PutPoliciesRequest_Body)(nil), // 16: s3gw.control.PutPoliciesRequest.Body
|
||||||
(*RemovePoliciesRequest_ChainInfo)(nil), // 17: s3gw.control.RemovePoliciesRequest.ChainInfo
|
(*PutPoliciesResponse_Body)(nil), // 17: s3gw.control.PutPoliciesResponse.Body
|
||||||
(*RemovePoliciesRequest_Body)(nil), // 18: s3gw.control.RemovePoliciesRequest.Body
|
(*RemovePoliciesRequest_ChainInfo)(nil), // 18: s3gw.control.RemovePoliciesRequest.ChainInfo
|
||||||
(*RemovePoliciesResponse_Body)(nil), // 19: s3gw.control.RemovePoliciesResponse.Body
|
(*RemovePoliciesRequest_Body)(nil), // 19: s3gw.control.RemovePoliciesRequest.Body
|
||||||
(*GetPolicyRequest_Body)(nil), // 20: s3gw.control.GetPolicyRequest.Body
|
(*RemovePoliciesResponse_Body)(nil), // 20: s3gw.control.RemovePoliciesResponse.Body
|
||||||
(*GetPolicyResponse_Body)(nil), // 21: s3gw.control.GetPolicyResponse.Body
|
(*GetPolicyRequest_Body)(nil), // 21: s3gw.control.GetPolicyRequest.Body
|
||||||
(*ListPoliciesRequest_Body)(nil), // 22: s3gw.control.ListPoliciesRequest.Body
|
(*GetPolicyResponse_Body)(nil), // 22: s3gw.control.GetPolicyResponse.Body
|
||||||
(*ListPoliciesResponse_Body)(nil), // 23: s3gw.control.ListPoliciesResponse.Body
|
(*ListPoliciesRequest_Body)(nil), // 23: s3gw.control.ListPoliciesRequest.Body
|
||||||
|
(*ListPoliciesResponse_Body)(nil), // 24: s3gw.control.ListPoliciesResponse.Body
|
||||||
}
|
}
|
||||||
var file_pkg_service_control_service_proto_depIdxs = []int32{
|
var file_pkg_service_control_service_proto_depIdxs = []int32{
|
||||||
12, // 0: s3gw.control.HealthCheckRequest.body:type_name -> s3gw.control.HealthCheckRequest.Body
|
13, // 0: s3gw.control.HealthCheckRequest.body:type_name -> s3gw.control.HealthCheckRequest.Body
|
||||||
1, // 1: s3gw.control.HealthCheckRequest.signature:type_name -> s3gw.control.Signature
|
2, // 1: s3gw.control.HealthCheckRequest.signature:type_name -> s3gw.control.Signature
|
||||||
13, // 2: s3gw.control.HealthCheckResponse.body:type_name -> s3gw.control.HealthCheckResponse.Body
|
14, // 2: s3gw.control.HealthCheckResponse.body:type_name -> s3gw.control.HealthCheckResponse.Body
|
||||||
1, // 3: s3gw.control.HealthCheckResponse.signature:type_name -> s3gw.control.Signature
|
2, // 3: s3gw.control.HealthCheckResponse.signature:type_name -> s3gw.control.Signature
|
||||||
15, // 4: s3gw.control.PutPoliciesRequest.body:type_name -> s3gw.control.PutPoliciesRequest.Body
|
16, // 4: s3gw.control.PutPoliciesRequest.body:type_name -> s3gw.control.PutPoliciesRequest.Body
|
||||||
1, // 5: s3gw.control.PutPoliciesRequest.signature:type_name -> s3gw.control.Signature
|
2, // 5: s3gw.control.PutPoliciesRequest.signature:type_name -> s3gw.control.Signature
|
||||||
16, // 6: s3gw.control.PutPoliciesResponse.body:type_name -> s3gw.control.PutPoliciesResponse.Body
|
17, // 6: s3gw.control.PutPoliciesResponse.body:type_name -> s3gw.control.PutPoliciesResponse.Body
|
||||||
1, // 7: s3gw.control.PutPoliciesResponse.signature:type_name -> s3gw.control.Signature
|
2, // 7: s3gw.control.PutPoliciesResponse.signature:type_name -> s3gw.control.Signature
|
||||||
18, // 8: s3gw.control.RemovePoliciesRequest.body:type_name -> s3gw.control.RemovePoliciesRequest.Body
|
19, // 8: s3gw.control.RemovePoliciesRequest.body:type_name -> s3gw.control.RemovePoliciesRequest.Body
|
||||||
1, // 9: s3gw.control.RemovePoliciesRequest.signature:type_name -> s3gw.control.Signature
|
2, // 9: s3gw.control.RemovePoliciesRequest.signature:type_name -> s3gw.control.Signature
|
||||||
19, // 10: s3gw.control.RemovePoliciesResponse.body:type_name -> s3gw.control.RemovePoliciesResponse.Body
|
20, // 10: s3gw.control.RemovePoliciesResponse.body:type_name -> s3gw.control.RemovePoliciesResponse.Body
|
||||||
1, // 11: s3gw.control.RemovePoliciesResponse.signature:type_name -> s3gw.control.Signature
|
2, // 11: s3gw.control.RemovePoliciesResponse.signature:type_name -> s3gw.control.Signature
|
||||||
20, // 12: s3gw.control.GetPolicyRequest.body:type_name -> s3gw.control.GetPolicyRequest.Body
|
21, // 12: s3gw.control.GetPolicyRequest.body:type_name -> s3gw.control.GetPolicyRequest.Body
|
||||||
1, // 13: s3gw.control.GetPolicyRequest.signature:type_name -> s3gw.control.Signature
|
2, // 13: s3gw.control.GetPolicyRequest.signature:type_name -> s3gw.control.Signature
|
||||||
21, // 14: s3gw.control.GetPolicyResponse.body:type_name -> s3gw.control.GetPolicyResponse.Body
|
22, // 14: s3gw.control.GetPolicyResponse.body:type_name -> s3gw.control.GetPolicyResponse.Body
|
||||||
1, // 15: s3gw.control.GetPolicyResponse.signature:type_name -> s3gw.control.Signature
|
2, // 15: s3gw.control.GetPolicyResponse.signature:type_name -> s3gw.control.Signature
|
||||||
22, // 16: s3gw.control.ListPoliciesRequest.body:type_name -> s3gw.control.ListPoliciesRequest.Body
|
23, // 16: s3gw.control.ListPoliciesRequest.body:type_name -> s3gw.control.ListPoliciesRequest.Body
|
||||||
1, // 17: s3gw.control.ListPoliciesRequest.signature:type_name -> s3gw.control.Signature
|
2, // 17: s3gw.control.ListPoliciesRequest.signature:type_name -> s3gw.control.Signature
|
||||||
23, // 18: s3gw.control.ListPoliciesResponse.body:type_name -> s3gw.control.ListPoliciesResponse.Body
|
24, // 18: s3gw.control.ListPoliciesResponse.body:type_name -> s3gw.control.ListPoliciesResponse.Body
|
||||||
1, // 19: s3gw.control.ListPoliciesResponse.signature:type_name -> s3gw.control.Signature
|
2, // 19: s3gw.control.ListPoliciesResponse.signature:type_name -> s3gw.control.Signature
|
||||||
0, // 20: s3gw.control.HealthCheckResponse.Body.health_status:type_name -> s3gw.control.HealthStatus
|
0, // 20: s3gw.control.HealthCheckResponse.Body.health_status:type_name -> s3gw.control.HealthStatus
|
||||||
14, // 21: s3gw.control.PutPoliciesRequest.Body.chainDatas:type_name -> s3gw.control.PutPoliciesRequest.ChainData
|
1, // 21: s3gw.control.PutPoliciesRequest.ChainData.target:type_name -> s3gw.control.PolicyTarget
|
||||||
17, // 22: s3gw.control.RemovePoliciesRequest.Body.chainInfos:type_name -> s3gw.control.RemovePoliciesRequest.ChainInfo
|
15, // 22: s3gw.control.PutPoliciesRequest.Body.chainDatas:type_name -> s3gw.control.PutPoliciesRequest.ChainData
|
||||||
2, // 23: s3gw.control.ControlService.HealthCheck:input_type -> s3gw.control.HealthCheckRequest
|
1, // 23: s3gw.control.RemovePoliciesRequest.ChainInfo.target:type_name -> s3gw.control.PolicyTarget
|
||||||
4, // 24: s3gw.control.ControlService.PutPolicies:input_type -> s3gw.control.PutPoliciesRequest
|
18, // 24: s3gw.control.RemovePoliciesRequest.Body.chainInfos:type_name -> s3gw.control.RemovePoliciesRequest.ChainInfo
|
||||||
6, // 25: s3gw.control.ControlService.RemovePolicies:input_type -> s3gw.control.RemovePoliciesRequest
|
1, // 25: s3gw.control.GetPolicyRequest.Body.target:type_name -> s3gw.control.PolicyTarget
|
||||||
8, // 26: s3gw.control.ControlService.GetPolicy:input_type -> s3gw.control.GetPolicyRequest
|
1, // 26: s3gw.control.ListPoliciesRequest.Body.target:type_name -> s3gw.control.PolicyTarget
|
||||||
10, // 27: s3gw.control.ControlService.ListPolicies:input_type -> s3gw.control.ListPoliciesRequest
|
3, // 27: s3gw.control.ControlService.HealthCheck:input_type -> s3gw.control.HealthCheckRequest
|
||||||
3, // 28: s3gw.control.ControlService.HealthCheck:output_type -> s3gw.control.HealthCheckResponse
|
5, // 28: s3gw.control.ControlService.PutPolicies:input_type -> s3gw.control.PutPoliciesRequest
|
||||||
5, // 29: s3gw.control.ControlService.PutPolicies:output_type -> s3gw.control.PutPoliciesResponse
|
7, // 29: s3gw.control.ControlService.RemovePolicies:input_type -> s3gw.control.RemovePoliciesRequest
|
||||||
7, // 30: s3gw.control.ControlService.RemovePolicies:output_type -> s3gw.control.RemovePoliciesResponse
|
9, // 30: s3gw.control.ControlService.GetPolicy:input_type -> s3gw.control.GetPolicyRequest
|
||||||
9, // 31: s3gw.control.ControlService.GetPolicy:output_type -> s3gw.control.GetPolicyResponse
|
11, // 31: s3gw.control.ControlService.ListPolicies:input_type -> s3gw.control.ListPoliciesRequest
|
||||||
11, // 32: s3gw.control.ControlService.ListPolicies:output_type -> s3gw.control.ListPoliciesResponse
|
4, // 32: s3gw.control.ControlService.HealthCheck:output_type -> s3gw.control.HealthCheckResponse
|
||||||
28, // [28:33] is the sub-list for method output_type
|
6, // 33: s3gw.control.ControlService.PutPolicies:output_type -> s3gw.control.PutPoliciesResponse
|
||||||
23, // [23:28] is the sub-list for method input_type
|
8, // 34: s3gw.control.ControlService.RemovePolicies:output_type -> s3gw.control.RemovePoliciesResponse
|
||||||
23, // [23:23] is the sub-list for extension type_name
|
10, // 35: s3gw.control.ControlService.GetPolicy:output_type -> s3gw.control.GetPolicyResponse
|
||||||
23, // [23:23] is the sub-list for extension extendee
|
12, // 36: s3gw.control.ControlService.ListPolicies:output_type -> s3gw.control.ListPoliciesResponse
|
||||||
0, // [0:23] is the sub-list for field type_name
|
32, // [32:37] is the sub-list for method output_type
|
||||||
|
27, // [27:32] is the sub-list for method input_type
|
||||||
|
27, // [27:27] is the sub-list for extension type_name
|
||||||
|
27, // [27:27] is the sub-list for extension extendee
|
||||||
|
0, // [0:27] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_pkg_service_control_service_proto_init() }
|
func init() { file_pkg_service_control_service_proto_init() }
|
||||||
|
@ -1815,7 +1934,7 @@ func file_pkg_service_control_service_proto_init() {
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_pkg_service_control_service_proto_rawDesc,
|
RawDescriptor: file_pkg_service_control_service_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 2,
|
||||||
NumMessages: 23,
|
NumMessages: 23,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
|
|
|
@ -69,13 +69,33 @@ enum HealthStatus {
|
||||||
SHUTTING_DOWN = 3;
|
SHUTTING_DOWN = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Policy target to store chains.
|
||||||
|
enum PolicyTarget {
|
||||||
|
// Undefined target, invalid to use.
|
||||||
|
TARGET_UNDEFINED = 0;
|
||||||
|
|
||||||
|
// Container target for bucket policies.
|
||||||
|
CONTAINER = 1;
|
||||||
|
|
||||||
|
// Namespace target for namespace policies.
|
||||||
|
NAMESPACE = 2;
|
||||||
|
|
||||||
|
// User target for namespace user policies.
|
||||||
|
USER = 3;
|
||||||
|
|
||||||
|
// Group target for namespace target policies.
|
||||||
|
GROUP = 4;
|
||||||
|
}
|
||||||
|
|
||||||
// Put policies request.
|
// Put policies request.
|
||||||
message PutPoliciesRequest {
|
message PutPoliciesRequest {
|
||||||
message ChainData {
|
message ChainData {
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
string namespace = 1;
|
PolicyTarget target = 1;
|
||||||
|
// Policy name.
|
||||||
|
string name = 2;
|
||||||
// Chain rules.
|
// Chain rules.
|
||||||
bytes chain = 2;
|
bytes chain = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Body {
|
message Body {
|
||||||
|
@ -101,10 +121,12 @@ message PutPoliciesResponse {
|
||||||
// Remove policies request.
|
// Remove policies request.
|
||||||
message RemovePoliciesRequest {
|
message RemovePoliciesRequest {
|
||||||
message ChainInfo {
|
message ChainInfo {
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
string namespace = 1;
|
PolicyTarget target = 1;
|
||||||
|
// Policy name.
|
||||||
|
string name = 2;
|
||||||
// Chain id to remove.
|
// Chain id to remove.
|
||||||
bytes chainID = 2;
|
bytes chainID = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Body {
|
message Body {
|
||||||
|
@ -130,10 +152,12 @@ message RemovePoliciesResponse {
|
||||||
// Get policy request.
|
// Get policy request.
|
||||||
message GetPolicyRequest {
|
message GetPolicyRequest {
|
||||||
message Body {
|
message Body {
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
string namespace = 1;
|
PolicyTarget target = 1;
|
||||||
// Chain id to remove.
|
// Policy name.
|
||||||
bytes chainID = 2;
|
string name = 2;
|
||||||
|
// Chain id to get.
|
||||||
|
bytes chainID = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
Body body = 1;
|
Body body = 1;
|
||||||
|
@ -157,8 +181,10 @@ message GetPolicyResponse {
|
||||||
// List policies request.
|
// List policies request.
|
||||||
message ListPoliciesRequest {
|
message ListPoliciesRequest {
|
||||||
message Body {
|
message Body {
|
||||||
// Namespace.
|
// Policy entity type.
|
||||||
string namespace = 1;
|
PolicyTarget target = 1;
|
||||||
|
// Policy name.
|
||||||
|
string name = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Body body = 1;
|
Body body = 1;
|
||||||
|
|
|
@ -207,8 +207,9 @@ func (x *PutPoliciesRequest_ChainData) StableSize() (size int) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
size += proto.StringSize(1, x.Namespace)
|
size += proto.EnumSize(1, int32(x.Target))
|
||||||
size += proto.BytesSize(2, x.Chain)
|
size += proto.StringSize(2, x.Name)
|
||||||
|
size += proto.BytesSize(3, x.Chain)
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,8 +229,9 @@ func (x *PutPoliciesRequest_ChainData) StableMarshal(buf []byte) []byte {
|
||||||
buf = make([]byte, x.StableSize())
|
buf = make([]byte, x.StableSize())
|
||||||
}
|
}
|
||||||
var offset int
|
var offset int
|
||||||
offset += proto.StringMarshal(1, buf[offset:], x.Namespace)
|
offset += proto.EnumMarshal(1, buf[offset:], int32(x.Target))
|
||||||
offset += proto.BytesMarshal(2, buf[offset:], x.Chain)
|
offset += proto.StringMarshal(2, buf[offset:], x.Name)
|
||||||
|
offset += proto.BytesMarshal(3, buf[offset:], x.Chain)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,8 +409,9 @@ func (x *RemovePoliciesRequest_ChainInfo) StableSize() (size int) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
size += proto.StringSize(1, x.Namespace)
|
size += proto.EnumSize(1, int32(x.Target))
|
||||||
size += proto.BytesSize(2, x.ChainID)
|
size += proto.StringSize(2, x.Name)
|
||||||
|
size += proto.BytesSize(3, x.ChainID)
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,8 +431,9 @@ func (x *RemovePoliciesRequest_ChainInfo) StableMarshal(buf []byte) []byte {
|
||||||
buf = make([]byte, x.StableSize())
|
buf = make([]byte, x.StableSize())
|
||||||
}
|
}
|
||||||
var offset int
|
var offset int
|
||||||
offset += proto.StringMarshal(1, buf[offset:], x.Namespace)
|
offset += proto.EnumMarshal(1, buf[offset:], int32(x.Target))
|
||||||
offset += proto.BytesMarshal(2, buf[offset:], x.ChainID)
|
offset += proto.StringMarshal(2, buf[offset:], x.Name)
|
||||||
|
offset += proto.BytesMarshal(3, buf[offset:], x.ChainID)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,8 +611,9 @@ func (x *GetPolicyRequest_Body) StableSize() (size int) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
size += proto.StringSize(1, x.Namespace)
|
size += proto.EnumSize(1, int32(x.Target))
|
||||||
size += proto.BytesSize(2, x.ChainID)
|
size += proto.StringSize(2, x.Name)
|
||||||
|
size += proto.BytesSize(3, x.ChainID)
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,8 +633,9 @@ func (x *GetPolicyRequest_Body) StableMarshal(buf []byte) []byte {
|
||||||
buf = make([]byte, x.StableSize())
|
buf = make([]byte, x.StableSize())
|
||||||
}
|
}
|
||||||
var offset int
|
var offset int
|
||||||
offset += proto.StringMarshal(1, buf[offset:], x.Namespace)
|
offset += proto.EnumMarshal(1, buf[offset:], int32(x.Target))
|
||||||
offset += proto.BytesMarshal(2, buf[offset:], x.ChainID)
|
offset += proto.StringMarshal(2, buf[offset:], x.Name)
|
||||||
|
offset += proto.BytesMarshal(3, buf[offset:], x.ChainID)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +787,8 @@ func (x *ListPoliciesRequest_Body) StableSize() (size int) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
size += proto.StringSize(1, x.Namespace)
|
size += proto.EnumSize(1, int32(x.Target))
|
||||||
|
size += proto.StringSize(2, x.Name)
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +808,8 @@ func (x *ListPoliciesRequest_Body) StableMarshal(buf []byte) []byte {
|
||||||
buf = make([]byte, x.StableSize())
|
buf = make([]byte, x.StableSize())
|
||||||
}
|
}
|
||||||
var offset int
|
var offset int
|
||||||
offset += proto.StringMarshal(1, buf[offset:], x.Namespace)
|
offset += proto.EnumMarshal(1, buf[offset:], int32(x.Target))
|
||||||
|
offset += proto.StringMarshal(2, buf[offset:], x.Name)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.2.0
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
// - protoc v3.21.9
|
// - protoc v3.21.12
|
||||||
// source: pkg/service/control/service.proto
|
// source: pkg/service/control/service.proto
|
||||||
|
|
||||||
package control
|
package control
|
||||||
|
|
|
@ -32,8 +32,8 @@ type (
|
||||||
// Each method must return ErrNodeNotFound or ErrNodeAccessDenied if relevant.
|
// Each method must return ErrNodeNotFound or ErrNodeAccessDenied if relevant.
|
||||||
ServiceClient interface {
|
ServiceClient interface {
|
||||||
GetNodes(ctx context.Context, p *GetNodesParams) ([]NodeResponse, error)
|
GetNodes(ctx context.Context, p *GetNodesParams) ([]NodeResponse, error)
|
||||||
GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) ([]NodeResponse, error)
|
GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) ([]NodeResponse, error)
|
||||||
GetSubTreeStream(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) (SubTreeStream, error)
|
GetSubTreeStream(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) (SubTreeStream, error)
|
||||||
AddNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, parent uint64, meta map[string]string) (uint64, error)
|
AddNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, parent uint64, meta map[string]string) (uint64, error)
|
||||||
AddNodeByPath(ctx context.Context, bktInfo *data.BucketInfo, treeID string, path []string, meta map[string]string) (uint64, error)
|
AddNodeByPath(ctx context.Context, bktInfo *data.BucketInfo, treeID string, path []string, meta map[string]string) (uint64, error)
|
||||||
MoveNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID, parentID uint64, meta map[string]string) error
|
MoveNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID, parentID uint64, meta map[string]string) error
|
||||||
|
@ -45,10 +45,10 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
treeNode struct {
|
treeNode struct {
|
||||||
ID uint64
|
ID []uint64
|
||||||
ParentID uint64
|
ParentID []uint64
|
||||||
ObjID oid.ID
|
ObjID oid.ID
|
||||||
TimeStamp uint64
|
TimeStamp []uint64
|
||||||
Size uint64
|
Size uint64
|
||||||
Meta map[string]string
|
Meta map[string]string
|
||||||
}
|
}
|
||||||
|
@ -140,38 +140,46 @@ type Meta interface {
|
||||||
|
|
||||||
type NodeResponse interface {
|
type NodeResponse interface {
|
||||||
GetMeta() []Meta
|
GetMeta() []Meta
|
||||||
GetNodeID() uint64
|
GetNodeID() []uint64
|
||||||
GetParentID() uint64
|
GetParentID() []uint64
|
||||||
GetTimestamp() uint64
|
GetTimestamp() []uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTreeNode(nodeInfo NodeResponse) (*treeNode, error) {
|
func newTreeNode(nodeInfo NodeResponse) (*treeNode, error) {
|
||||||
treeNode := &treeNode{
|
tNode := &treeNode{
|
||||||
ID: nodeInfo.GetNodeID(),
|
ID: nodeInfo.GetNodeID(),
|
||||||
ParentID: nodeInfo.GetParentID(),
|
ParentID: nodeInfo.GetParentID(),
|
||||||
TimeStamp: nodeInfo.GetTimestamp(),
|
TimeStamp: nodeInfo.GetTimestamp(),
|
||||||
Meta: make(map[string]string, len(nodeInfo.GetMeta())),
|
Meta: make(map[string]string, len(nodeInfo.GetMeta())),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(tNode.ID) == 0 || len(tNode.ParentID) == 0 || len(tNode.TimeStamp) == 0 {
|
||||||
|
return nil, errors.New("invalid tree node: missing id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tNode.ID) != len(tNode.ParentID) || len(tNode.ID) != len(tNode.TimeStamp) {
|
||||||
|
return nil, errors.New("invalid tree node: length multiple ids mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
for _, kv := range nodeInfo.GetMeta() {
|
for _, kv := range nodeInfo.GetMeta() {
|
||||||
switch kv.GetKey() {
|
switch kv.GetKey() {
|
||||||
case oidKV:
|
case oidKV:
|
||||||
if err := treeNode.ObjID.DecodeString(string(kv.GetValue())); err != nil {
|
if err := tNode.ObjID.DecodeString(string(kv.GetValue())); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case sizeKV:
|
case sizeKV:
|
||||||
if sizeStr := string(kv.GetValue()); len(sizeStr) > 0 {
|
if sizeStr := string(kv.GetValue()); len(sizeStr) > 0 {
|
||||||
var err error
|
var err error
|
||||||
if treeNode.Size, err = strconv.ParseUint(sizeStr, 10, 64); err != nil {
|
if tNode.Size, err = strconv.ParseUint(sizeStr, 10, 64); err != nil {
|
||||||
return nil, fmt.Errorf("invalid size value '%s': %w", sizeStr, err)
|
return nil, fmt.Errorf("invalid size value '%s': %w", sizeStr, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
treeNode.Meta[kv.GetKey()] = string(kv.GetValue())
|
tNode.Meta[kv.GetKey()] = string(kv.GetValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return treeNode, nil
|
return tNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *treeNode) Get(key string) (string, bool) {
|
func (n *treeNode) Get(key string) (string, bool) {
|
||||||
|
@ -184,28 +192,52 @@ func (n *treeNode) FileName() (string, bool) {
|
||||||
return value, ok
|
return value, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *treeNode) IsSplit() bool {
|
||||||
|
return len(n.ID) != 1 || len(n.ParentID) != 1 || len(n.TimeStamp) != 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *treeNode) GetLatestNodeIndex() int {
|
||||||
|
var (
|
||||||
|
maxTimestamp uint64
|
||||||
|
index int
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, timestamp := range n.TimeStamp {
|
||||||
|
if timestamp > maxTimestamp {
|
||||||
|
maxTimestamp = timestamp
|
||||||
|
index = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
func newNodeVersion(log *zap.Logger, filePath string, node NodeResponse) (*data.NodeVersion, error) {
|
func newNodeVersion(log *zap.Logger, filePath string, node NodeResponse) (*data.NodeVersion, error) {
|
||||||
treeNode, err := newTreeNode(node)
|
tNode, err := newTreeNode(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid tree node: %w", err)
|
return nil, fmt.Errorf("invalid tree node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newNodeVersionFromTreeNode(log, filePath, treeNode), nil
|
return newNodeVersionFromTreeNode(log, filePath, tNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNodeVersionFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) *data.NodeVersion {
|
func newNodeVersionFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) (*data.NodeVersion, error) {
|
||||||
_, isUnversioned := treeNode.Get(isUnversionedKV)
|
_, isUnversioned := treeNode.Get(isUnversionedKV)
|
||||||
_, isDeleteMarker := treeNode.Get(isDeleteMarkerKV)
|
_, isDeleteMarker := treeNode.Get(isDeleteMarkerKV)
|
||||||
_, isCombined := treeNode.Get(isCombinedKV)
|
_, isCombined := treeNode.Get(isCombinedKV)
|
||||||
eTag, _ := treeNode.Get(etagKV)
|
eTag, _ := treeNode.Get(etagKV)
|
||||||
md5, _ := treeNode.Get(md5KV)
|
md5, _ := treeNode.Get(md5KV)
|
||||||
|
|
||||||
|
if treeNode.IsSplit() {
|
||||||
|
return nil, errors.New("invalid version tree node: this is split node")
|
||||||
|
}
|
||||||
|
|
||||||
version := &data.NodeVersion{
|
version := &data.NodeVersion{
|
||||||
BaseNodeVersion: data.BaseNodeVersion{
|
BaseNodeVersion: data.BaseNodeVersion{
|
||||||
ID: treeNode.ID,
|
ID: treeNode.ID[0],
|
||||||
ParenID: treeNode.ParentID,
|
ParenID: treeNode.ParentID[0],
|
||||||
OID: treeNode.ObjID,
|
OID: treeNode.ObjID,
|
||||||
Timestamp: treeNode.TimeStamp,
|
Timestamp: treeNode.TimeStamp[0],
|
||||||
ETag: eTag,
|
ETag: eTag,
|
||||||
MD5: md5,
|
MD5: md5,
|
||||||
Size: treeNode.Size,
|
Size: treeNode.Size,
|
||||||
|
@ -234,7 +266,7 @@ func newNodeVersionFromTreeNode(log *zap.Logger, filePath string, treeNode *tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return version
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) (*data.MultipartInfo, error) {
|
func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) (*data.MultipartInfo, error) {
|
||||||
|
@ -243,8 +275,12 @@ func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *tr
|
||||||
return nil, fmt.Errorf("it's not a multipart node: missing UploadId")
|
return nil, fmt.Errorf("it's not a multipart node: missing UploadId")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if treeNode.IsSplit() {
|
||||||
|
return nil, fmt.Errorf("invalid multipart node '%s': tree node is split", filePath)
|
||||||
|
}
|
||||||
|
|
||||||
multipartInfo := &data.MultipartInfo{
|
multipartInfo := &data.MultipartInfo{
|
||||||
ID: treeNode.ID,
|
ID: treeNode.ID[0],
|
||||||
Key: filePath,
|
Key: filePath,
|
||||||
UploadID: uploadID,
|
UploadID: uploadID,
|
||||||
Meta: treeNode.Meta,
|
Meta: treeNode.Meta,
|
||||||
|
@ -276,8 +312,12 @@ func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *tr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMultipartInfo(log *zap.Logger, node NodeResponse) (*data.MultipartInfo, error) {
|
func newMultipartInfo(log *zap.Logger, node NodeResponse) (*data.MultipartInfo, error) {
|
||||||
|
if len(node.GetNodeID()) != 1 {
|
||||||
|
return nil, errors.New("invalid multipart node: this is split node")
|
||||||
|
}
|
||||||
|
|
||||||
multipartInfo := &data.MultipartInfo{
|
multipartInfo := &data.MultipartInfo{
|
||||||
ID: node.GetNodeID(),
|
ID: node.GetNodeID()[0],
|
||||||
Meta: make(map[string]string, len(node.GetMeta())),
|
Meta: make(map[string]string, len(node.GetMeta())),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,8 +395,7 @@ func newPartInfo(node NodeResponse) (*data.PartInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
|
func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
|
||||||
keysToReturn := []string{versioningKV, lockConfigurationKV, cannedACLKV, ownerKeyKV}
|
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName})
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName}, keysToReturn)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't get node: %w", err)
|
return nil, fmt.Errorf("couldn't get node: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -384,7 +423,7 @@ func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) error {
|
func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) error {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName}, []string{})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return fmt.Errorf("couldn't get node: %w", err)
|
return fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -397,11 +436,16 @@ func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, se
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.service.MoveNode(ctx, bktInfo, systemTree, node.ID, 0, meta)
|
ind := node.GetLatestNodeIndex()
|
||||||
|
if node.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketSettingsNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetNotificationConfigurationNode(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
func (c *Tree) GetNotificationConfigurationNode(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{notifConfFileName}, []string{oidKV})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{notifConfFileName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oid.ID{}, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
@ -410,7 +454,7 @@ func (c *Tree) GetNotificationConfigurationNode(ctx context.Context, bktInfo *da
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutNotificationConfigurationNode(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
func (c *Tree) PutNotificationConfigurationNode(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{notifConfFileName}, []string{oidKV})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{notifConfFileName})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
|
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -427,11 +471,16 @@ func (c *Tree) PutNotificationConfigurationNode(ctx context.Context, bktInfo *da
|
||||||
return oid.ID{}, layer.ErrNoNodeToRemove
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.ObjID, c.service.MoveNode(ctx, bktInfo, systemTree, node.ID, 0, meta)
|
ind := node.GetLatestNodeIndex()
|
||||||
|
if node.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralNotificationConfigurationNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.ObjID, c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
func (c *Tree) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename}, []string{oidKV})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oid.ID{}, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
@ -440,7 +489,7 @@ func (c *Tree) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename}, []string{oidKV})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
|
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -457,17 +506,27 @@ func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objI
|
||||||
return oid.ID{}, layer.ErrNoNodeToRemove
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.ObjID, c.service.MoveNode(ctx, bktInfo, systemTree, node.ID, 0, meta)
|
ind := node.GetLatestNodeIndex()
|
||||||
|
if node.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketCorsNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.ObjID, c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
func (c *Tree) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename}, []string{oidKV})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
|
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
|
||||||
return oid.ID{}, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if node != nil {
|
if node != nil {
|
||||||
return node.ObjID, c.service.RemoveNode(ctx, bktInfo, systemTree, node.ID)
|
ind := node.GetLatestNodeIndex()
|
||||||
|
if node.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketCorsNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.ObjID, c.service.RemoveNode(ctx, bktInfo, systemTree, node.ID[ind])
|
||||||
}
|
}
|
||||||
|
|
||||||
return oid.ID{}, layer.ErrNoNodeToRemove
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
|
@ -513,11 +572,15 @@ func (c *Tree) PutObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, o
|
||||||
|
|
||||||
if tagNode == nil {
|
if tagNode == nil {
|
||||||
_, err = c.service.AddNode(ctx, bktInfo, versionTree, objVersion.ID, treeTagSet)
|
_, err = c.service.AddNode(ctx, bktInfo, versionTree, objVersion.ID, treeTagSet)
|
||||||
} else {
|
return err
|
||||||
err = c.service.MoveNode(ctx, bktInfo, versionTree, tagNode.ID, objVersion.ID, treeTagSet)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
ind := tagNode.GetLatestNodeIndex()
|
||||||
|
if tagNode.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralObjectTaggingNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.service.MoveNode(ctx, bktInfo, versionTree, tagNode.ID[ind], objVersion.ID, treeTagSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) error {
|
func (c *Tree) DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) error {
|
||||||
|
@ -525,7 +588,7 @@ func (c *Tree) DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
|
func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
|
||||||
node, err := c.getSystemNodeWithAllAttributes(ctx, bktInfo, []string{bucketTaggingFilename})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{bucketTaggingFilename})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -542,7 +605,7 @@ func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
|
func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, []string{bucketTaggingFilename}, []string{})
|
node, err := c.getSystemNode(ctx, bktInfo, []string{bucketTaggingFilename})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return fmt.Errorf("couldn't get node: %w", err)
|
return fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -557,11 +620,15 @@ func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, t
|
||||||
|
|
||||||
if isErrNotFound {
|
if isErrNotFound {
|
||||||
_, err = c.service.AddNode(ctx, bktInfo, systemTree, 0, treeTagSet)
|
_, err = c.service.AddNode(ctx, bktInfo, systemTree, 0, treeTagSet)
|
||||||
} else {
|
return err
|
||||||
err = c.service.MoveNode(ctx, bktInfo, systemTree, node.ID, 0, treeTagSet)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
ind := node.GetLatestNodeIndex()
|
||||||
|
if node.IsSplit() {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketTaggingNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, treeTagSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
|
func (c *Tree) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
|
||||||
|
@ -579,7 +646,7 @@ func (c *Tree) getTreeNode(ctx context.Context, bktInfo *data.BucketInfo, nodeID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getTreeNodes(ctx context.Context, bktInfo *data.BucketInfo, nodeID uint64, keys ...string) (map[string]*treeNode, error) {
|
func (c *Tree) getTreeNodes(ctx context.Context, bktInfo *data.BucketInfo, nodeID uint64, keys ...string) (map[string]*treeNode, error) {
|
||||||
subtree, err := c.service.GetSubTree(ctx, bktInfo, versionTree, nodeID, 2)
|
subtree, err := c.service.GetSubTree(ctx, bktInfo, versionTree, []uint64{nodeID}, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -610,7 +677,7 @@ func (c *Tree) GetVersions(ctx context.Context, bktInfo *data.BucketInfo, filepa
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetLatestVersion(ctx context.Context, bktInfo *data.BucketInfo, objectName string) (*data.NodeVersion, error) {
|
func (c *Tree) GetLatestVersion(ctx context.Context, bktInfo *data.BucketInfo, objectName string) (*data.NodeVersion, error) {
|
||||||
meta := []string{oidKV, isUnversionedKV, isDeleteMarkerKV, etagKV, sizeKV, md5KV}
|
meta := []string{oidKV, isCombinedKV, isUnversionedKV, isDeleteMarkerKV, etagKV, sizeKV, md5KV}
|
||||||
path := pathFromName(objectName)
|
path := pathFromName(objectName)
|
||||||
|
|
||||||
p := &GetNodesParams{
|
p := &GetNodesParams{
|
||||||
|
@ -626,7 +693,7 @@ func (c *Tree) GetLatestVersion(ctx context.Context, bktInfo *data.BucketInfo, o
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
latestNode, err := getLatestNode(nodes)
|
latestNode, err := getLatestVersionNode(nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -634,17 +701,20 @@ func (c *Tree) GetLatestVersion(ctx context.Context, bktInfo *data.BucketInfo, o
|
||||||
return newNodeVersion(c.reqLogger(ctx), objectName, latestNode)
|
return newNodeVersion(c.reqLogger(ctx), objectName, latestNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLatestNode(nodes []NodeResponse) (NodeResponse, error) {
|
func getLatestVersionNode(nodes []NodeResponse) (NodeResponse, error) {
|
||||||
var (
|
var (
|
||||||
maxCreationTime uint64
|
maxCreationTime uint64
|
||||||
targetIndexNode = -1
|
targetIndexNode = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, node := range nodes {
|
for i, node := range nodes {
|
||||||
currentCreationTime := node.GetTimestamp()
|
if !checkExistOID(node.GetMeta()) {
|
||||||
if checkExistOID(node.GetMeta()) && currentCreationTime > maxCreationTime {
|
continue
|
||||||
maxCreationTime = currentCreationTime
|
}
|
||||||
|
|
||||||
|
if currentCreationTime := getMaxTimestamp(node); currentCreationTime > maxCreationTime {
|
||||||
targetIndexNode = i
|
targetIndexNode = i
|
||||||
|
maxCreationTime = currentCreationTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,6 +725,38 @@ func getLatestNode(nodes []NodeResponse) (NodeResponse, error) {
|
||||||
return nodes[targetIndexNode], nil
|
return nodes[targetIndexNode], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLatestNode(nodes []NodeResponse) NodeResponse {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index int
|
||||||
|
maxTimestamp uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, node := range nodes {
|
||||||
|
if timestamp := getMaxTimestamp(node); timestamp > maxTimestamp {
|
||||||
|
index = i
|
||||||
|
maxTimestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMaxTimestamp(node NodeResponse) uint64 {
|
||||||
|
var maxTimestamp uint64
|
||||||
|
|
||||||
|
for _, timestamp := range node.GetTimestamp() {
|
||||||
|
if timestamp > maxTimestamp {
|
||||||
|
maxTimestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
func checkExistOID(meta []Meta) bool {
|
func checkExistOID(meta []Meta) bool {
|
||||||
for _, kv := range meta {
|
for _, kv := range meta {
|
||||||
if kv.GetKey() == "OID" {
|
if kv.GetKey() == "OID" {
|
||||||
|
@ -684,10 +786,28 @@ func (s *DummySubTreeStream) Next() (NodeResponse, error) {
|
||||||
return s.data, nil
|
return s.data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MultiID []uint64
|
||||||
|
|
||||||
|
func (m MultiID) Equal(id MultiID) bool {
|
||||||
|
seen := make(map[uint64]struct{}, len(m))
|
||||||
|
|
||||||
|
for i := range m {
|
||||||
|
seen[m[i]] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range id {
|
||||||
|
if _, ok := seen[id[i]]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type VersionsByPrefixStreamImpl struct {
|
type VersionsByPrefixStreamImpl struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
rootID uint64
|
rootID MultiID
|
||||||
intermediateRootID uint64
|
intermediateRootID MultiID
|
||||||
service ServiceClient
|
service ServiceClient
|
||||||
bktInfo *data.BucketInfo
|
bktInfo *data.BucketInfo
|
||||||
mainStream SubTreeStream
|
mainStream SubTreeStream
|
||||||
|
@ -729,7 +849,7 @@ func (s *VersionsByPrefixStreamImpl) Next(context.Context) (*data.NodeVersion, e
|
||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
s.innerStream = nil
|
s.innerStream = nil
|
||||||
maps.Clear(s.namesMap)
|
maps.Clear(s.namesMap)
|
||||||
if s.currentLatest != nil && s.currentLatest.ID != s.intermediateRootID {
|
if s.currentLatest != nil && !s.intermediateRootID.Equal([]uint64{s.currentLatest.ID}) {
|
||||||
return s.currentLatest, nil
|
return s.currentLatest, nil
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
@ -750,14 +870,14 @@ func (s *VersionsByPrefixStreamImpl) getNodeFromMainStream() (NodeResponse, erro
|
||||||
return nil, fmt.Errorf("main stream next: %w", err)
|
return nil, fmt.Errorf("main stream next: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.GetNodeID() != s.rootID && strings.HasPrefix(getFilename(node), s.tailPrefix) {
|
if !s.rootID.Equal(node.GetNodeID()) && strings.HasPrefix(getFilename(node), s.tailPrefix) {
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *VersionsByPrefixStreamImpl) initInnerStream(node NodeResponse) (err error) {
|
func (s *VersionsByPrefixStreamImpl) initInnerStream(node NodeResponse) (err error) {
|
||||||
if node.GetParentID() == s.rootID {
|
if s.rootID.Equal(node.GetParentID()) {
|
||||||
s.intermediateRootID = node.GetNodeID()
|
s.intermediateRootID = node.GetNodeID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,20 +944,23 @@ func (s *VersionsByPrefixStreamImpl) parseNodeResponse(node NodeResponse) (res *
|
||||||
}
|
}
|
||||||
|
|
||||||
var filepath string
|
var filepath string
|
||||||
if trNode.ID != s.intermediateRootID {
|
if !s.intermediateRootID.Equal(trNode.ID) {
|
||||||
if filepath, err = formFilePath(node, fileName, s.namesMap); err != nil {
|
if filepath, err = formFilePath(node, fileName, s.namesMap); err != nil {
|
||||||
return nil, false, fmt.Errorf("invalid node order: %w", err)
|
return nil, false, fmt.Errorf("invalid node order: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filepath = parentPrefix + fileName
|
filepath = parentPrefix + fileName
|
||||||
s.namesMap[trNode.ID] = filepath
|
for _, id := range trNode.ID {
|
||||||
|
s.namesMap[id] = filepath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if trNode.ObjID.Equals(oid.ID{}) { // The node can be intermediate, but we still want to update namesMap
|
if trNode.ObjID.Equals(oid.ID{}) { // The node can be intermediate, but we still want to update namesMap
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return newNodeVersionFromTreeNode(s.log, filepath, trNode), false, nil
|
nodeVersion, err := newNodeVersionFromTreeNode(s.log, filepath, trNode)
|
||||||
|
return nodeVersion, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) InitVersionsByPrefixStream(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) (data.VersionsStream, error) {
|
func (c *Tree) InitVersionsByPrefixStream(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) (data.VersionsStream, error) {
|
||||||
|
@ -863,28 +986,28 @@ func (c *Tree) InitVersionsByPrefixStream(ctx context.Context, bktInfo *data.Buc
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getSubTreeByPrefixMainStream(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string) (SubTreeStream, string, uint64, error) {
|
func (c *Tree) getSubTreeByPrefixMainStream(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string) (SubTreeStream, string, []uint64, error) {
|
||||||
rootID, tailPrefix, err := c.determinePrefixNode(ctx, bktInfo, treeID, prefix)
|
rootID, tailPrefix, err := c.determinePrefixNode(ctx, bktInfo, treeID, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, layer.ErrNodeNotFound) {
|
if errors.Is(err, layer.ErrNodeNotFound) {
|
||||||
return nil, "", 0, io.EOF
|
return nil, "", nil, io.EOF
|
||||||
}
|
}
|
||||||
return nil, "", 0, err
|
return nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
subTree, err := c.service.GetSubTreeStream(ctx, bktInfo, treeID, rootID, 2)
|
subTree, err := c.service.GetSubTreeStream(ctx, bktInfo, treeID, rootID, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, layer.ErrNodeNotFound) {
|
if errors.Is(err, layer.ErrNodeNotFound) {
|
||||||
return nil, "", 0, io.EOF
|
return nil, "", nil, io.EOF
|
||||||
}
|
}
|
||||||
return nil, "", 0, err
|
return nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return subTree, tailPrefix, rootID, nil
|
return subTree, tailPrefix, rootID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) determinePrefixNode(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string) (uint64, string, error) {
|
func (c *Tree) determinePrefixNode(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string) ([]uint64, string, error) {
|
||||||
var rootID uint64
|
rootID := []uint64{0}
|
||||||
path := strings.Split(prefix, separator)
|
path := strings.Split(prefix, separator)
|
||||||
tailPrefix := path[len(path)-1]
|
tailPrefix := path[len(path)-1]
|
||||||
|
|
||||||
|
@ -892,14 +1015,14 @@ func (c *Tree) determinePrefixNode(ctx context.Context, bktInfo *data.BucketInfo
|
||||||
var err error
|
var err error
|
||||||
rootID, err = c.getPrefixNodeID(ctx, bktInfo, treeID, path[:len(path)-1])
|
rootID, err = c.getPrefixNodeID(ctx, bktInfo, treeID, path[:len(path)-1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootID, tailPrefix, nil
|
return rootID, tailPrefix, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, treeID string, prefixPath []string) (uint64, error) {
|
func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, treeID string, prefixPath []string) ([]uint64, error) {
|
||||||
p := &GetNodesParams{
|
p := &GetNodesParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
TreeID: treeID,
|
TreeID: treeID,
|
||||||
|
@ -909,24 +1032,21 @@ func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, tr
|
||||||
}
|
}
|
||||||
nodes, err := c.service.GetNodes(ctx, p)
|
nodes, err := c.service.GetNodes(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var intermediateNodes []uint64
|
var intermediateNodes []uint64
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if isIntermediate(node) {
|
if isIntermediate(node) {
|
||||||
intermediateNodes = append(intermediateNodes, node.GetNodeID())
|
intermediateNodes = append(intermediateNodes, node.GetNodeID()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(intermediateNodes) == 0 {
|
if len(intermediateNodes) == 0 {
|
||||||
return 0, layer.ErrNodeNotFound
|
return nil, layer.ErrNodeNotFound
|
||||||
}
|
|
||||||
if len(intermediateNodes) > 1 {
|
|
||||||
return 0, fmt.Errorf("found more than one intermediate nodes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return intermediateNodes[0], nil
|
return intermediateNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string, latestOnly bool) ([]NodeResponse, string, error) {
|
func (c *Tree) getSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string, latestOnly bool) ([]NodeResponse, string, error) {
|
||||||
|
@ -948,7 +1068,7 @@ func (c *Tree) getSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo,
|
||||||
|
|
||||||
nodesMap := make(map[string][]NodeResponse, len(subTree))
|
nodesMap := make(map[string][]NodeResponse, len(subTree))
|
||||||
for _, node := range subTree {
|
for _, node := range subTree {
|
||||||
if node.GetNodeID() == rootID {
|
if MultiID(rootID).Equal(node.GetNodeID()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,7 +1080,7 @@ func (c *Tree) getSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo,
|
||||||
nodes := nodesMap[fileName]
|
nodes := nodesMap[fileName]
|
||||||
|
|
||||||
// Add all nodes if flag latestOnly is false.
|
// Add all nodes if flag latestOnly is false.
|
||||||
// Add all intermediate nodes (actually should be exactly one intermediate node with the same name)
|
// Add all intermediate nodes
|
||||||
// and only latest leaf (object) nodes. To do this store and replace last leaf (object) node in nodes[0]
|
// and only latest leaf (object) nodes. To do this store and replace last leaf (object) node in nodes[0]
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
nodes = []NodeResponse{node}
|
nodes = []NodeResponse{node}
|
||||||
|
@ -968,7 +1088,7 @@ func (c *Tree) getSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo,
|
||||||
nodes = append(nodes, node)
|
nodes = append(nodes, node)
|
||||||
} else if isIntermediate(nodes[0]) {
|
} else if isIntermediate(nodes[0]) {
|
||||||
nodes = append([]NodeResponse{node}, nodes...)
|
nodes = append([]NodeResponse{node}, nodes...)
|
||||||
} else if node.GetTimestamp() > nodes[0].GetTimestamp() {
|
} else if getMaxTimestamp(node) > getMaxTimestamp(nodes[0]) {
|
||||||
nodes[0] = node
|
nodes[0] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,29 +1122,33 @@ func isIntermediate(node NodeResponse) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formFilePath(node NodeResponse, fileName string, namesMap map[uint64]string) (string, error) {
|
func formFilePath(node NodeResponse, fileName string, namesMap map[uint64]string) (string, error) {
|
||||||
parentPath, ok := namesMap[node.GetParentID()]
|
var filepath string
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("couldn't get parent path")
|
|
||||||
}
|
|
||||||
|
|
||||||
filepath := parentPath + separator + fileName
|
for i, id := range node.GetParentID() {
|
||||||
namesMap[node.GetNodeID()] = filepath
|
parentPath, ok := namesMap[id]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't get parent path")
|
||||||
|
}
|
||||||
|
|
||||||
|
filepath = parentPath + separator + fileName
|
||||||
|
namesMap[node.GetNodeID()[i]] = filepath
|
||||||
|
}
|
||||||
|
|
||||||
return filepath, nil
|
return filepath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTreeNode(node NodeResponse) (*treeNode, string, error) {
|
func parseTreeNode(node NodeResponse) (*treeNode, string, error) {
|
||||||
treeNode, err := newTreeNode(node)
|
tNode, err := newTreeNode(node)
|
||||||
if err != nil { // invalid OID attribute
|
if err != nil { // invalid OID attribute
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName, ok := treeNode.FileName()
|
fileName, ok := tNode.FileName()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", fmt.Errorf("doesn't contain FileName")
|
return nil, "", fmt.Errorf("doesn't contain FileName")
|
||||||
}
|
}
|
||||||
|
|
||||||
return treeNode, fileName, nil
|
return tNode, fileName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formLatestNodeKey(parentID uint64, fileName string) string {
|
func formLatestNodeKey(parentID uint64, fileName string) string {
|
||||||
|
@ -1091,7 +1215,7 @@ func (c *Tree) GetMultipartUploadsByPrefix(ctx context.Context, bktInfo *data.Bu
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getSubTreeMultipartUploads(ctx context.Context, bktInfo *data.BucketInfo, nodeID uint64, parentFilePath string) ([]*data.MultipartInfo, error) {
|
func (c *Tree) getSubTreeMultipartUploads(ctx context.Context, bktInfo *data.BucketInfo, nodeID []uint64, parentFilePath string) ([]*data.MultipartInfo, error) {
|
||||||
subTree, err := c.service.GetSubTree(ctx, bktInfo, systemTree, nodeID, maxGetSubTreeDepth)
|
subTree, err := c.service.GetSubTree(ctx, bktInfo, systemTree, nodeID, maxGetSubTreeDepth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1107,7 +1231,7 @@ func (c *Tree) getSubTreeMultipartUploads(ctx context.Context, bktInfo *data.Buc
|
||||||
multiparts := make(map[string][]*data.MultipartInfo, len(subTree))
|
multiparts := make(map[string][]*data.MultipartInfo, len(subTree))
|
||||||
|
|
||||||
for i, node := range subTree {
|
for i, node := range subTree {
|
||||||
treeNode, fileName, err := parseTreeNode(node)
|
tNode, fileName, err := parseTreeNode(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1118,23 +1242,27 @@ func (c *Tree) getSubTreeMultipartUploads(ctx context.Context, bktInfo *data.Buc
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filepath = parentPrefix + fileName
|
filepath = parentPrefix + fileName
|
||||||
namesMap[treeNode.ID] = filepath
|
for _, id := range tNode.ID {
|
||||||
|
namesMap[id] = filepath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
multipartInfo, err := newMultipartInfoFromTreeNode(c.reqLogger(ctx), filepath, treeNode)
|
multipartInfo, err := newMultipartInfoFromTreeNode(c.reqLogger(ctx), filepath, tNode)
|
||||||
if err != nil || multipartInfo.Finished {
|
if err != nil || multipartInfo.Finished {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
key := formLatestNodeKey(node.GetParentID(), fileName)
|
for _, id := range node.GetParentID() {
|
||||||
multipartInfos, ok := multiparts[key]
|
key := formLatestNodeKey(id, fileName)
|
||||||
if !ok {
|
multipartInfos, ok := multiparts[key]
|
||||||
multipartInfos = []*data.MultipartInfo{multipartInfo}
|
if !ok {
|
||||||
} else {
|
multipartInfos = []*data.MultipartInfo{multipartInfo}
|
||||||
multipartInfos = append(multipartInfos, multipartInfo)
|
} else {
|
||||||
}
|
multipartInfos = append(multipartInfos, multipartInfo)
|
||||||
|
}
|
||||||
|
|
||||||
multiparts[key] = multipartInfos
|
multiparts[key] = multipartInfos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*data.MultipartInfo, 0, len(multiparts))
|
result := make([]*data.MultipartInfo, 0, len(multiparts))
|
||||||
|
@ -1177,7 +1305,7 @@ func (c *Tree) GetMultipartUpload(ctx context.Context, bktInfo *data.BucketInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) AddPart(ctx context.Context, bktInfo *data.BucketInfo, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete oid.ID, err error) {
|
func (c *Tree) AddPart(ctx context.Context, bktInfo *data.BucketInfo, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete oid.ID, err error) {
|
||||||
parts, err := c.service.GetSubTree(ctx, bktInfo, systemTree, multipartNodeID, 2)
|
parts, err := c.service.GetSubTree(ctx, bktInfo, systemTree, []uint64{multipartNodeID}, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oid.ID{}, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
@ -1192,15 +1320,30 @@ func (c *Tree) AddPart(ctx context.Context, bktInfo *data.BucketInfo, multipartN
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
if part.GetNodeID() == multipartNodeID {
|
if len(part.GetNodeID()) != 1 {
|
||||||
|
// multipart parts nodeID shouldn't have multiple values
|
||||||
|
c.reqLogger(ctx).Warn(logs.UnexpectedMultiNodeIDsInSubTreeMultiParts,
|
||||||
|
zap.String("key", info.Key),
|
||||||
|
zap.String("upload id", info.UploadID),
|
||||||
|
zap.Uint64("multipart node id ", multipartNodeID),
|
||||||
|
zap.Uint64s("node ids", part.GetNodeID()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nodeID := part.GetNodeID()[0]
|
||||||
|
if nodeID == multipartNodeID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
partInfo, err := newPartInfo(part)
|
partInfo, err := newPartInfo(part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FailedToParsePartInfo,
|
||||||
|
zap.String("key", info.Key),
|
||||||
|
zap.String("upload id", info.UploadID),
|
||||||
|
zap.Uint64("multipart node id ", multipartNodeID),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if partInfo.Number == info.Number {
|
if partInfo.Number == info.Number {
|
||||||
return partInfo.OID, c.service.MoveNode(ctx, bktInfo, systemTree, part.GetNodeID(), multipartNodeID, meta)
|
return partInfo.OID, c.service.MoveNode(ctx, bktInfo, systemTree, nodeID, multipartNodeID, meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,18 +1355,29 @@ func (c *Tree) AddPart(ctx context.Context, bktInfo *data.BucketInfo, multipartN
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetParts(ctx context.Context, bktInfo *data.BucketInfo, multipartNodeID uint64) ([]*data.PartInfo, error) {
|
func (c *Tree) GetParts(ctx context.Context, bktInfo *data.BucketInfo, multipartNodeID uint64) ([]*data.PartInfo, error) {
|
||||||
parts, err := c.service.GetSubTree(ctx, bktInfo, systemTree, multipartNodeID, 2)
|
parts, err := c.service.GetSubTree(ctx, bktInfo, systemTree, []uint64{multipartNodeID}, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*data.PartInfo, 0, len(parts))
|
result := make([]*data.PartInfo, 0, len(parts))
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
if part.GetNodeID() == multipartNodeID {
|
if len(part.GetNodeID()) != 1 {
|
||||||
|
// multipart parts nodeID shouldn't have multiple values
|
||||||
|
c.reqLogger(ctx).Warn(logs.UnexpectedMultiNodeIDsInSubTreeMultiParts,
|
||||||
|
zap.Uint64("multipart node id ", multipartNodeID),
|
||||||
|
zap.Uint64s("node ids", part.GetNodeID()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if part.GetNodeID()[0] == multipartNodeID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
partInfo, err := newPartInfo(part)
|
partInfo, err := newPartInfo(part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.reqLogger(ctx).Warn(logs.FailedToParsePartInfo,
|
||||||
|
zap.Uint64("multipart node id ", multipartNodeID),
|
||||||
|
zap.Uint64s("node ids", part.GetNodeID()),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result = append(result, partInfo)
|
result = append(result, partInfo)
|
||||||
|
@ -1278,7 +1432,10 @@ func getLock(lockNode *treeNode) (*data.LockInfo, error) {
|
||||||
if lockNode == nil {
|
if lockNode == nil {
|
||||||
return &data.LockInfo{}, nil
|
return &data.LockInfo{}, nil
|
||||||
}
|
}
|
||||||
lockInfo := data.NewLockInfo(lockNode.ID)
|
if lockNode.IsSplit() {
|
||||||
|
return nil, errors.New("invalid lock node: this is split node")
|
||||||
|
}
|
||||||
|
lockInfo := data.NewLockInfo(lockNode.ID[0])
|
||||||
|
|
||||||
if legalHold, ok := lockNode.Get(legalHoldOIDKV); ok {
|
if legalHold, ok := lockNode.Get(legalHoldOIDKV); ok {
|
||||||
var legalHoldOID oid.ID
|
var legalHoldOID oid.ID
|
||||||
|
@ -1368,14 +1525,14 @@ func (c *Tree) clearOutdatedVersionInfo(ctx context.Context, bktInfo *data.Bucke
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if taggingNode != nil {
|
if taggingNode != nil {
|
||||||
return c.service.RemoveNode(ctx, bktInfo, treeID, taggingNode.ID)
|
return c.service.RemoveNode(ctx, bktInfo, treeID, taggingNode.ID[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getVersions(ctx context.Context, bktInfo *data.BucketInfo, treeID, filepath string, onlyUnversioned bool) ([]*data.NodeVersion, error) {
|
func (c *Tree) getVersions(ctx context.Context, bktInfo *data.BucketInfo, treeID, filepath string, onlyUnversioned bool) ([]*data.NodeVersion, error) {
|
||||||
keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV, etagKV, sizeKV, md5KV}
|
keysToReturn := []string{oidKV, isCombinedKV, isUnversionedKV, isDeleteMarkerKV, etagKV, sizeKV, md5KV}
|
||||||
path := pathFromName(filepath)
|
path := pathFromName(filepath)
|
||||||
p := &GetNodesParams{
|
p := &GetNodesParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
|
@ -1437,35 +1594,46 @@ func metaFromMultipart(info *data.MultipartInfo, fileName string) map[string]str
|
||||||
return info.Meta
|
return info.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, path, meta []string) (*treeNode, error) {
|
func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, path []string) (*treeNode, error) {
|
||||||
return c.getNode(ctx, bktInfo, systemTree, path, meta, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Tree) getSystemNodeWithAllAttributes(ctx context.Context, bktInfo *data.BucketInfo, path []string) (*treeNode, error) {
|
|
||||||
return c.getNode(ctx, bktInfo, systemTree, path, []string{}, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Tree) getNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, path, meta []string, allAttrs bool) (*treeNode, error) {
|
|
||||||
p := &GetNodesParams{
|
p := &GetNodesParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
TreeID: treeID,
|
TreeID: systemTree,
|
||||||
Path: path,
|
Path: path,
|
||||||
Meta: meta,
|
|
||||||
LatestOnly: false,
|
LatestOnly: false,
|
||||||
AllAttrs: allAttrs,
|
AllAttrs: true,
|
||||||
}
|
}
|
||||||
nodes, err := c.service.GetNodes(ctx, p)
|
nodes, err := c.service.GetNodes(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodes = filterMultipartNodes(nodes)
|
||||||
|
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
return nil, layer.ErrNodeNotFound
|
return nil, layer.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
return nil, fmt.Errorf("found more than one node")
|
c.reqLogger(ctx).Warn(logs.FoundSeveralSystemNodes, zap.String("path", strings.Join(path, "/")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return newTreeNode(nodes[0])
|
return newTreeNode(getLatestNode(nodes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterMultipartNodes(nodes []NodeResponse) []NodeResponse {
|
||||||
|
res := make([]NodeResponse, 0, len(nodes))
|
||||||
|
|
||||||
|
LOOP:
|
||||||
|
for _, node := range nodes {
|
||||||
|
for _, meta := range node.GetMeta() {
|
||||||
|
if meta.GetKey() == uploadIDKV {
|
||||||
|
continue LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) reqLogger(ctx context.Context) *zap.Logger {
|
func (c *Tree) reqLogger(ctx context.Context) *zap.Logger {
|
||||||
|
|
|
@ -2,12 +2,14 @@ package tree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type nodeMeta struct {
|
type nodeMeta struct {
|
||||||
|
@ -30,16 +32,16 @@ type nodeResponse struct {
|
||||||
timestamp uint64
|
timestamp uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nodeResponse) GetNodeID() uint64 {
|
func (n nodeResponse) GetNodeID() []uint64 {
|
||||||
return n.nodeID
|
return []uint64{n.nodeID}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nodeResponse) GetParentID() uint64 {
|
func (n nodeResponse) GetParentID() []uint64 {
|
||||||
return n.parentID
|
return []uint64{n.parentID}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nodeResponse) GetTimestamp() uint64 {
|
func (n nodeResponse) GetTimestamp() []uint64 {
|
||||||
return n.timestamp
|
return []uint64{n.timestamp}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nodeResponse) GetMeta() []Meta {
|
func (n nodeResponse) GetMeta() []Meta {
|
||||||
|
@ -184,6 +186,22 @@ func NewTreeServiceClientMemory() (*ServiceClientMemory, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nodeResponseWrapper struct {
|
||||||
|
nodeResponse
|
||||||
|
allAttr bool
|
||||||
|
attrs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nodeResponseWrapper) GetMeta() []Meta {
|
||||||
|
res := make([]Meta, 0, len(n.meta))
|
||||||
|
for _, value := range n.meta {
|
||||||
|
if n.allAttr || slices.Contains(n.attrs, value.key) {
|
||||||
|
res = append(res, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ServiceClientMemory) GetNodes(_ context.Context, p *GetNodesParams) ([]NodeResponse, error) {
|
func (c *ServiceClientMemory) GetNodes(_ context.Context, p *GetNodesParams) ([]NodeResponse, error) {
|
||||||
cnr, ok := c.containers[p.BktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[p.BktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -206,13 +224,17 @@ func (c *ServiceClientMemory) GetNodes(_ context.Context, p *GetNodesParams) ([]
|
||||||
|
|
||||||
res2 := make([]NodeResponse, len(res))
|
res2 := make([]NodeResponse, len(res))
|
||||||
for i, n := range res {
|
for i, n := range res {
|
||||||
res2[i] = n
|
res2[i] = nodeResponseWrapper{
|
||||||
|
nodeResponse: n,
|
||||||
|
allAttr: p.AllAttrs,
|
||||||
|
attrs: p.Meta,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res2, nil
|
return res2, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ServiceClientMemory) GetSubTree(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) ([]NodeResponse, error) {
|
func (c *ServiceClientMemory) GetSubTree(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) ([]NodeResponse, error) {
|
||||||
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -223,9 +245,11 @@ func (c *ServiceClientMemory) GetSubTree(_ context.Context, bktInfo *data.Bucket
|
||||||
return nil, ErrNodeNotFound
|
return nil, ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
sortNode(tr.treeData)
|
if len(rootID) != 1 {
|
||||||
|
return nil, errors.New("invalid rootID")
|
||||||
|
}
|
||||||
|
|
||||||
node := tr.treeData.getNode(rootID)
|
node := tr.treeData.getNode(rootID[0])
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return nil, ErrNodeNotFound
|
return nil, ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
@ -251,7 +275,7 @@ func (s *SubTreeStreamMemoryImpl) Next() (NodeResponse, error) {
|
||||||
return s.res[s.offset-1], nil
|
return s.res[s.offset-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) (SubTreeStream, error) {
|
func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) (SubTreeStream, error) {
|
||||||
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return &SubTreeStreamMemoryImpl{err: ErrNodeNotFound}, nil
|
return &SubTreeStreamMemoryImpl{err: ErrNodeNotFound}, nil
|
||||||
|
@ -262,7 +286,11 @@ func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.
|
||||||
return nil, ErrNodeNotFound
|
return nil, ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node := tr.treeData.getNode(rootID)
|
if len(rootID) != 1 {
|
||||||
|
return nil, errors.New("invalid rootID")
|
||||||
|
}
|
||||||
|
|
||||||
|
node := tr.treeData.getNode(rootID[0])
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return nil, ErrNodeNotFound
|
return nil, ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,14 +293,14 @@ func TestGetLatestNode(t *testing.T) {
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
actualNode, err := getLatestNode(tc.nodes)
|
actualNode, err := getLatestVersionNode(tc.nodes)
|
||||||
if tc.error {
|
if tc.error {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tc.exceptedNodeID, actualNode.GetNodeID())
|
require.EqualValues(t, []uint64{tc.exceptedNodeID}, actualNode.GetNodeID())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue