forked from TrueCloudLab/frostfs-sdk-go
Compare commits
No commits in common. "feat/patch/cli" and "master" have entirely different histories.
feat/patch
...
master
158 changed files with 4812 additions and 9188 deletions
|
@ -13,9 +13,9 @@ jobs:
|
|||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Run commit format checker
|
||||
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3
|
||||
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v2
|
||||
with:
|
||||
from: 'origin/${{ github.event.pull_request.base.ref }}'
|
||||
|
|
|
@ -8,24 +8,17 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
- name: golangci-lint
|
||||
uses: https://github.com/golangci/golangci-lint-action@v2
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Install linters
|
||||
run: make lint-install
|
||||
|
||||
- name: Run linters
|
||||
run: make lint
|
||||
version: latest
|
||||
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go_versions: [ '1.21', '1.22' ]
|
||||
go_versions: [ '1.19', '1.20' ]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -27,7 +27,3 @@ antlr-*.jar
|
|||
|
||||
# tempfiles
|
||||
.cache
|
||||
|
||||
# binary
|
||||
bin/
|
||||
release/
|
||||
|
|
10
.gitlint
Normal file
10
.gitlint
Normal file
|
@ -0,0 +1,10 @@
|
|||
[general]
|
||||
fail-without-commits=true
|
||||
contrib=CC1
|
||||
|
||||
[title-match-regex]
|
||||
regex=^\[\#[0-9Xx]+\]\s
|
||||
|
||||
[ignore-by-title]
|
||||
regex=^Release(.*)
|
||||
ignore=title-match-regex
|
|
@ -18,19 +18,13 @@ repos:
|
|||
- id: end-of-file-fixer
|
||||
exclude: "(.key|.interp|.tokens)$"
|
||||
|
||||
- repo: local
|
||||
- repo: https://github.com/golangci/golangci-lint
|
||||
rev: v1.51.2
|
||||
hooks:
|
||||
- id: go-unit-tests
|
||||
name: go unit tests
|
||||
entry: make test GOFLAGS=''
|
||||
pass_filenames: false
|
||||
types: [go]
|
||||
language: system
|
||||
- id: golangci-lint
|
||||
|
||||
- repo: local
|
||||
- repo: https://github.com/jorisroovers/gitlint
|
||||
rev: v0.18.0
|
||||
hooks:
|
||||
- id: make-lint
|
||||
name: Run Make Lint
|
||||
entry: make lint
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: gitlint
|
||||
stages: [commit-msg]
|
||||
|
|
24
Makefile
24
Makefile
|
@ -1,16 +1,10 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
ANTLR_VERSION="4.13.0"
|
||||
TMP_DIR := .cache
|
||||
LINT_VERSION ?= 1.56.2
|
||||
TRUECLOUDLAB_LINT_VERSION ?= 0.0.2
|
||||
OUTPUT_LINT_DIR ?= $(shell pwd)/bin
|
||||
LINT_DIR = $(OUTPUT_LINT_DIR)/golangci-lint-$(LINT_VERSION)-v$(TRUECLOUDLAB_LINT_VERSION)
|
||||
|
||||
# Run tests
|
||||
test: GOFLAGS ?= "-cover -count=1"
|
||||
test:
|
||||
@GOFLAGS=$(GOFLAGS) go test ./...
|
||||
@go test ./... -cover
|
||||
|
||||
# Pull go dependencies
|
||||
dep:
|
||||
|
@ -21,23 +15,9 @@ dep:
|
|||
@CGO_ENABLED=0 \
|
||||
go mod tidy -v && echo OK
|
||||
|
||||
# Install linters
|
||||
lint-install:
|
||||
@mkdir -p $(TMP_DIR)
|
||||
@rm -rf $(TMP_DIR)/linters
|
||||
@git -c advice.detachedHead=false clone --branch v$(TRUECLOUDLAB_LINT_VERSION) https://git.frostfs.info/TrueCloudLab/linters.git $(TMP_DIR)/linters
|
||||
@@make -C $(TMP_DIR)/linters lib CGO_ENABLED=1 OUT_DIR=$(OUTPUT_LINT_DIR)
|
||||
@rm -rf $(TMP_DIR)/linters
|
||||
@rmdir $(TMP_DIR) 2>/dev/null || true
|
||||
@CGO_ENABLED=1 GOBIN=$(LINT_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$(LINT_VERSION)
|
||||
|
||||
# Run linters
|
||||
lint:
|
||||
@if [ ! -d "$(LINT_DIR)" ]; then \
|
||||
echo "Run make lint-install"; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(LINT_DIR)/golangci-lint run
|
||||
@golangci-lint --timeout=5m run
|
||||
|
||||
# Run tests with race detection and produce coverage output
|
||||
cover:
|
||||
|
|
|
@ -42,6 +42,7 @@ Contains client for working with FrostFS.
|
|||
```go
|
||||
var prmInit client.PrmInit
|
||||
prmInit.SetDefaultPrivateKey(key) // private key for request signing
|
||||
prmInit.ResolveFrostFSFailures() // enable erroneous status parsing
|
||||
|
||||
var c client.Client
|
||||
c.Init(prmInit)
|
||||
|
@ -76,7 +77,8 @@ if needed and perform any desired action. In the case above we may want to repor
|
|||
these details to the user as well as retry an operation, possibly with different parameters.
|
||||
Status wire-format is extendable and each node can report any set of details it wants.
|
||||
The set of reserved status codes can be found in
|
||||
[FrostFS API](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/branch/master/status/types.proto).
|
||||
[FrostFS API](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/branch/master/status/types.proto). There is also
|
||||
a `client.PrmInit.ResolveFrostFSFailures()` to seamlessly convert erroneous statuses into Go error type.
|
||||
|
||||
### policy
|
||||
Contains helpers allowing conversion of placing policy from/to JSON representation
|
||||
|
|
52
ape/chain.go
52
ape/chain.go
|
@ -1,52 +0,0 @@
|
|||
package ape
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidChainRepresentation = errors.New("invalid chain representation")
|
||||
)
|
||||
|
||||
// ChainID is Chain's identifier.
|
||||
type ChainID []byte
|
||||
|
||||
// Chain is an SDK representation for v2's Chain.
|
||||
//
|
||||
// Note that Chain (as well as v2's Chain) and all related entities
|
||||
// are NOT operated by Access-Policy-Engine (APE). The client is responsible
|
||||
// to convert these types to policy-engine entities.
|
||||
type Chain struct {
|
||||
// Raw is the encoded chain kind.
|
||||
// It assumes that Raw's bytes are the result of encoding provided by
|
||||
// policy-engine package.
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
// ToV2 converts Chain to v2.
|
||||
func (c *Chain) ToV2() *apeV2.Chain {
|
||||
v2ct := new(apeV2.Chain)
|
||||
|
||||
if c.Raw != nil {
|
||||
v2Raw := new(apeV2.ChainRaw)
|
||||
v2Raw.SetRaw(c.Raw)
|
||||
v2ct.SetKind(v2Raw)
|
||||
}
|
||||
|
||||
return v2ct
|
||||
}
|
||||
|
||||
// ReadFromV2 fills Chain from v2.
|
||||
func (c *Chain) ReadFromV2(v2ct *apeV2.Chain) error {
|
||||
switch v := v2ct.GetKind().(type) {
|
||||
default:
|
||||
return fmt.Errorf("unsupported chain kind: %T", v)
|
||||
case *apeV2.ChainRaw:
|
||||
raw := v.GetRaw()
|
||||
c.Raw = raw
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package ape
|
||||
|
||||
import (
|
||||
apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape"
|
||||
)
|
||||
|
||||
// TargetType is an SDK representation for v2's TargetType.
|
||||
type TargetType apeV2.TargetType
|
||||
|
||||
const (
|
||||
TargetTypeUndefined TargetType = iota
|
||||
TargetTypeNamespace
|
||||
TargetTypeContainer
|
||||
TargetTypeUser
|
||||
TargetTypeGroup
|
||||
)
|
||||
|
||||
// ToV2 converts TargetType to v2.
|
||||
func (targetType TargetType) ToV2() apeV2.TargetType {
|
||||
return apeV2.TargetType(targetType)
|
||||
}
|
||||
|
||||
// FromV2 reads TargetType to v2.
|
||||
func (targetType *TargetType) FromV2(v2targetType apeV2.TargetType) {
|
||||
*targetType = TargetType(v2targetType)
|
||||
}
|
||||
|
||||
// ChainTarget is an SDK representation for v2's ChainTarget.
|
||||
//
|
||||
// Note that ChainTarget (as well as v2's ChainTarget) and all related entities
|
||||
// are NOT operated by Access-Policy-Engine (APE). The client is responsible
|
||||
// to convert these types to policy-engine entities.
|
||||
type ChainTarget struct {
|
||||
TargetType TargetType
|
||||
|
||||
Name string
|
||||
}
|
||||
|
||||
// ToV2 converts ChainTarget to v2.
|
||||
func (ct *ChainTarget) ToV2() *apeV2.ChainTarget {
|
||||
v2ct := new(apeV2.ChainTarget)
|
||||
|
||||
v2ct.SetTargetType(ct.TargetType.ToV2())
|
||||
v2ct.SetName(ct.Name)
|
||||
|
||||
return v2ct
|
||||
}
|
||||
|
||||
// FromV2 reads ChainTarget frpm v2.
|
||||
func (ct *ChainTarget) FromV2(v2ct *apeV2.ChainTarget) {
|
||||
ct.TargetType.FromV2(v2ct.GetTargetType())
|
||||
ct.Name = v2ct.GetName()
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package ape_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape"
|
||||
)
|
||||
|
||||
var (
|
||||
m = map[ape.TargetType]apeV2.TargetType{
|
||||
ape.TargetTypeUndefined: apeV2.TargetTypeUndefined,
|
||||
ape.TargetTypeNamespace: apeV2.TargetTypeNamespace,
|
||||
ape.TargetTypeContainer: apeV2.TargetTypeContainer,
|
||||
ape.TargetTypeUser: apeV2.TargetTypeUser,
|
||||
ape.TargetTypeGroup: apeV2.TargetTypeGroup,
|
||||
}
|
||||
)
|
||||
|
||||
func TestTargetType(t *testing.T) {
|
||||
for typesdk, typev2 := range m {
|
||||
t.Run("from sdk to v2 "+typev2.String(), func(t *testing.T) {
|
||||
v2 := typesdk.ToV2()
|
||||
require.Equal(t, v2, typev2)
|
||||
})
|
||||
|
||||
t.Run("from v2 to sdk "+typev2.String(), func(t *testing.T) {
|
||||
var typ ape.TargetType
|
||||
typ.FromV2(typev2)
|
||||
require.Equal(t, typesdk, typ)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainTarget(t *testing.T) {
|
||||
var (
|
||||
typ = ape.TargetTypeNamespace
|
||||
name = "namespaceXXYYZZ"
|
||||
)
|
||||
|
||||
t.Run("from sdk to v2", func(t *testing.T) {
|
||||
ct := ape.ChainTarget{
|
||||
TargetType: typ,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
v2 := ct.ToV2()
|
||||
require.Equal(t, m[typ], v2.GetTargetType())
|
||||
require.Equal(t, name, v2.GetName())
|
||||
})
|
||||
|
||||
t.Run("from v2 to sdk", func(t *testing.T) {
|
||||
v2 := &apeV2.ChainTarget{}
|
||||
v2.SetTargetType(m[typ])
|
||||
v2.SetName(name)
|
||||
|
||||
var ct ape.ChainTarget
|
||||
ct.FromV2(v2)
|
||||
|
||||
require.Equal(t, typ, ct.TargetType)
|
||||
require.Equal(t, name, ct.Name)
|
||||
})
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package ape_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape"
|
||||
)
|
||||
|
||||
const (
|
||||
encoded = `{"ID":"","Rules":[{"Status":"Allow","Actions":{"Inverted":false,"Names":["GetObject"]},"Resources":{"Inverted":false,"Names":["native:object/*"]},"Any":false,"Condition":[{"Op":"StringEquals","Object":"Resource","Key":"Department","Value":"HR"}]}],"MatchType":"DenyPriority"}`
|
||||
)
|
||||
|
||||
func TestChainData(t *testing.T) {
|
||||
t.Run("raw chain", func(t *testing.T) {
|
||||
var c ape.Chain
|
||||
|
||||
b := []byte(encoded)
|
||||
c.Raw = b
|
||||
|
||||
v2, ok := c.ToV2().GetKind().(*apeV2.ChainRaw)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, b, v2.Raw)
|
||||
})
|
||||
}
|
||||
|
||||
func TestChainMessageV2(t *testing.T) {
|
||||
b := []byte(encoded)
|
||||
|
||||
v2Raw := &apeV2.ChainRaw{}
|
||||
v2Raw.SetRaw(b)
|
||||
|
||||
v2 := &apeV2.Chain{}
|
||||
v2.SetKind(v2Raw)
|
||||
|
||||
var c ape.Chain
|
||||
c.ReadFromV2(v2)
|
||||
|
||||
require.NotNil(t, c.Raw)
|
||||
require.Equal(t, b, c.Raw)
|
||||
}
|
114
bearer/bearer.go
114
bearer/bearer.go
|
@ -6,9 +6,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||
apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
||||
|
@ -35,85 +33,9 @@ type Token struct {
|
|||
sigSet bool
|
||||
sig refs.Signature
|
||||
|
||||
apeOverrideSet bool
|
||||
apeOverride APEOverride
|
||||
|
||||
impersonate bool
|
||||
}
|
||||
|
||||
// APEOverride is the list of APE chains defined for a target.
|
||||
// These chains are meant to serve as overrides to the already defined (or even undefined)
|
||||
// APE chains for the target (see contract `Policy`).
|
||||
//
|
||||
// The server-side processing of the bearer token with set APE overrides must verify if a client is permitted
|
||||
// to override chains for the target, preventing unauthorized access through the APE mechanism.
|
||||
type APEOverride struct {
|
||||
// Target for which chains are applied.
|
||||
Target apeSDK.ChainTarget
|
||||
|
||||
// The list of APE chains.
|
||||
Chains []apeSDK.Chain
|
||||
}
|
||||
|
||||
// Marshal marshals APEOverride into a protobuf binary form.
|
||||
func (c *APEOverride) Marshal() ([]byte, error) {
|
||||
return c.ToV2().StableMarshal(nil), nil
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals protobuf binary representation of APEOverride.
|
||||
func (c *APEOverride) Unmarshal(data []byte) error {
|
||||
overrideV2 := new(acl.APEOverride)
|
||||
if err := overrideV2.Unmarshal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.FromV2(overrideV2)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes APEOverride to protobuf JSON format.
|
||||
func (c *APEOverride) MarshalJSON() ([]byte, error) {
|
||||
return c.ToV2().MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes APEOverride from protobuf JSON format.
|
||||
func (c *APEOverride) UnmarshalJSON(data []byte) error {
|
||||
overrideV2 := new(acl.APEOverride)
|
||||
if err := overrideV2.UnmarshalJSON(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.FromV2(overrideV2)
|
||||
}
|
||||
|
||||
func (c *APEOverride) FromV2(tokenAPEChains *acl.APEOverride) error {
|
||||
c.Target.FromV2(tokenAPEChains.GetTarget())
|
||||
if chains := tokenAPEChains.GetChains(); len(chains) > 0 {
|
||||
c.Chains = make([]apeSDK.Chain, len(chains))
|
||||
for i := range chains {
|
||||
if err := c.Chains[i].ReadFromV2(chains[i]); err != nil {
|
||||
return fmt.Errorf("invalid APE chain: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *APEOverride) ToV2() *acl.APEOverride {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
apeOverride := new(acl.APEOverride)
|
||||
apeOverride.SetTarget(c.Target.ToV2())
|
||||
chains := make([]*apeV2.Chain, len(c.Chains))
|
||||
for i := range c.Chains {
|
||||
chains[i] = c.Chains[i].ToV2()
|
||||
}
|
||||
apeOverride.SetChains(chains)
|
||||
|
||||
return apeOverride
|
||||
}
|
||||
|
||||
// reads Token from the acl.BearerToken message. If checkFieldPresence is set,
|
||||
// returns an error on absence of any protocol-required field.
|
||||
func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
|
||||
|
@ -126,11 +48,10 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
|
|||
|
||||
b.impersonate = body.GetImpersonate()
|
||||
|
||||
apeOverrides := body.GetAPEOverride()
|
||||
eaclTable := body.GetEACL()
|
||||
if b.eaclTableSet = eaclTable != nil; b.eaclTableSet {
|
||||
b.eaclTable = *eacl.NewTableFromV2(eaclTable)
|
||||
} else if checkFieldPresence && !b.impersonate && apeOverrides == nil {
|
||||
} else if checkFieldPresence && !b.impersonate {
|
||||
return errors.New("missing eACL table")
|
||||
}
|
||||
|
||||
|
@ -151,14 +72,6 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
|
|||
return errors.New("missing token lifetime")
|
||||
}
|
||||
|
||||
if b.apeOverrideSet = apeOverrides != nil; b.apeOverrideSet {
|
||||
if err = b.apeOverride.FromV2(apeOverrides); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if checkFieldPresence && !b.impersonate && !b.eaclTableSet {
|
||||
return errors.New("missing APE override")
|
||||
}
|
||||
|
||||
sig := m.GetSignature()
|
||||
if b.sigSet = sig != nil; sig != nil {
|
||||
b.sig = *sig
|
||||
|
@ -177,7 +90,7 @@ func (b *Token) ReadFromV2(m acl.BearerToken) error {
|
|||
}
|
||||
|
||||
func (b Token) fillBody() *acl.BearerTokenBody {
|
||||
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet && !b.impersonate && !b.apeOverrideSet {
|
||||
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet && !b.impersonate {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -203,10 +116,6 @@ func (b Token) fillBody() *acl.BearerTokenBody {
|
|||
body.SetLifetime(&lifetime)
|
||||
}
|
||||
|
||||
if b.apeOverrideSet {
|
||||
body.SetAPEOverride(b.apeOverride.ToV2())
|
||||
}
|
||||
|
||||
body.SetImpersonate(b.impersonate)
|
||||
|
||||
return &body
|
||||
|
@ -305,25 +214,6 @@ func (b Token) EACLTable() eacl.Table {
|
|||
return eacl.Table{}
|
||||
}
|
||||
|
||||
// SetAPEOverride sets APE override to the bearer token.
|
||||
//
|
||||
// See also: APEOverride.
|
||||
func (b *Token) SetAPEOverride(v APEOverride) {
|
||||
b.apeOverride = v
|
||||
b.apeOverrideSet = true
|
||||
}
|
||||
|
||||
// APEOverride returns APE override set by SetAPEOverride.
|
||||
//
|
||||
// Zero Token has zero APEOverride.
|
||||
func (b *Token) APEOverride() APEOverride {
|
||||
if b.apeOverrideSet {
|
||||
return b.apeOverride
|
||||
}
|
||||
|
||||
return APEOverride{}
|
||||
}
|
||||
|
||||
// SetImpersonate mark token as impersonate to consider token signer as request owner.
|
||||
// If this field is true extended EACLTable in token body isn't processed.
|
||||
func (b *Token) SetImpersonate(v bool) {
|
||||
|
|
|
@ -3,7 +3,6 @@ package bearer_test
|
|||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||
|
@ -82,58 +81,6 @@ func TestToken_SetEACLTable(t *testing.T) {
|
|||
require.True(t, isEqualEACLTables(eaclTable, val.EACLTable()))
|
||||
}
|
||||
|
||||
func TestToken_SetAPEOverrides(t *testing.T) {
|
||||
var val bearer.Token
|
||||
var m acl.BearerToken
|
||||
filled := bearertest.Token()
|
||||
|
||||
val.WriteToV2(&m)
|
||||
require.Zero(t, m.GetBody())
|
||||
|
||||
val2 := filled
|
||||
|
||||
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||
require.Zero(t, val2.APEOverride())
|
||||
|
||||
val2 = filled
|
||||
|
||||
jd, err := val.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||
require.Zero(t, val2.APEOverride())
|
||||
|
||||
// set value
|
||||
|
||||
tApe := bearertest.APEOverride()
|
||||
|
||||
val.SetAPEOverride(tApe)
|
||||
require.Equal(t, tApe, val.APEOverride())
|
||||
|
||||
val.WriteToV2(&m)
|
||||
require.NotNil(t, m.GetBody().GetAPEOverride())
|
||||
require.True(t, tokenAPEOverridesEqual(tApe.ToV2(), m.GetBody().GetAPEOverride()))
|
||||
|
||||
val2 = filled
|
||||
|
||||
require.NoError(t, val2.Unmarshal(val.Marshal()))
|
||||
apeOverride := val2.APEOverride()
|
||||
require.True(t, tokenAPEOverridesEqual(tApe.ToV2(), apeOverride.ToV2()))
|
||||
|
||||
val2 = filled
|
||||
|
||||
jd, err = val.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, val2.UnmarshalJSON(jd))
|
||||
apeOverride = val.APEOverride()
|
||||
require.True(t, tokenAPEOverridesEqual(tApe.ToV2(), apeOverride.ToV2()))
|
||||
}
|
||||
|
||||
func tokenAPEOverridesEqual(lhs, rhs *acl.APEOverride) bool {
|
||||
return reflect.DeepEqual(lhs, rhs)
|
||||
}
|
||||
|
||||
func TestToken_ForUser(t *testing.T) {
|
||||
var val bearer.Token
|
||||
var m acl.BearerToken
|
||||
|
@ -160,7 +107,7 @@ func TestToken_ForUser(t *testing.T) {
|
|||
require.Zero(t, m.GetBody())
|
||||
|
||||
// set value
|
||||
usr := usertest.ID()
|
||||
usr := *usertest.ID()
|
||||
|
||||
var usrV2 refs.OwnerID
|
||||
usr.WriteToV2(&usrV2)
|
||||
|
@ -296,11 +243,11 @@ func TestToken_AssertContainer(t *testing.T) {
|
|||
|
||||
func TestToken_AssertUser(t *testing.T) {
|
||||
var val bearer.Token
|
||||
usr := usertest.ID()
|
||||
usr := *usertest.ID()
|
||||
|
||||
require.True(t, val.AssertUser(usr))
|
||||
|
||||
val.ForUser(usertest.ID())
|
||||
val.ForUser(*usertest.ID())
|
||||
require.False(t, val.AssertUser(usr))
|
||||
|
||||
val.ForUser(usr)
|
||||
|
@ -385,7 +332,7 @@ func TestToken_ReadFromV2(t *testing.T) {
|
|||
val.WriteToV2(&m2)
|
||||
require.Equal(t, m, m2)
|
||||
|
||||
usr, usr2 := usertest.ID(), usertest.ID()
|
||||
usr, usr2 := *usertest.ID(), *usertest.ID()
|
||||
|
||||
require.True(t, val.AssertUser(usr))
|
||||
require.True(t, val.AssertUser(usr2))
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package bearertest
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test"
|
||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
||||
|
@ -14,19 +13,8 @@ func Token() (t bearer.Token) {
|
|||
t.SetExp(3)
|
||||
t.SetNbf(2)
|
||||
t.SetIat(1)
|
||||
t.ForUser(usertest.ID())
|
||||
t.ForUser(*usertest.ID())
|
||||
t.SetEACLTable(*eacltest.Table())
|
||||
t.SetAPEOverride(APEOverride())
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func APEOverride() bearer.APEOverride {
|
||||
return bearer.APEOverride{
|
||||
Target: ape.ChainTarget{
|
||||
TargetType: ape.TargetTypeContainer,
|
||||
Name: "F8JsMnChywiPvbDvpxMbjTjx5KhWHHp6gCDt8BhzL9kF",
|
||||
},
|
||||
Chains: []ape.Chain{{Raw: []byte("{}")}},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,26 +17,26 @@ import (
|
|||
|
||||
// PrmBalanceGet groups parameters of BalanceGet operation.
|
||||
type PrmBalanceGet struct {
|
||||
XHeaders []string
|
||||
prmCommonMeta
|
||||
|
||||
Account user.ID
|
||||
accountSet bool
|
||||
account user.ID
|
||||
}
|
||||
|
||||
// SetAccount sets identifier of the FrostFS account for which the balance is requested.
|
||||
// Required parameter.
|
||||
//
|
||||
// Deprecated: Use PrmBalanceGet.Account instead.
|
||||
func (x *PrmBalanceGet) SetAccount(id user.ID) {
|
||||
x.Account = id
|
||||
x.account = id
|
||||
x.accountSet = true
|
||||
}
|
||||
|
||||
func (x *PrmBalanceGet) buildRequest(c *Client) (*v2accounting.BalanceRequest, error) {
|
||||
if x.Account.IsEmpty() {
|
||||
if !x.accountSet {
|
||||
return nil, errorAccountNotSet
|
||||
}
|
||||
|
||||
var accountV2 refs.OwnerID
|
||||
x.Account.WriteToV2(&accountV2)
|
||||
x.account.WriteToV2(&accountV2)
|
||||
|
||||
var body v2accounting.BalanceRequestBody
|
||||
body.SetOwnerID(&accountV2)
|
||||
|
@ -64,9 +64,9 @@ func (x ResBalanceGet) Amount() accounting.Decimal {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`,
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmBalanceGet docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -79,7 +79,7 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
)
|
||||
|
||||
// PrmAPEManagerAddChain groups parameters of APEManagerAddChain operation.
|
||||
type PrmAPEManagerAddChain struct {
|
||||
XHeaders []string
|
||||
|
||||
ChainTarget apeSDK.ChainTarget
|
||||
|
||||
Chain apeSDK.Chain
|
||||
}
|
||||
|
||||
func (prm *PrmAPEManagerAddChain) buildRequest(c *Client) (*apemanagerV2.AddChainRequest, error) {
|
||||
if len(prm.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
req := new(apemanagerV2.AddChainRequest)
|
||||
reqBody := new(apemanagerV2.AddChainRequestBody)
|
||||
|
||||
reqBody.SetTarget(prm.ChainTarget.ToV2())
|
||||
reqBody.SetChain(prm.Chain.ToV2())
|
||||
|
||||
req.SetBody(reqBody)
|
||||
|
||||
var meta sessionV2.RequestMetaHeader
|
||||
writeXHeadersToMeta(prm.XHeaders, &meta)
|
||||
|
||||
c.prepareRequest(req, &meta)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
type ResAPEManagerAddChain struct {
|
||||
statusRes
|
||||
|
||||
// ChainID of set Chain. If Chain does not contain chainID before request, then
|
||||
// ChainID is generated.
|
||||
ChainID apeSDK.ChainID
|
||||
}
|
||||
|
||||
// APEManagerAddChain sets Chain for ChainTarget.
|
||||
func (c *Client) APEManagerAddChain(ctx context.Context, prm PrmAPEManagerAddChain) (*ResAPEManagerAddChain, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := rpcapi.AddChain(&c.c, req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResAPEManagerAddChain
|
||||
res.st, err = c.processResponse(resp)
|
||||
if err != nil || !apistatus.IsSuccessful(res.st) {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
res.ChainID = resp.GetBody().GetChainID()
|
||||
|
||||
return &res, nil
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
)
|
||||
|
||||
// PrmAPEManagerListChains groups parameters of APEManagerListChains operation.
|
||||
type PrmAPEManagerListChains struct {
|
||||
XHeaders []string
|
||||
|
||||
ChainTarget apeSDK.ChainTarget
|
||||
}
|
||||
|
||||
func (prm *PrmAPEManagerListChains) buildRequest(c *Client) (*apemanagerV2.ListChainsRequest, error) {
|
||||
if len(prm.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
req := new(apemanagerV2.ListChainsRequest)
|
||||
reqBody := new(apemanagerV2.ListChainsRequestBody)
|
||||
|
||||
reqBody.SetTarget(prm.ChainTarget.ToV2())
|
||||
|
||||
req.SetBody(reqBody)
|
||||
|
||||
var meta sessionV2.RequestMetaHeader
|
||||
writeXHeadersToMeta(prm.XHeaders, &meta)
|
||||
|
||||
c.prepareRequest(req, &meta)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
type ResAPEManagerListChains struct {
|
||||
statusRes
|
||||
|
||||
Chains []apeSDK.Chain
|
||||
}
|
||||
|
||||
// APEManagerListChains lists Chains for ChainTarget.
|
||||
func (c *Client) APEManagerListChains(ctx context.Context, prm PrmAPEManagerListChains) (*ResAPEManagerListChains, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := rpcapi.ListChains(&c.c, req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResAPEManagerListChains
|
||||
res.st, err = c.processResponse(resp)
|
||||
if err != nil || !apistatus.IsSuccessful(res.st) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ch := range resp.GetBody().GetChains() {
|
||||
var chSDK apeSDK.Chain
|
||||
if err := chSDK.ReadFromV2(ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Chains = append(res.Chains, chSDK)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
)
|
||||
|
||||
// PrmAPEManagerRemoveChain groups parameters of APEManagerRemoveChain operation.
|
||||
type PrmAPEManagerRemoveChain struct {
|
||||
XHeaders []string
|
||||
|
||||
ChainTarget apeSDK.ChainTarget
|
||||
|
||||
ChainID apeSDK.ChainID
|
||||
}
|
||||
|
||||
func (prm *PrmAPEManagerRemoveChain) buildRequest(c *Client) (*apemanagerV2.RemoveChainRequest, error) {
|
||||
if len(prm.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
req := new(apemanagerV2.RemoveChainRequest)
|
||||
reqBody := new(apemanagerV2.RemoveChainRequestBody)
|
||||
|
||||
reqBody.SetTarget(prm.ChainTarget.ToV2())
|
||||
reqBody.SetChainID(prm.ChainID)
|
||||
|
||||
req.SetBody(reqBody)
|
||||
|
||||
var meta sessionV2.RequestMetaHeader
|
||||
writeXHeadersToMeta(prm.XHeaders, &meta)
|
||||
|
||||
c.prepareRequest(req, &meta)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
type ResAPEManagerRemoveChain struct {
|
||||
statusRes
|
||||
}
|
||||
|
||||
// APEManagerRemoveChain removes Chain with ChainID defined for ChainTarget.
|
||||
func (c *Client) APEManagerRemoveChain(ctx context.Context, prm PrmAPEManagerRemoveChain) (*ResAPEManagerRemoveChain, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := rpcapi.RemoveChain(&c.c, req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResAPEManagerRemoveChain
|
||||
res.st, err = c.processResponse(resp)
|
||||
if err != nil || !apistatus.IsSuccessful(res.st) {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
100
client/client.go
100
client/client.go
|
@ -78,22 +78,31 @@ func (c *Client) Init(prm PrmInit) {
|
|||
//
|
||||
// See also Init / Close.
|
||||
func (c *Client) Dial(ctx context.Context, prm PrmDial) error {
|
||||
if prm.Endpoint == "" {
|
||||
if prm.endpoint == "" {
|
||||
return errorServerAddrUnset
|
||||
}
|
||||
|
||||
if prm.DialTimeout <= 0 {
|
||||
prm.DialTimeout = defaultDialTimeout
|
||||
if prm.timeoutDialSet {
|
||||
if prm.timeoutDial <= 0 {
|
||||
return errorNonPositiveTimeout
|
||||
}
|
||||
} else {
|
||||
prm.timeoutDial = 5 * time.Second
|
||||
}
|
||||
if prm.StreamTimeout <= 0 {
|
||||
prm.StreamTimeout = defaultStreamTimeout
|
||||
|
||||
if prm.streamTimeoutSet {
|
||||
if prm.streamTimeout <= 0 {
|
||||
return errorNonPositiveTimeout
|
||||
}
|
||||
} else {
|
||||
prm.streamTimeout = 10 * time.Second
|
||||
}
|
||||
|
||||
c.c = *client.New(append(
|
||||
client.WithNetworkURIAddress(prm.Endpoint, prm.TLSConfig),
|
||||
client.WithDialTimeout(prm.DialTimeout),
|
||||
client.WithRWTimeout(prm.StreamTimeout),
|
||||
client.WithGRPCDialOptions(prm.GRPCDialOptions),
|
||||
client.WithNetworkURIAddress(prm.endpoint, prm.tlsConfig),
|
||||
client.WithDialTimeout(prm.timeoutDial),
|
||||
client.WithRWTimeout(prm.streamTimeout),
|
||||
client.WithGRPCDialOptions(prm.dialOptions),
|
||||
)...)
|
||||
|
||||
c.setFrostFSAPIServer((*coreServer)(&c.c))
|
||||
|
@ -135,67 +144,52 @@ func (c *Client) Close() error {
|
|||
//
|
||||
// See also Init.
|
||||
type PrmInit struct {
|
||||
DisableFrostFSErrorResolution bool
|
||||
resolveFrostFSErrors bool
|
||||
|
||||
Key ecdsa.PrivateKey
|
||||
key ecdsa.PrivateKey
|
||||
|
||||
ResponseInfoCallback func(ResponseMetaInfo) error
|
||||
cbRespInfo func(ResponseMetaInfo) error
|
||||
|
||||
NetMagic uint64
|
||||
netMagic uint64
|
||||
}
|
||||
|
||||
// SetDefaultPrivateKey sets Client private key to be used for the protocol
|
||||
// communication by default.
|
||||
//
|
||||
// Required for operations without custom key parametrization (see corresponding Prm* docs).
|
||||
//
|
||||
// Deprecated: Use PrmInit.Key instead.
|
||||
func (x *PrmInit) SetDefaultPrivateKey(key ecdsa.PrivateKey) {
|
||||
x.Key = key
|
||||
x.key = key
|
||||
}
|
||||
|
||||
// Deprecated: method is no-op. Option is default.
|
||||
// ResolveFrostFSFailures makes the Client to resolve failure statuses of the
|
||||
// FrostFS protocol into Go built-in errors. These errors are returned from
|
||||
// each protocol operation. By default, statuses aren't resolved and written
|
||||
// to the resulting structure (see corresponding Res* docs).
|
||||
func (x *PrmInit) ResolveFrostFSFailures() {
|
||||
}
|
||||
|
||||
// DisableFrostFSFailuresResolution makes the Client to preserve failure statuses of the
|
||||
// FrostFS protocol only in resulting structure (see corresponding Res* docs).
|
||||
// These errors are returned from each protocol operation. By default, statuses
|
||||
// are resolved and returned as a Go built-in errors.
|
||||
//
|
||||
// Deprecated: Use PrmInit.DisableFrostFSErrorResolution instead.
|
||||
func (x *PrmInit) DisableFrostFSFailuresResolution() {
|
||||
x.DisableFrostFSErrorResolution = true
|
||||
x.resolveFrostFSErrors = true
|
||||
}
|
||||
|
||||
// SetResponseInfoCallback makes the Client to pass ResponseMetaInfo from each
|
||||
// FrostFS server response to f. Nil (default) means ignore response meta info.
|
||||
//
|
||||
// Deprecated: Use PrmInit.ResponseInfoCallback instead.
|
||||
func (x *PrmInit) SetResponseInfoCallback(f func(ResponseMetaInfo) error) {
|
||||
x.ResponseInfoCallback = f
|
||||
x.cbRespInfo = f
|
||||
}
|
||||
|
||||
const (
|
||||
defaultDialTimeout = 5 * time.Second
|
||||
defaultStreamTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
// PrmDial groups connection parameters for the Client.
|
||||
//
|
||||
// See also Dial.
|
||||
type PrmDial struct {
|
||||
Endpoint string
|
||||
endpoint string
|
||||
|
||||
TLSConfig *tls.Config
|
||||
tlsConfig *tls.Config
|
||||
|
||||
// If DialTimeout is non-positive, then it's set to defaultDialTimeout.
|
||||
DialTimeout time.Duration
|
||||
timeoutDialSet bool
|
||||
timeoutDial time.Duration
|
||||
|
||||
// If StreamTimeout is non-positive, then it's set to defaultStreamTimeout.
|
||||
StreamTimeout time.Duration
|
||||
streamTimeoutSet bool
|
||||
streamTimeout time.Duration
|
||||
|
||||
GRPCDialOptions []grpc.DialOption
|
||||
dialOptions []grpc.DialOption
|
||||
}
|
||||
|
||||
// SetServerURI sets server URI in the FrostFS network.
|
||||
|
@ -211,41 +205,33 @@ type PrmDial struct {
|
|||
// grpcs
|
||||
//
|
||||
// See also SetTLSConfig.
|
||||
//
|
||||
// Deprecated: Use PrmDial.Endpoint instead.
|
||||
func (x *PrmDial) SetServerURI(endpoint string) {
|
||||
x.Endpoint = endpoint
|
||||
x.endpoint = endpoint
|
||||
}
|
||||
|
||||
// SetTLSConfig sets tls.Config to open TLS client connection
|
||||
// to the FrostFS server. Nil (default) means insecure connection.
|
||||
//
|
||||
// See also SetServerURI.
|
||||
//
|
||||
// Depreacted: Use PrmDial.TLSConfig instead.
|
||||
func (x *PrmDial) SetTLSConfig(tlsConfig *tls.Config) {
|
||||
x.TLSConfig = tlsConfig
|
||||
x.tlsConfig = tlsConfig
|
||||
}
|
||||
|
||||
// SetTimeout sets the timeout for connection to be established.
|
||||
// MUST BE positive. If not called, 5s timeout will be used by default.
|
||||
//
|
||||
// Deprecated: Use PrmDial.DialTimeout instead.
|
||||
func (x *PrmDial) SetTimeout(timeout time.Duration) {
|
||||
x.DialTimeout = timeout
|
||||
x.timeoutDialSet = true
|
||||
x.timeoutDial = timeout
|
||||
}
|
||||
|
||||
// SetStreamTimeout sets the timeout for individual operations in streaming RPC.
|
||||
// MUST BE positive. If not called, 10s timeout will be used by default.
|
||||
//
|
||||
// Deprecated: Use PrmDial.StreamTimeout instead.
|
||||
func (x *PrmDial) SetStreamTimeout(timeout time.Duration) {
|
||||
x.StreamTimeout = timeout
|
||||
x.streamTimeoutSet = true
|
||||
x.streamTimeout = timeout
|
||||
}
|
||||
|
||||
// SetGRPCDialOptions sets the gRPC dial options for new gRPC client connection.
|
||||
//
|
||||
// Deprecated: Use PrmDial.GRPCDialOptions instead.
|
||||
func (x *PrmDial) SetGRPCDialOptions(opts ...grpc.DialOption) {
|
||||
x.GRPCDialOptions = opts
|
||||
x.dialOptions = opts
|
||||
}
|
||||
|
|
|
@ -29,9 +29,8 @@ func assertStatusErr(tb testing.TB, res interface{ Status() apistatus.Status })
|
|||
}
|
||||
|
||||
func newClient(server frostFSAPIServer) *Client {
|
||||
prm := PrmInit{
|
||||
Key: *key,
|
||||
}
|
||||
var prm PrmInit
|
||||
prm.SetDefaultPrivateKey(*key)
|
||||
|
||||
var c Client
|
||||
c.Init(prm)
|
||||
|
@ -44,9 +43,8 @@ func TestClient_DialContext(t *testing.T) {
|
|||
var c Client
|
||||
|
||||
// try to connect to any host
|
||||
prm := PrmDial{
|
||||
Endpoint: "localhost:8080",
|
||||
}
|
||||
var prm PrmDial
|
||||
prm.SetServerURI("localhost:8080")
|
||||
|
||||
assert := func(ctx context.Context, errExpected error) {
|
||||
// expect particular context error according to Dial docs
|
||||
|
|
|
@ -24,6 +24,24 @@ func (x statusRes) Status() apistatus.Status {
|
|||
return x.st
|
||||
}
|
||||
|
||||
// groups meta parameters shared between all Client operations.
|
||||
type prmCommonMeta struct {
|
||||
// FrostFS request X-Headers
|
||||
xHeaders []string
|
||||
}
|
||||
|
||||
// WithXHeaders specifies list of extended headers (string key-value pairs)
|
||||
// to be attached to the request. Must have an even length.
|
||||
//
|
||||
// Slice must not be mutated until the operation completes.
|
||||
func (x *prmCommonMeta) WithXHeaders(hs ...string) {
|
||||
if len(hs)%2 != 0 {
|
||||
panic("slice of X-Headers with odd length")
|
||||
}
|
||||
|
||||
x.xHeaders = hs
|
||||
}
|
||||
|
||||
func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
|
||||
if len(xHeaders) == 0 {
|
||||
return
|
||||
|
@ -46,13 +64,16 @@ func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
|
|||
|
||||
// error messages.
|
||||
var (
|
||||
errorMissingContainer = errors.New("missing container")
|
||||
errorMissingObject = errors.New("missing object")
|
||||
errorAccountNotSet = errors.New("account not set")
|
||||
errorServerAddrUnset = errors.New("server address is unset or empty")
|
||||
errorZeroRangeLength = errors.New("zero range length")
|
||||
errorMissingRanges = errors.New("missing ranges")
|
||||
errorInvalidXHeaders = errors.New("xheaders must be presented only as key-value pairs")
|
||||
errorMissingContainer = errors.New("missing container")
|
||||
errorMissingObject = errors.New("missing object")
|
||||
errorAccountNotSet = errors.New("account not set")
|
||||
errorServerAddrUnset = errors.New("server address is unset or empty")
|
||||
errorNonPositiveTimeout = errors.New("non-positive timeout")
|
||||
errorEACLTableNotSet = errors.New("eACL table not set")
|
||||
errorMissingAnnouncements = errors.New("missing announcements")
|
||||
errorZeroRangeLength = errors.New("zero range length")
|
||||
errorMissingRanges = errors.New("missing ranges")
|
||||
errorInvalidXHeaders = errors.New("xheaders must be presented only as key-value pairs")
|
||||
)
|
||||
|
||||
type request interface {
|
||||
|
@ -75,19 +96,19 @@ func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader)
|
|||
|
||||
meta.SetTTL(ttl)
|
||||
meta.SetVersion(verV2)
|
||||
meta.SetNetworkMagic(c.prm.NetMagic)
|
||||
meta.SetNetworkMagic(c.prm.netMagic)
|
||||
|
||||
req.SetMetaHeader(meta)
|
||||
}
|
||||
|
||||
// processResponse verifies response signature and converts status to an error if needed.
|
||||
func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
|
||||
if c.prm.ResponseInfoCallback != nil {
|
||||
if c.prm.cbRespInfo != nil {
|
||||
rmi := ResponseMetaInfo{
|
||||
key: resp.GetVerificationHeader().GetBodySignature().GetKey(),
|
||||
epoch: resp.GetMetaHeader().GetEpoch(),
|
||||
}
|
||||
if err := c.prm.ResponseInfoCallback(rmi); err != nil {
|
||||
if err := c.prm.cbRespInfo(rmi); err != nil {
|
||||
return nil, fmt.Errorf("response callback error: %w", err)
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +119,7 @@ func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
|
|||
}
|
||||
|
||||
st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
|
||||
if !c.prm.DisableFrostFSErrorResolution {
|
||||
if c.prm.resolveFrostFSErrors {
|
||||
return st, apistatus.ErrFromStatus(st)
|
||||
}
|
||||
return st, nil
|
||||
|
|
|
@ -52,7 +52,7 @@ func (prm *PrmContainerDelete) buildRequest(c *Client) (*v2container.DeleteReque
|
|||
|
||||
var sig frostfscrypto.Signature
|
||||
|
||||
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.Key), data)
|
||||
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calculate signature: %w", err)
|
||||
}
|
||||
|
@ -101,9 +101,9 @@ type ResContainerDelete struct {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Operation is asynchronous and no guaranteed even in the absence of errors.
|
||||
// The required time is also not predictable.
|
||||
|
@ -124,7 +124,7 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (*
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
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/session"
|
||||
)
|
||||
|
||||
// PrmContainerEACL groups parameters of ContainerEACL operation.
|
||||
|
@ -22,8 +21,6 @@ type PrmContainerEACL struct {
|
|||
XHeaders []string
|
||||
|
||||
ContainerID *cid.ID
|
||||
|
||||
Session *session.Container
|
||||
}
|
||||
|
||||
// SetContainer sets identifier of the FrostFS container to read the eACL table.
|
||||
|
@ -49,19 +46,9 @@ func (x *PrmContainerEACL) buildRequest(c *Client) (*v2container.GetExtendedACLR
|
|||
reqBody := new(v2container.GetExtendedACLRequestBody)
|
||||
reqBody.SetContainerID(&cidV2)
|
||||
|
||||
var meta v2session.RequestMetaHeader
|
||||
writeXHeadersToMeta(x.XHeaders, &meta)
|
||||
|
||||
if x.Session != nil {
|
||||
var tokv2 v2session.Token
|
||||
x.Session.WriteToV2(&tokv2)
|
||||
|
||||
meta.SetSessionToken(&tokv2)
|
||||
}
|
||||
|
||||
var req v2container.GetExtendedACLRequest
|
||||
req.SetBody(reqBody)
|
||||
c.prepareRequest(&req, &meta)
|
||||
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
|
@ -81,9 +68,9 @@ func (x ResContainerEACL) Table() eacl.Table {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmContainerEACL docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -98,7 +85,7 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
)
|
||||
|
||||
// PrmContainerGet groups parameters of ContainerGet operation.
|
||||
|
@ -23,8 +22,6 @@ type PrmContainerGet struct {
|
|||
XHeaders []string
|
||||
|
||||
ContainerID *cid.ID
|
||||
|
||||
Session *session.Container
|
||||
}
|
||||
|
||||
// SetContainer sets identifier of the container to be read.
|
||||
|
@ -50,19 +47,9 @@ func (prm *PrmContainerGet) buildRequest(c *Client) (*v2container.GetRequest, er
|
|||
reqBody := new(v2container.GetRequestBody)
|
||||
reqBody.SetContainerID(&cidV2)
|
||||
|
||||
var meta v2session.RequestMetaHeader
|
||||
writeXHeadersToMeta(prm.XHeaders, &meta)
|
||||
|
||||
if prm.Session != nil {
|
||||
var tokv2 v2session.Token
|
||||
prm.Session.WriteToV2(&tokv2)
|
||||
|
||||
meta.SetSessionToken(&tokv2)
|
||||
}
|
||||
|
||||
var req v2container.GetRequest
|
||||
req.SetBody(reqBody)
|
||||
c.prepareRequest(&req, &meta)
|
||||
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
|
@ -84,9 +71,9 @@ func (x ResContainerGet) Container() container.Container {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmContainerGet docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -100,7 +87,7 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,51 +12,38 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
)
|
||||
|
||||
// PrmContainerList groups parameters of ContainerList operation.
|
||||
type PrmContainerList struct {
|
||||
XHeaders []string
|
||||
prmCommonMeta
|
||||
|
||||
Account user.ID
|
||||
|
||||
Session *session.Container
|
||||
ownerSet bool
|
||||
ownerID user.ID
|
||||
}
|
||||
|
||||
// SetAccount sets identifier of the FrostFS account to list the containers.
|
||||
// Required parameter.
|
||||
//
|
||||
// Deprecated: Use PrmContainerList.Account instead.
|
||||
func (x *PrmContainerList) SetAccount(id user.ID) {
|
||||
x.Account = id
|
||||
x.ownerID = id
|
||||
x.ownerSet = true
|
||||
}
|
||||
|
||||
func (x *PrmContainerList) buildRequest(c *Client) (*v2container.ListRequest, error) {
|
||||
if x.Account.IsEmpty() {
|
||||
if !x.ownerSet {
|
||||
return nil, errorAccountNotSet
|
||||
}
|
||||
|
||||
var ownerV2 refs.OwnerID
|
||||
x.Account.WriteToV2(&ownerV2)
|
||||
x.ownerID.WriteToV2(&ownerV2)
|
||||
|
||||
reqBody := new(v2container.ListRequestBody)
|
||||
reqBody.SetOwnerID(&ownerV2)
|
||||
|
||||
var meta v2session.RequestMetaHeader
|
||||
writeXHeadersToMeta(x.XHeaders, &meta)
|
||||
|
||||
if x.Session != nil {
|
||||
var tokv2 v2session.Token
|
||||
x.Session.WriteToV2(&tokv2)
|
||||
|
||||
meta.SetSessionToken(&tokv2)
|
||||
}
|
||||
|
||||
var req v2container.ListRequest
|
||||
req.SetBody(reqBody)
|
||||
c.prepareRequest(&req, &meta)
|
||||
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
|
@ -78,9 +65,9 @@ func (x ResContainerList) Containers() []cid.ID {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmContainerList docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -93,7 +80,7 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ func (x *PrmContainerPut) buildRequest(c *Client) (*v2container.PutRequest, erro
|
|||
|
||||
var sig frostfscrypto.Signature
|
||||
|
||||
err := container.CalculateSignature(&sig, *x.Container, c.prm.Key)
|
||||
err := container.CalculateSignature(&sig, *x.Container, c.prm.key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calculate container signature: %w", err)
|
||||
}
|
||||
|
@ -110,9 +110,9 @@ func (x ResContainerPut) ID() cid.ID {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Operation is asynchronous and no guaranteed even in the absence of errors.
|
||||
// The required time is also not predictable.
|
||||
|
@ -132,7 +132,7 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
136
client/container_set_eacl.go
Normal file
136
client/container_set_eacl.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
)
|
||||
|
||||
// PrmContainerSetEACL groups parameters of ContainerSetEACL operation.
|
||||
type PrmContainerSetEACL struct {
|
||||
// FrostFS request X-Headers.
|
||||
XHeaders []string
|
||||
|
||||
Table *eacl.Table
|
||||
|
||||
Session *session.Container
|
||||
}
|
||||
|
||||
// SetTable sets eACL table structure to be set for the container.
|
||||
// Required parameter.
|
||||
//
|
||||
// Deprecated: Use PrmContainerSetEACL.Table instead.
|
||||
func (x *PrmContainerSetEACL) SetTable(table eacl.Table) {
|
||||
x.Table = &table
|
||||
}
|
||||
|
||||
// WithinSession specifies session within which extended ACL of the container
|
||||
// should be saved.
|
||||
//
|
||||
// Creator of the session acquires the authorship of the request. This affects
|
||||
// the execution of an operation (e.g. access control).
|
||||
//
|
||||
// Session is optional, if set the following requirements apply:
|
||||
// - if particular container is specified (ApplyOnlyTo), it MUST equal the container
|
||||
// for which extended ACL is going to be set
|
||||
// - session operation MUST be session.VerbContainerSetEACL (ForVerb)
|
||||
// - token MUST be signed using private key of the owner of the container to be saved
|
||||
//
|
||||
// Deprecated: Use PrmContainerSetEACL.Session instead.
|
||||
func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
|
||||
x.Session = &s
|
||||
}
|
||||
|
||||
func (x *PrmContainerSetEACL) buildRequest(c *Client) (*v2container.SetExtendedACLRequest, error) {
|
||||
if x.Table == nil {
|
||||
return nil, errorEACLTableNotSet
|
||||
}
|
||||
|
||||
if len(x.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
eaclV2 := x.Table.ToV2()
|
||||
|
||||
var sig frostfscrypto.Signature
|
||||
|
||||
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), eaclV2.StableMarshal(nil))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calculate signature: %w", err)
|
||||
}
|
||||
|
||||
var sigv2 refs.Signature
|
||||
sig.WriteToV2(&sigv2)
|
||||
|
||||
reqBody := new(v2container.SetExtendedACLRequestBody)
|
||||
reqBody.SetEACL(eaclV2)
|
||||
reqBody.SetSignature(&sigv2)
|
||||
|
||||
var meta v2session.RequestMetaHeader
|
||||
writeXHeadersToMeta(x.XHeaders, &meta)
|
||||
|
||||
if x.Session != nil {
|
||||
var tokv2 v2session.Token
|
||||
x.Session.WriteToV2(&tokv2)
|
||||
|
||||
meta.SetSessionToken(&tokv2)
|
||||
}
|
||||
|
||||
var req v2container.SetExtendedACLRequest
|
||||
req.SetBody(reqBody)
|
||||
c.prepareRequest(&req, &meta)
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
// ResContainerSetEACL groups resulting values of ContainerSetEACL operation.
|
||||
type ResContainerSetEACL struct {
|
||||
statusRes
|
||||
}
|
||||
|
||||
// ContainerSetEACL sends request to update eACL table of the FrostFS container.
|
||||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Operation is asynchronous and no guaranteed even in the absence of errors.
|
||||
// The required time is also not predictable.
|
||||
//
|
||||
// Success can be verified by reading by identifier (see EACL).
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmContainerSetEACL docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
//
|
||||
// Return statuses:
|
||||
// - global (see Client docs).
|
||||
func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) (*ResContainerSetEACL, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := rpcapi.SetEACL(&c.c, req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResContainerSetEACL
|
||||
res.st, err = c.processResponse(resp)
|
||||
return &res, err
|
||||
}
|
92
client/container_space.go
Normal file
92
client/container_space.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
)
|
||||
|
||||
// PrmAnnounceSpace groups parameters of ContainerAnnounceUsedSpace operation.
|
||||
type PrmAnnounceSpace struct {
|
||||
XHeaders []string
|
||||
|
||||
Announcements []container.SizeEstimation
|
||||
}
|
||||
|
||||
// SetValues sets values describing volume of space that is used for the container objects.
|
||||
// Required parameter. Must not be empty.
|
||||
//
|
||||
// Must not be mutated before the end of the operation.
|
||||
//
|
||||
// Deprecated: Use PrmAnnounceSpace.Announcements instead.
|
||||
func (x *PrmAnnounceSpace) SetValues(vs []container.SizeEstimation) {
|
||||
x.Announcements = vs
|
||||
}
|
||||
|
||||
func (x *PrmAnnounceSpace) buildRequest(c *Client) (*v2container.AnnounceUsedSpaceRequest, error) {
|
||||
if len(x.Announcements) == 0 {
|
||||
return nil, errorMissingAnnouncements
|
||||
}
|
||||
|
||||
v2announce := make([]v2container.UsedSpaceAnnouncement, len(x.Announcements))
|
||||
for i := range x.Announcements {
|
||||
x.Announcements[i].WriteToV2(&v2announce[i])
|
||||
}
|
||||
|
||||
reqBody := new(v2container.AnnounceUsedSpaceRequestBody)
|
||||
reqBody.SetAnnouncements(v2announce)
|
||||
|
||||
var req v2container.AnnounceUsedSpaceRequest
|
||||
req.SetBody(reqBody)
|
||||
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
// ResAnnounceSpace groups resulting values of ContainerAnnounceUsedSpace operation.
|
||||
type ResAnnounceSpace struct {
|
||||
statusRes
|
||||
}
|
||||
|
||||
// ContainerAnnounceUsedSpace sends request to announce volume of the space used for the container objects.
|
||||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Operation is asynchronous and no guaranteed even in the absence of errors.
|
||||
// The required time is also not predictable.
|
||||
//
|
||||
// At this moment success can not be checked.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmAnnounceSpace docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
//
|
||||
// Return statuses:
|
||||
// - global (see Client docs).
|
||||
func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounceSpace) (*ResAnnounceSpace, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := rpcapi.AnnounceUsedSpace(&c.c, req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res ResAnnounceSpace
|
||||
res.st, err = c.processResponse(resp)
|
||||
return &res, err
|
||||
}
|
|
@ -61,18 +61,6 @@ func IsErrSessionNotFound(err error) bool {
|
|||
return wrapsErrType[*apistatus.SessionTokenNotFound](err)
|
||||
}
|
||||
|
||||
// IsErrAPEManagerAccessDenied checks if err corresponds to FrostFS status return
|
||||
// corresponding to apemanager access deny. Supports wrapped errors.
|
||||
func IsErrAPEManagerAccessDenied(err error) bool {
|
||||
return wrapsErrType[*apistatus.APEManagerAccessDenied](err)
|
||||
}
|
||||
|
||||
// IsErrNodeUnderMaintenance checks if err corresponds to FrostFS status return
|
||||
// corresponding to nodes being under maintenance. Supports wrapped errors.
|
||||
func IsErrNodeUnderMaintenance(err error) bool {
|
||||
return wrapsErrType[*apistatus.NodeUnderMaintenance](err)
|
||||
}
|
||||
|
||||
// returns error describing missing field with the given name.
|
||||
func newErrMissingResponseField(name string) error {
|
||||
return fmt.Errorf("missing %s field in the response", name)
|
||||
|
|
|
@ -33,15 +33,10 @@ func TestErrors(t *testing.T) {
|
|||
{
|
||||
check: client.IsErrSessionExpired,
|
||||
err: new(apistatus.SessionTokenExpired),
|
||||
},
|
||||
{
|
||||
}, {
|
||||
check: client.IsErrSessionNotFound,
|
||||
err: new(apistatus.SessionTokenNotFound),
|
||||
},
|
||||
{
|
||||
check: client.IsErrNodeUnderMaintenance,
|
||||
err: new(apistatus.NodeUnderMaintenance),
|
||||
},
|
||||
}
|
||||
|
||||
for i := range errs {
|
||||
|
|
|
@ -53,9 +53,9 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo {
|
|||
// Method can be used as a health check to see if node is alive and responds to requests.
|
||||
//
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmEndpointInfo docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -71,7 +71,7 @@ func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEnd
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
@ -140,9 +140,9 @@ func (x ResNetworkInfo) Info() netmap.NetworkInfo {
|
|||
// NetworkInfo requests information about the FrostFS network of which the remote server is a part.
|
||||
//
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmNetworkInfo docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -158,7 +158,7 @@ func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetwo
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,8 @@ func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetwo
|
|||
}
|
||||
|
||||
// PrmNetMapSnapshot groups parameters of NetMapSnapshot operation.
|
||||
type PrmNetMapSnapshot struct{}
|
||||
type PrmNetMapSnapshot struct {
|
||||
}
|
||||
|
||||
// ResNetMapSnapshot groups resulting values of NetMapSnapshot operation.
|
||||
type ResNetMapSnapshot struct {
|
||||
|
@ -203,9 +204,9 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap {
|
|||
// NetMapSnapshot requests current network view of the remote server.
|
||||
//
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly.
|
||||
// Context is required and MUST NOT be nil. It is used for network communication.
|
||||
|
@ -227,7 +228,7 @@ func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResN
|
|||
req.SetBody(&body)
|
||||
c.prepareRequest(&req, &meta)
|
||||
|
||||
err := signature.SignServiceMessage(&c.prm.Key, &req)
|
||||
err := signature.SignServiceMessage(&c.prm.key, &req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@ func TestClient_NetMapSnapshot(t *testing.T) {
|
|||
var res *ResNetMapSnapshot
|
||||
var srv serverNetMap
|
||||
c := newClient(&srv)
|
||||
c.prm.DisableFrostFSFailuresResolution()
|
||||
ctx := context.Background()
|
||||
|
||||
// request signature
|
||||
|
|
|
@ -112,9 +112,9 @@ func (prm *PrmObjectDelete) buildRequest(c *Client) (*v2object.DeleteRequest, er
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`,
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmObjectDelete docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -131,7 +131,7 @@ func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObj
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key := c.prm.Key
|
||||
key := c.prm.key
|
||||
if prm.Key != nil {
|
||||
key = *prm.Key
|
||||
}
|
||||
|
|
|
@ -150,9 +150,6 @@ func (x *ObjectReader) ReadHeader(dst *object.Object) bool {
|
|||
case *v2object.SplitInfo:
|
||||
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
|
||||
return false
|
||||
case *v2object.ECInfo:
|
||||
x.err = object.NewECInfoError(object.NewECInfoFromV2(v))
|
||||
return false
|
||||
case *v2object.GetObjectPartInit:
|
||||
partInit = v
|
||||
}
|
||||
|
@ -261,7 +258,6 @@ func (x *ObjectReader) close(ignoreEOF bool) (*ResObjectGet, error) {
|
|||
// Return errors:
|
||||
//
|
||||
// *object.SplitInfoError (returned on virtual objects with PrmObjectGet.MakeRaw).
|
||||
// *object.ECInfoError (returned on erasure-coded objects with PrmObjectGet.MakeRaw).
|
||||
//
|
||||
// Return statuses:
|
||||
// - global (see Client docs);
|
||||
|
@ -311,7 +307,7 @@ func (c *Client) ObjectGetInit(ctx context.Context, prm PrmObjectGet) (*ObjectRe
|
|||
|
||||
key := prm.Key
|
||||
if key == nil {
|
||||
key = &c.prm.Key
|
||||
key = &c.prm.key
|
||||
}
|
||||
|
||||
err = signature.SignServiceMessage(key, req)
|
||||
|
@ -448,9 +444,9 @@ func (prm *PrmObjectHead) buildRequest(c *Client) (*v2object.HeadRequest, error)
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`,
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmObjectHead docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -458,7 +454,6 @@ func (prm *PrmObjectHead) buildRequest(c *Client) (*v2object.HeadRequest, error)
|
|||
// Return errors:
|
||||
//
|
||||
// *object.SplitInfoError (returned on virtual objects with PrmObjectHead.MakeRaw).
|
||||
// *object.ECInfoError (returned on erasure-coded objects with PrmObjectHead.MakeRaw).
|
||||
//
|
||||
// Return statuses:
|
||||
// - global (see Client docs);
|
||||
|
@ -473,7 +468,7 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key := c.prm.Key
|
||||
key := c.prm.key
|
||||
if prm.Key != nil {
|
||||
key = *prm.Key
|
||||
}
|
||||
|
@ -507,8 +502,6 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH
|
|||
return nil, fmt.Errorf("unexpected header type %T", v)
|
||||
case *v2object.SplitInfo:
|
||||
return nil, object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
|
||||
case *v2object.ECInfo:
|
||||
return nil, object.NewECInfoError(object.NewECInfoFromV2(v))
|
||||
case *v2object.HeaderWithSignature:
|
||||
res.hdr = v
|
||||
}
|
||||
|
@ -672,9 +665,6 @@ func (x *ObjectRangeReader) readChunk(buf []byte) (int, bool) {
|
|||
case *v2object.SplitInfo:
|
||||
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
|
||||
return read, false
|
||||
case *v2object.ECInfo:
|
||||
x.err = object.NewECInfoError(object.NewECInfoFromV2(v))
|
||||
return read, false
|
||||
case *v2object.GetRangePartChunk:
|
||||
partChunk = v
|
||||
}
|
||||
|
@ -735,7 +725,6 @@ func (x *ObjectRangeReader) close(ignoreEOF bool) (*ResObjectRange, error) {
|
|||
// Return errors:
|
||||
//
|
||||
// *object.SplitInfoError (returned on virtual objects with PrmObjectRange.MakeRaw).
|
||||
// *object.ECInfoError (returned on erasure-coded objects with PrmObjectRange.MakeRaw).
|
||||
//
|
||||
// Return statuses:
|
||||
// - global (see Client docs);
|
||||
|
@ -787,7 +776,7 @@ func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*Obje
|
|||
|
||||
key := prm.Key
|
||||
if key == nil {
|
||||
key = &c.prm.Key
|
||||
key = &c.prm.key
|
||||
}
|
||||
|
||||
err = signature.SignServiceMessage(key, req)
|
||||
|
|
|
@ -152,9 +152,9 @@ func (prm *PrmObjectHash) buildRequest(c *Client) (*v2object.GetRangeHashRequest
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`,
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmObjectHash docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -172,7 +172,7 @@ func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectH
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key := c.prm.Key
|
||||
key := c.prm.key
|
||||
if prm.Key != nil {
|
||||
key = *prm.Key
|
||||
}
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
|
||||
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
)
|
||||
|
||||
type ResObjectPatch struct {
|
||||
statusRes
|
||||
|
||||
obj oid.ID
|
||||
}
|
||||
|
||||
func (r ResObjectPatch) ObjectID() oid.ID {
|
||||
return r.obj
|
||||
}
|
||||
|
||||
// PrmObjectPatch groups parameters of ObjectPatch operation.
|
||||
type PrmObjectPatch struct {
|
||||
XHeaders []string
|
||||
|
||||
BearerToken *bearer.Token
|
||||
|
||||
Session *session.Object
|
||||
|
||||
Local bool
|
||||
|
||||
Address oid.Address
|
||||
|
||||
Key *ecdsa.PrivateKey
|
||||
|
||||
Offset uint64
|
||||
|
||||
Length uint64
|
||||
|
||||
Chunk []byte
|
||||
}
|
||||
|
||||
func (c *Client) ObjectPatchInit(ctx context.Context, prm PrmObjectPatch) (*objectPatcher, error) {
|
||||
if len(prm.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
var p objectPatcher
|
||||
stream, err := rpcapi.Patch(&c.c, &p.respV2, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open stream: %w", err)
|
||||
}
|
||||
|
||||
p.key = &c.prm.Key
|
||||
if prm.Key != nil {
|
||||
p.key = prm.Key
|
||||
}
|
||||
p.client = c
|
||||
p.stream = stream
|
||||
p.addr = prm.Address
|
||||
|
||||
p.req.SetBody(&v2object.PatchRequestBody{})
|
||||
|
||||
meta := new(v2session.RequestMetaHeader)
|
||||
writeXHeadersToMeta(prm.XHeaders, meta)
|
||||
|
||||
if prm.BearerToken != nil {
|
||||
v2BearerToken := new(acl.BearerToken)
|
||||
prm.BearerToken.WriteToV2(v2BearerToken)
|
||||
meta.SetBearerToken(v2BearerToken)
|
||||
}
|
||||
|
||||
if prm.Session != nil {
|
||||
v2SessionToken := new(v2session.Token)
|
||||
prm.Session.WriteToV2(v2SessionToken)
|
||||
meta.SetSessionToken(v2SessionToken)
|
||||
}
|
||||
|
||||
if prm.Local {
|
||||
meta.SetTTL(1)
|
||||
}
|
||||
|
||||
c.prepareRequest(&p.req, meta)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
type objectPatcher struct {
|
||||
client *Client
|
||||
|
||||
stream interface {
|
||||
Write(*v2object.PatchRequest) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
key *ecdsa.PrivateKey
|
||||
res ResObjectPatch
|
||||
err error
|
||||
|
||||
addr oid.Address
|
||||
|
||||
req v2object.PatchRequest
|
||||
respV2 v2object.PatchResponse
|
||||
}
|
||||
|
||||
func (x *objectPatcher) Patch(_ context.Context, patch *object.Patch) bool {
|
||||
x.req.SetBody(patch.ToV2())
|
||||
x.req.SetVerificationHeader(nil)
|
||||
|
||||
x.err = signature.SignServiceMessage(x.key, &x.req)
|
||||
if x.err != nil {
|
||||
x.err = fmt.Errorf("sign message: %w", x.err)
|
||||
return false
|
||||
}
|
||||
|
||||
x.err = x.stream.Write(&x.req)
|
||||
|
||||
return x.err == nil
|
||||
}
|
||||
|
||||
func (x *objectPatcher) Close(_ context.Context) (*ResObjectPatch, error) {
|
||||
// Ignore io.EOF error, because it is expected error for client-side
|
||||
// stream termination by the server. E.g. when stream contains invalid
|
||||
// message. Server returns an error in response message (in status).
|
||||
if x.err != nil && !errors.Is(x.err, io.EOF) {
|
||||
return nil, x.err
|
||||
}
|
||||
|
||||
if x.err = x.stream.Close(); x.err != nil {
|
||||
return nil, x.err
|
||||
}
|
||||
|
||||
x.res.st, x.err = x.client.processResponse(&x.respV2)
|
||||
if x.err != nil {
|
||||
return nil, x.err
|
||||
}
|
||||
|
||||
if !apistatus.IsSuccessful(x.res.st) {
|
||||
return &x.res, nil
|
||||
}
|
||||
|
||||
const fieldID = "ID"
|
||||
|
||||
idV2 := x.respV2.Body.ObjectID
|
||||
if idV2 == nil {
|
||||
return nil, newErrMissingResponseField(fieldID)
|
||||
}
|
||||
|
||||
x.err = x.res.obj.ReadFromV2(*idV2)
|
||||
if x.err != nil {
|
||||
x.err = newErrInvalidResponseField(fieldID, x.err)
|
||||
}
|
||||
|
||||
return &x.res, nil
|
||||
}
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"crypto/ecdsa"
|
||||
|
||||
buffPool "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/pool"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
|
@ -37,8 +36,6 @@ type PrmObjectPutInit struct {
|
|||
WithoutHomomorphHash bool
|
||||
|
||||
Key *ecdsa.PrivateKey
|
||||
|
||||
Pool *buffPool.BufferPool
|
||||
}
|
||||
|
||||
// SetCopiesNumber sets number of object copies that is enough to consider put successful.
|
||||
|
@ -72,8 +69,7 @@ func (x *PrmObjectPutInit) SetGRPCPayloadChunkLen(v int) {
|
|||
type ResObjectPut struct {
|
||||
statusRes
|
||||
|
||||
obj oid.ID
|
||||
epoch uint64
|
||||
obj oid.ID
|
||||
}
|
||||
|
||||
// StoredObjectID returns identifier of the saved object.
|
||||
|
@ -81,11 +77,6 @@ func (x ResObjectPut) StoredObjectID() oid.ID {
|
|||
return x.obj
|
||||
}
|
||||
|
||||
// StoredEpoch returns creation epoch of the saved object.
|
||||
func (x ResObjectPut) StoredEpoch() uint64 {
|
||||
return x.epoch
|
||||
}
|
||||
|
||||
// ObjectWriter is designed to write one object or
|
||||
// multiple parts of one object to FrostFS system.
|
||||
//
|
||||
|
|
|
@ -28,7 +28,7 @@ func (c *Client) objectPutInitRaw(ctx context.Context, prm PrmObjectPutInit) (*o
|
|||
return nil, fmt.Errorf("open stream: %w", err)
|
||||
}
|
||||
|
||||
w.key = &c.prm.Key
|
||||
w.key = &c.prm.key
|
||||
if prm.Key != nil {
|
||||
w.key = prm.Key
|
||||
}
|
||||
|
@ -175,7 +175,6 @@ func (x *objectWriterRaw) Close(_ context.Context) (*ResObjectPut, error) {
|
|||
if x.err != nil {
|
||||
x.err = newErrInvalidResponseField(fieldID, x.err)
|
||||
}
|
||||
x.res.epoch = x.respV2.GetMetaHeader().GetEpoch()
|
||||
|
||||
return &x.res, nil
|
||||
}
|
||||
|
|
|
@ -93,13 +93,6 @@ func (prm *PrmObjectPutSingle) SetObject(o *v2object.Object) {
|
|||
// ResObjectPutSingle groups resulting values of PutSingle operation.
|
||||
type ResObjectPutSingle struct {
|
||||
statusRes
|
||||
|
||||
epoch uint64
|
||||
}
|
||||
|
||||
// Epoch returns creation epoch of the saved object.
|
||||
func (r *ResObjectPutSingle) Epoch() uint64 {
|
||||
return r.epoch
|
||||
}
|
||||
|
||||
func (prm *PrmObjectPutSingle) buildRequest(c *Client) (*v2object.PutSingleRequest, error) {
|
||||
|
@ -149,7 +142,7 @@ func (c *Client) ObjectPutSingle(ctx context.Context, prm PrmObjectPutSingle) (*
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key := &c.prm.Key
|
||||
key := &c.prm.key
|
||||
if prm.Key != nil {
|
||||
key = prm.Key
|
||||
}
|
||||
|
@ -169,7 +162,6 @@ func (c *Client) ObjectPutSingle(ctx context.Context, prm PrmObjectPutSingle) (*
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.epoch = resp.GetMetaHeader().GetEpoch()
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
buffPool "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/pool"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
|
||||
|
@ -17,7 +16,7 @@ func (c *Client) objectPutInitTransformer(prm PrmObjectPutInit) (*objectWriterTr
|
|||
client: c,
|
||||
prm: prm,
|
||||
}
|
||||
key := &c.prm.Key
|
||||
key := &c.prm.key
|
||||
if prm.Key != nil {
|
||||
key = prm.Key
|
||||
}
|
||||
|
@ -27,7 +26,6 @@ func (c *Client) objectPutInitTransformer(prm PrmObjectPutInit) (*objectWriterTr
|
|||
MaxSize: prm.MaxSize,
|
||||
WithoutHomomorphicHash: prm.WithoutHomomorphHash,
|
||||
NetworkState: prm.EpochSource,
|
||||
Pool: prm.Pool,
|
||||
})
|
||||
return &w, nil
|
||||
}
|
||||
|
@ -49,20 +47,13 @@ func (x *objectWriterTransformer) WritePayloadChunk(ctx context.Context, chunk [
|
|||
}
|
||||
|
||||
func (x *objectWriterTransformer) Close(ctx context.Context) (*ResObjectPut, error) {
|
||||
if x.err != nil {
|
||||
return nil, x.err
|
||||
}
|
||||
|
||||
ai, err := x.ot.Close(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ai != nil {
|
||||
x.it.res.epoch = ai.Epoch
|
||||
if ai.ParentID != nil {
|
||||
x.it.res.obj = *ai.ParentID
|
||||
}
|
||||
if ai != nil && ai.ParentID != nil {
|
||||
x.it.res.obj = *ai.ParentID
|
||||
}
|
||||
return x.it.res, nil
|
||||
}
|
||||
|
@ -92,7 +83,7 @@ func (it *internalTarget) putAsStream(ctx context.Context, o *object.Object) err
|
|||
wrt.WritePayloadChunk(ctx, o.Payload())
|
||||
}
|
||||
it.res, err = wrt.Close(ctx)
|
||||
if err == nil && it.client.prm.DisableFrostFSErrorResolution && !apistatus.IsSuccessful(it.res.st) {
|
||||
if err == nil && !it.client.prm.resolveFrostFSErrors && !apistatus.IsSuccessful(it.res.st) {
|
||||
err = apistatus.ErrFromStatus(it.res.st)
|
||||
}
|
||||
return err
|
||||
|
@ -119,26 +110,15 @@ func (it *internalTarget) tryPutSingle(ctx context.Context, o *object.Object) (b
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
it.returnBuffPool(o.Payload())
|
||||
id, _ := o.ID()
|
||||
it.res = &ResObjectPut{
|
||||
statusRes: res.statusRes,
|
||||
obj: id,
|
||||
epoch: res.epoch,
|
||||
}
|
||||
if it.client.prm.DisableFrostFSErrorResolution && !apistatus.IsSuccessful(it.res.st) {
|
||||
if !it.client.prm.resolveFrostFSErrors && !apistatus.IsSuccessful(it.res.st) {
|
||||
return true, apistatus.ErrFromStatus(it.res.st)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
func (it *internalTarget) returnBuffPool(playback []byte) {
|
||||
if it.prm.Pool == nil {
|
||||
return
|
||||
}
|
||||
var buffer buffPool.Buffer
|
||||
buffer.Data = playback
|
||||
it.prm.Pool.Put(&buffer)
|
||||
}
|
||||
|
|
|
@ -24,26 +24,19 @@ import (
|
|||
|
||||
// PrmObjectSearch groups parameters of ObjectSearch operation.
|
||||
type PrmObjectSearch struct {
|
||||
XHeaders []string
|
||||
meta v2session.RequestMetaHeader
|
||||
|
||||
Local bool
|
||||
key *ecdsa.PrivateKey
|
||||
|
||||
BearerToken *bearer.Token
|
||||
cnrSet bool
|
||||
cnrID cid.ID
|
||||
|
||||
Session *session.Object
|
||||
|
||||
ContainerID *cid.ID
|
||||
|
||||
Key *ecdsa.PrivateKey
|
||||
|
||||
Filters object.SearchFilters
|
||||
filters object.SearchFilters
|
||||
}
|
||||
|
||||
// MarkLocal tells the server to execute the operation locally.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.Local instead.
|
||||
func (x *PrmObjectSearch) MarkLocal() {
|
||||
x.Local = true
|
||||
x.meta.SetTTL(1)
|
||||
}
|
||||
|
||||
// WithinSession specifies session within which the search query must be executed.
|
||||
|
@ -52,10 +45,10 @@ func (x *PrmObjectSearch) MarkLocal() {
|
|||
// This may affect the execution of an operation (e.g. access control).
|
||||
//
|
||||
// Must be signed.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.Session instead.
|
||||
func (x *PrmObjectSearch) WithinSession(t session.Object) {
|
||||
x.Session = &t
|
||||
var tokv2 v2session.Token
|
||||
t.WriteToV2(&tokv2)
|
||||
x.meta.SetSessionToken(&tokv2)
|
||||
}
|
||||
|
||||
// WithBearerToken attaches bearer token to be used for the operation.
|
||||
|
@ -63,44 +56,37 @@ func (x *PrmObjectSearch) WithinSession(t session.Object) {
|
|||
// If set, underlying eACL rules will be used in access control.
|
||||
//
|
||||
// Must be signed.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.BearerToken instead.
|
||||
func (x *PrmObjectSearch) WithBearerToken(t bearer.Token) {
|
||||
x.BearerToken = &t
|
||||
var v2token acl.BearerToken
|
||||
t.WriteToV2(&v2token)
|
||||
x.meta.SetBearerToken(&v2token)
|
||||
}
|
||||
|
||||
// WithXHeaders specifies list of extended headers (string key-value pairs)
|
||||
// to be attached to the request. Must have an even length.
|
||||
//
|
||||
// Slice must not be mutated until the operation completes.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.XHeaders instead.
|
||||
func (x *PrmObjectSearch) WithXHeaders(hs ...string) {
|
||||
x.XHeaders = hs
|
||||
writeXHeadersToMeta(hs, &x.meta)
|
||||
}
|
||||
|
||||
// UseKey specifies private key to sign the requests.
|
||||
// If key is not provided, then Client default key is used.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.Key instead.
|
||||
func (x *PrmObjectSearch) UseKey(key ecdsa.PrivateKey) {
|
||||
x.Key = &key
|
||||
x.key = &key
|
||||
}
|
||||
|
||||
// InContainer specifies the container in which to look for objects.
|
||||
// Required parameter.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.ContainerID instead.
|
||||
func (x *PrmObjectSearch) InContainer(id cid.ID) {
|
||||
x.ContainerID = &id
|
||||
x.cnrID = id
|
||||
x.cnrSet = true
|
||||
}
|
||||
|
||||
// SetFilters sets filters by which to select objects. All container objects
|
||||
// match unset/empty filters.
|
||||
//
|
||||
// Deprecated: Use PrmObjectSearch.Filters instead.
|
||||
func (x *PrmObjectSearch) SetFilters(filters object.SearchFilters) {
|
||||
x.Filters = filters
|
||||
x.filters = filters
|
||||
}
|
||||
|
||||
// ResObjectSearch groups the final result values of ObjectSearch operation.
|
||||
|
@ -226,48 +212,6 @@ func (x *ObjectListReader) Close() (*ResObjectSearch, error) {
|
|||
return &x.res, nil
|
||||
}
|
||||
|
||||
func (x *PrmObjectSearch) buildRequest(c *Client) (*v2object.SearchRequest, error) {
|
||||
if x.ContainerID == nil {
|
||||
return nil, errorMissingContainer
|
||||
}
|
||||
|
||||
if len(x.XHeaders)%2 != 0 {
|
||||
return nil, errorInvalidXHeaders
|
||||
}
|
||||
|
||||
meta := new(v2session.RequestMetaHeader)
|
||||
writeXHeadersToMeta(x.XHeaders, meta)
|
||||
|
||||
if x.BearerToken != nil {
|
||||
v2BearerToken := new(acl.BearerToken)
|
||||
x.BearerToken.WriteToV2(v2BearerToken)
|
||||
meta.SetBearerToken(v2BearerToken)
|
||||
}
|
||||
|
||||
if x.Session != nil {
|
||||
v2SessionToken := new(v2session.Token)
|
||||
x.Session.WriteToV2(v2SessionToken)
|
||||
meta.SetSessionToken(v2SessionToken)
|
||||
}
|
||||
|
||||
if x.Local {
|
||||
meta.SetTTL(1)
|
||||
}
|
||||
cnrV2 := new(v2refs.ContainerID)
|
||||
x.ContainerID.WriteToV2(cnrV2)
|
||||
|
||||
body := new(v2object.SearchRequestBody)
|
||||
body.SetVersion(1)
|
||||
body.SetContainerID(cnrV2)
|
||||
body.SetFilters(x.Filters.ToV2())
|
||||
|
||||
req := new(v2object.SearchRequest)
|
||||
req.SetBody(body)
|
||||
c.prepareRequest(req, meta)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// ObjectSearchInit initiates object selection through a remote server using FrostFS API protocol.
|
||||
//
|
||||
// The call only opens the transmission channel, explicit fetching of matched objects
|
||||
|
@ -277,17 +221,30 @@ func (x *PrmObjectSearch) buildRequest(c *Client) (*v2object.SearchRequest, erro
|
|||
// Returns an error if parameters are set incorrectly (see PrmObjectSearch docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*ObjectListReader, error) {
|
||||
req, err := prm.buildRequest(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// check parameters
|
||||
if !prm.cnrSet {
|
||||
return nil, errorMissingContainer
|
||||
}
|
||||
|
||||
key := prm.Key
|
||||
var cidV2 v2refs.ContainerID
|
||||
prm.cnrID.WriteToV2(&cidV2)
|
||||
|
||||
var body v2object.SearchRequestBody
|
||||
body.SetVersion(1)
|
||||
body.SetContainerID(&cidV2)
|
||||
body.SetFilters(prm.filters.ToV2())
|
||||
|
||||
// init reader
|
||||
var req v2object.SearchRequest
|
||||
req.SetBody(&body)
|
||||
c.prepareRequest(&req, &prm.meta)
|
||||
|
||||
key := prm.key
|
||||
if key == nil {
|
||||
key = &c.prm.Key
|
||||
key = &c.prm.key
|
||||
}
|
||||
|
||||
err = signature.SignServiceMessage(key, req)
|
||||
err := signature.SignServiceMessage(key, &req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
@ -295,7 +252,7 @@ func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*Ob
|
|||
var r ObjectListReader
|
||||
ctx, r.cancelCtxStream = context.WithCancel(ctx)
|
||||
|
||||
r.stream, err = rpcapi.SearchObjects(&c.c, req, client.WithContext(ctx))
|
||||
r.stream, err = rpcapi.SearchObjects(&c.c, &req, client.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open stream: %w", err)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (x *PrmSessionCreate) UseKey(key ecdsa.PrivateKey) {
|
|||
}
|
||||
|
||||
func (x *PrmSessionCreate) buildRequest(c *Client) (*v2session.CreateRequest, error) {
|
||||
ownerKey := c.prm.Key.PublicKey
|
||||
ownerKey := c.prm.key.PublicKey
|
||||
if x.Key != nil {
|
||||
ownerKey = x.Key.PublicKey
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ func (x ResSessionCreate) PublicKey() []byte {
|
|||
//
|
||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||
// Any client's internal or transport errors are returned as `error`.
|
||||
// If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful
|
||||
// FrostFS status codes are included in the returned result structure,
|
||||
// otherwise, are also returned as `error`.
|
||||
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
|
||||
// FrostFS status codes are returned as `error`, otherwise, are included
|
||||
// in the returned result structure.
|
||||
//
|
||||
// Returns an error if parameters are set incorrectly (see PrmSessionCreate docs).
|
||||
// Context is required and must not be nil. It is used for network communication.
|
||||
|
@ -104,7 +104,7 @@ func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResS
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := signature.SignServiceMessage(&c.prm.Key, req); err != nil {
|
||||
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package apistatus
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
|
||||
)
|
||||
|
||||
// APEManagerAccessDenied describes status of the failure because of the access control violation.
|
||||
// Instances provide Status and StatusV2 interfaces.
|
||||
type APEManagerAccessDenied struct {
|
||||
v2 status.Status
|
||||
}
|
||||
|
||||
const defaultAPEManagerAccessDeniedMsg = "apemanager access denied"
|
||||
|
||||
func (x *APEManagerAccessDenied) Error() string {
|
||||
msg := x.v2.Message()
|
||||
if msg == "" {
|
||||
msg = defaultAPEManagerAccessDeniedMsg
|
||||
}
|
||||
|
||||
return errMessageStatusV2(
|
||||
globalizeCodeV2(apemanager.StatusAPEManagerAccessDenied, apemanager.GlobalizeFail),
|
||||
msg,
|
||||
)
|
||||
}
|
||||
|
||||
func (x *APEManagerAccessDenied) fromStatusV2(st *status.Status) {
|
||||
x.v2 = *st
|
||||
}
|
||||
|
||||
// ToStatusV2 converts APEManagerAccessDenied to v2's Status.
|
||||
// If the value was returned by FromStatusV2, returns the source message.
|
||||
// Otherwise, returns message with
|
||||
// - code: APE_MANAGER_ACCESS_DENIED;
|
||||
// - string message: "apemanager access denied";
|
||||
// - details: empty.
|
||||
func (x APEManagerAccessDenied) ToStatusV2() *status.Status {
|
||||
x.v2.SetCode(globalizeCodeV2(apemanager.StatusAPEManagerAccessDenied, apemanager.GlobalizeFail))
|
||||
x.v2.SetMessage(defaultAPEManagerAccessDeniedMsg)
|
||||
return &x.v2
|
||||
}
|
||||
|
||||
// WriteReason writes human-readable access rejection reason.
|
||||
func (x *APEManagerAccessDenied) WriteReason(reason string) {
|
||||
apemanager.WriteAccessDeniedDesc(&x.v2, reason)
|
||||
}
|
||||
|
||||
// Reason returns human-readable access rejection reason returned by the server.
|
||||
// Returns empty value is reason is not presented.
|
||||
func (x APEManagerAccessDenied) Reason() string {
|
||||
return apemanager.ReadAccessDeniedDesc(x.v2)
|
||||
}
|
|
@ -3,7 +3,6 @@ package apistatus
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||
|
@ -93,12 +92,6 @@ func FromStatusV2(st *status.Status) Status {
|
|||
case session.StatusTokenExpired:
|
||||
decoder = new(SessionTokenExpired)
|
||||
}
|
||||
case apemanager.LocalizeFailStatus(&code):
|
||||
//nolint:exhaustive
|
||||
switch code {
|
||||
case apemanager.StatusAPEManagerAccessDenied:
|
||||
decoder = new(APEManagerAccessDenied)
|
||||
}
|
||||
}
|
||||
|
||||
if decoder == nil {
|
||||
|
|
|
@ -125,12 +125,6 @@ func TestToStatusV2(t *testing.T) {
|
|||
}),
|
||||
codeV2: 4097,
|
||||
},
|
||||
{
|
||||
status: (statusConstructor)(func() apistatus.Status {
|
||||
return new(apistatus.APEManagerAccessDenied)
|
||||
}),
|
||||
codeV2: 5120,
|
||||
},
|
||||
{
|
||||
status: (statusConstructor)(func() apistatus.Status {
|
||||
return new(apistatus.NodeUnderMaintenance)
|
||||
|
@ -284,12 +278,6 @@ func TestFromStatusV2(t *testing.T) {
|
|||
}),
|
||||
codeV2: 4097,
|
||||
},
|
||||
{
|
||||
status: (statusConstructor)(func() apistatus.Status {
|
||||
return new(apistatus.APEManagerAccessDenied)
|
||||
}),
|
||||
codeV2: 5120,
|
||||
},
|
||||
{
|
||||
status: (statusConstructor)(func() apistatus.Status {
|
||||
return new(apistatus.NodeUnderMaintenance)
|
||||
|
|
|
@ -355,7 +355,7 @@ func (x Container) IterateAttributes(f func(key, val string)) {
|
|||
func (x Container) IterateUserAttributes(f func(key, val string)) {
|
||||
attrs := x.v2.GetAttributes()
|
||||
for _, attr := range attrs {
|
||||
key := attr.GetKey()
|
||||
var key = attr.GetKey()
|
||||
if !strings.HasPrefix(key, container.SysAttributePrefix) &&
|
||||
!strings.HasPrefix(key, container.SysAttributePrefixNeoFS) {
|
||||
f(key, attr.GetValue())
|
||||
|
|
|
@ -78,7 +78,7 @@ func TestContainer_Owner(t *testing.T) {
|
|||
|
||||
val = containertest.Container()
|
||||
|
||||
owner := usertest.ID()
|
||||
owner := *usertest.ID()
|
||||
|
||||
val.SetOwner(owner)
|
||||
|
||||
|
|
104
container/size.go
Normal file
104
container/size.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
)
|
||||
|
||||
// SizeEstimation groups information about estimation of the size of the data
|
||||
// stored in the FrostFS container.
|
||||
//
|
||||
// SizeEstimation is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.UsedSpaceAnnouncement
|
||||
// message. See ReadFromV2 / WriteToV2 methods.
|
||||
type SizeEstimation struct {
|
||||
m container.UsedSpaceAnnouncement
|
||||
}
|
||||
|
||||
// ReadFromV2 reads SizeEstimation from the container.UsedSpaceAnnouncement message.
|
||||
// Checks if the message conforms to FrostFS API V2 protocol.
|
||||
//
|
||||
// See also WriteToV2.
|
||||
func (x *SizeEstimation) ReadFromV2(m container.UsedSpaceAnnouncement) error {
|
||||
cnrV2 := m.GetContainerID()
|
||||
if cnrV2 == nil {
|
||||
return errors.New("missing container")
|
||||
}
|
||||
|
||||
var cnr cid.ID
|
||||
|
||||
err := cnr.ReadFromV2(*cnrV2)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid container: %w", err)
|
||||
}
|
||||
|
||||
x.m = m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteToV2 writes SizeEstimation into the container.UsedSpaceAnnouncement message.
|
||||
// The message MUST NOT be nil.
|
||||
//
|
||||
// See also ReadFromV2.
|
||||
func (x SizeEstimation) WriteToV2(m *container.UsedSpaceAnnouncement) {
|
||||
*m = x.m
|
||||
}
|
||||
|
||||
// SetEpoch sets epoch when estimation of the container data size was calculated.
|
||||
//
|
||||
// See also Epoch.
|
||||
func (x *SizeEstimation) SetEpoch(epoch uint64) {
|
||||
x.m.SetEpoch(epoch)
|
||||
}
|
||||
|
||||
// Epoch return epoch set using SetEpoch.
|
||||
//
|
||||
// Zero SizeEstimation represents estimation in zero epoch.
|
||||
func (x SizeEstimation) Epoch() uint64 {
|
||||
return x.m.GetEpoch()
|
||||
}
|
||||
|
||||
// SetContainer specifies the container for which the amount of data is estimated.
|
||||
// Required by the FrostFS API protocol.
|
||||
//
|
||||
// See also Container.
|
||||
func (x *SizeEstimation) SetContainer(cnr cid.ID) {
|
||||
var cidV2 refs.ContainerID
|
||||
cnr.WriteToV2(&cidV2)
|
||||
|
||||
x.m.SetContainerID(&cidV2)
|
||||
}
|
||||
|
||||
// Container returns container set using SetContainer.
|
||||
//
|
||||
// Zero SizeEstimation is not bound to any container (returns zero) which is
|
||||
// incorrect according to FrostFS API protocol.
|
||||
func (x SizeEstimation) Container() (res cid.ID) {
|
||||
m := x.m.GetContainerID()
|
||||
if m != nil {
|
||||
err := res.ReadFromV2(*m)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unexpected error from cid.ID.ReadFromV2: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SetValue sets estimated amount of data (in bytes) in the specified container.
|
||||
//
|
||||
// See also Value.
|
||||
func (x *SizeEstimation) SetValue(value uint64) {
|
||||
x.m.SetUsedSpace(value)
|
||||
}
|
||||
|
||||
// Value returns data size estimation set using SetValue.
|
||||
//
|
||||
// Zero SizeEstimation has zero value.
|
||||
func (x SizeEstimation) Value() uint64 {
|
||||
return x.m.GetUsedSpace()
|
||||
}
|
94
container/size_test.go
Normal file
94
container/size_test.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package container_test
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSizeEstimation_Epoch(t *testing.T) {
|
||||
var val container.SizeEstimation
|
||||
|
||||
require.Zero(t, val.Epoch())
|
||||
|
||||
const epoch = 123
|
||||
|
||||
val.SetEpoch(epoch)
|
||||
require.EqualValues(t, epoch, val.Epoch())
|
||||
|
||||
var msg v2container.UsedSpaceAnnouncement
|
||||
val.WriteToV2(&msg)
|
||||
|
||||
require.EqualValues(t, epoch, msg.GetEpoch())
|
||||
}
|
||||
|
||||
func TestSizeEstimation_Container(t *testing.T) {
|
||||
var val container.SizeEstimation
|
||||
|
||||
require.Zero(t, val.Container())
|
||||
|
||||
cnr := cidtest.ID()
|
||||
|
||||
val.SetContainer(cnr)
|
||||
require.True(t, val.Container().Equals(cnr))
|
||||
|
||||
var msg v2container.UsedSpaceAnnouncement
|
||||
val.WriteToV2(&msg)
|
||||
|
||||
var msgCnr refs.ContainerID
|
||||
cnr.WriteToV2(&msgCnr)
|
||||
|
||||
require.Equal(t, &msgCnr, msg.GetContainerID())
|
||||
}
|
||||
|
||||
func TestSizeEstimation_Value(t *testing.T) {
|
||||
var val container.SizeEstimation
|
||||
|
||||
require.Zero(t, val.Value())
|
||||
|
||||
const value = 876
|
||||
|
||||
val.SetValue(value)
|
||||
require.EqualValues(t, value, val.Value())
|
||||
|
||||
var msg v2container.UsedSpaceAnnouncement
|
||||
val.WriteToV2(&msg)
|
||||
|
||||
require.EqualValues(t, value, msg.GetUsedSpace())
|
||||
}
|
||||
|
||||
func TestSizeEstimation_ReadFromV2(t *testing.T) {
|
||||
const epoch = 654
|
||||
const value = 903
|
||||
var cnrMsg refs.ContainerID
|
||||
|
||||
var msg v2container.UsedSpaceAnnouncement
|
||||
|
||||
var val container.SizeEstimation
|
||||
|
||||
require.Error(t, val.ReadFromV2(msg))
|
||||
|
||||
msg.SetContainerID(&cnrMsg)
|
||||
|
||||
require.Error(t, val.ReadFromV2(msg))
|
||||
|
||||
cnrMsg.SetValue(make([]byte, sha256.Size))
|
||||
|
||||
var cnr cid.ID
|
||||
require.NoError(t, cnr.ReadFromV2(cnrMsg))
|
||||
|
||||
msg.SetEpoch(epoch)
|
||||
msg.SetUsedSpace(value)
|
||||
|
||||
require.NoError(t, val.ReadFromV2(msg))
|
||||
|
||||
require.EqualValues(t, epoch, val.Epoch())
|
||||
require.EqualValues(t, value, val.Value())
|
||||
require.EqualValues(t, cnr, val.Container())
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
|
||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
||||
)
|
||||
|
@ -15,13 +16,22 @@ func Container() (x container.Container) {
|
|||
|
||||
x.Init()
|
||||
x.SetAttribute("some attribute", "value")
|
||||
x.SetOwner(owner)
|
||||
x.SetOwner(*owner)
|
||||
x.SetBasicACL(BasicACL())
|
||||
x.SetPlacementPolicy(netmaptest.PlacementPolicy())
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// SizeEstimation returns random container.SizeEstimation.
|
||||
func SizeEstimation() (x container.SizeEstimation) {
|
||||
x.SetContainer(cidtest.ID())
|
||||
x.SetEpoch(rand.Uint64())
|
||||
x.SetValue(rand.Uint64())
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// BasicACL returns random acl.Basic.
|
||||
func BasicACL() (x acl.Basic) {
|
||||
x.FromBits(rand.Uint32())
|
||||
|
|
|
@ -125,7 +125,7 @@ func (r *Record) AddObjectContainerIDFilter(m Match, id cid.ID) {
|
|||
}
|
||||
|
||||
// AddObjectOwnerIDFilter adds filter by object owner ID.
|
||||
func (r *Record) AddObjectOwnerIDFilter(m Match, id user.ID) {
|
||||
func (r *Record) AddObjectOwnerIDFilter(m Match, id *user.ID) {
|
||||
r.addObjectReservedFilter(m, fKeyObjOwnerID, id)
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,14 @@ func TestReservedRecords(t *testing.T) {
|
|||
key: v2acl.FilterObjectType,
|
||||
value: "TOMBSTONE",
|
||||
},
|
||||
{
|
||||
f: func(r *Record) {
|
||||
require.True(t, typ.FromString("STORAGE_GROUP"))
|
||||
r.AddObjectTypeFilter(MatchStringEqual, *typ)
|
||||
},
|
||||
key: v2acl.FilterObjectType,
|
||||
value: "STORAGE_GROUP",
|
||||
},
|
||||
}
|
||||
|
||||
for n, testCase := range testSuit {
|
||||
|
|
|
@ -7,7 +7,8 @@ import (
|
|||
// Validator is a tool that calculates
|
||||
// the action on a request according
|
||||
// to the extended ACL rule table.
|
||||
type Validator struct{}
|
||||
type Validator struct {
|
||||
}
|
||||
|
||||
// NewValidator creates and initializes a new Validator using options.
|
||||
func NewValidator() *Validator {
|
||||
|
|
55
go.mod
55
go.mod
|
@ -1,47 +1,46 @@
|
|||
module git.frostfs.info/TrueCloudLab/frostfs-sdk-go
|
||||
|
||||
go 1.21
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230802075510-964c3edb3f44
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
|
||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1
|
||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/klauspost/reedsolomon v1.12.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/nspcc-dev/neo-go v0.106.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.uber.org/zap v1.27.0
|
||||
google.golang.org/grpc v1.62.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc
|
||||
github.com/stretchr/testify v1.8.3
|
||||
go.uber.org/zap v1.24.0
|
||||
google.golang.org/grpc v1.55.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 // indirect
|
||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 // indirect
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||
go.etcd.io/bbolt v1.3.9 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
727
go.sum
727
go.sum
|
@ -1,7 +1,40 @@
|
|||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3 h1:BbtF/98HU0nBl4szdDYAV3XadNE5sJ92uSFmNePQmfA=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e h1:kcBqZBiFIUBATUqEuvVigtkJJWQ2Gug/eYXn967o3M4=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
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.15.1-0.20230802075510-964c3edb3f44 h1:v6JqBD/VzZx3QSxbaXnUwnnJ1KEYheU4LzLGr3IhsAE=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230802075510-964c3edb3f44/go.mod h1:pKJJRLOChW4zDQsAt1e8k/snWKljJtpkiPfxV53ngjI=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb h1:S/TrbOOu9qEXZRZ9/Ddw7crnxbBUQLo68PSzQWYrc9M=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
||||
|
@ -10,183 +43,691 @@ git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9m
|
|||
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/go.mod h1:dhY+oy274hV8wGvGL4MwwMpdL3GYvaX1a8GQZQHvlF8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1:MJCkWUBhi9pn/CrYO1Q3P687y2KeahrOPS9BD9LDGb0=
|
||||
github.com/CityOfZion/neo-go v0.70.1-pre.0.20191209120015-fccb0085941e/go.mod h1:0enZl0az8xA6PVkwzEOwPWVJGqlt/GO4hA4kmQ5Xzig=
|
||||
github.com/CityOfZion/neo-go v0.70.1-pre.0.20191212173117-32ac01130d4c/go.mod h1:JtlHfeqLywZLswKIKFnAp+yzezY4Dji9qlfQKB2OD/I=
|
||||
github.com/CityOfZion/neo-go v0.71.1-pre.0.20200129171427-f773ec69fb84/go.mod h1:FLI526IrRWHmcsO+mHsCbj64pJZhwQFTLJZu+A4PGOA=
|
||||
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
|
||||
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
|
||||
github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs=
|
||||
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
|
||||
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-redis/redis v6.10.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
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.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
|
||||
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.12.1 h1:NhWgum1efX1x58daOBGCFWcxtEhOhXKKl1HAPQUp03Q=
|
||||
github.com/klauspost/reedsolomon v1.12.1/go.mod h1:nEi5Kjb6QqtbofI6s+cbG/j1da11c96IBYBSnVGtuBs=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
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/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
|
||||
github.com/nspcc-dev/neo-go v0.106.2 h1:KXSJ2J5Oacc7LrX3r4jvnC8ihKqHs5NB21q4f2S3r9o=
|
||||
github.com/nspcc-dev/neo-go v0.106.2/go.mod h1:Ojwfx3/lv0VTeEHMpQ17g0wTnXcCSoFQVq5GEeCZmGo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647/go.mod h1:g9xisXmX9NP9MjioaTe862n9SlZTrP+6PVUWLBYOr98=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
||||
github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
|
||||
github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
|
||||
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
|
||||
github.com/nspcc-dev/neo-go v0.99.4/go.mod h1:mKTolfRUfKjFso5HPvGSQtUZc70n0VKBMs16eGuC5gA=
|
||||
github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc h1:fySIWvUQsitK5e5qYIHnTDCXuPpwzz89SEUEIyY11sg=
|
||||
github.com/nspcc-dev/neo-go v0.101.2-0.20230601131642-a0117042e8fc/go.mod h1:s9QhjMC784MWqTURovMbyYduIJc86mnCruxcMiAebpc=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220927123257-24c107e3a262/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce h1:vLGuUNDkmQrWMa4rr4vTd1u8ULqejWxVmNz1L7ocTEI=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230615193820-9185820289ce/go.mod h1:ZUuXOkdtHZgaC13za/zMgXfQFncZ0jLzfQTe+OsDOtg=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
|
||||
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||
github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs=
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
||||
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/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.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.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/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
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.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
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.27/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.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/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-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
|
||||
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/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-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/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-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.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20190813064441-fde4db37ae7a/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-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-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/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-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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/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-20200923182605-d9f96fdee20d/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180318012157-96caea41033d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
||||
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
|
||||
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/grpc 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.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/abiosoft/ishell.v2 v2.0.0/go.mod h1:sFp+cGtH6o4s1FtpVPTMcHq2yue+c4DGOVohJCPUzwY=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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/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.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package netmap
|
||||
|
||||
import "slices"
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
type (
|
||||
// aggregator can calculate some value across all netmap
|
||||
|
@ -26,6 +28,7 @@ type (
|
|||
}
|
||||
|
||||
meanIQRAgg struct {
|
||||
k float64
|
||||
arr []float64
|
||||
}
|
||||
|
||||
|
@ -71,6 +74,12 @@ func newMinAgg() aggregator {
|
|||
return new(minAgg)
|
||||
}
|
||||
|
||||
// newMeanIQRAgg returns an aggregator which
|
||||
// computes mean value of values from IQR interval.
|
||||
func newMeanIQRAgg() aggregator {
|
||||
return new(meanIQRAgg)
|
||||
}
|
||||
|
||||
// newReverseMinNorm returns a normalizer which
|
||||
// normalize values in range of 0.0 to 1.0 to a minimum value.
|
||||
func newReverseMinNorm(min float64) normalizer {
|
||||
|
@ -109,10 +118,6 @@ func (a *minAgg) Compute() float64 {
|
|||
return a.min
|
||||
}
|
||||
|
||||
func (a *meanIQRAgg) clear() {
|
||||
a.arr = a.arr[:0]
|
||||
}
|
||||
|
||||
func (a *meanIQRAgg) Add(n float64) {
|
||||
a.arr = append(a.arr, n)
|
||||
}
|
||||
|
@ -123,7 +128,7 @@ func (a *meanIQRAgg) Compute() float64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
slices.Sort(a.arr)
|
||||
sort.Slice(a.arr, func(i, j int) bool { return a.arr[i] < a.arr[j] })
|
||||
|
||||
var min, max float64
|
||||
|
||||
|
@ -133,7 +138,8 @@ func (a *meanIQRAgg) Compute() float64 {
|
|||
min, max = a.arr[0], a.arr[l-1]
|
||||
} else {
|
||||
start, end := l/minLn, l*3/minLn-1
|
||||
min, max = a.arr[start], a.arr[end]
|
||||
iqr := a.k * (a.arr[end] - a.arr[start])
|
||||
min, max = a.arr[start]-iqr, a.arr[end]+iqr
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
@ -150,7 +156,11 @@ func (a *meanIQRAgg) Compute() float64 {
|
|||
}
|
||||
|
||||
func (r *reverseMinNorm) Normalize(w float64) float64 {
|
||||
return (r.min + 1) / (w + 1)
|
||||
if w == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.min / w
|
||||
}
|
||||
|
||||
func (r *sigmoidNorm) Normalize(w float64) float64 {
|
||||
|
|
|
@ -53,6 +53,7 @@ func BenchmarkNetmap_ContainerNodes(b *testing.B) {
|
|||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -9,41 +8,24 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// TestCase represents collection of placement policy tests for a single node set.
|
||||
type TestCase struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Nodes []NodeInfo `json:"nodes" yaml:"nodes"`
|
||||
Name string `json:"name"`
|
||||
Nodes []NodeInfo `json:"nodes"`
|
||||
Tests map[string]struct {
|
||||
Policy PlacementPolicy
|
||||
Pivot Base64
|
||||
Result [][]int `json:"result,omitempty" yaml:"result,omitempty"`
|
||||
Error string `json:"error,omitempty" yaml:"error,omitempty"`
|
||||
Policy PlacementPolicy `json:"policy"`
|
||||
Pivot []byte `json:"pivot,omitempty"`
|
||||
Result [][]int `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Placement struct {
|
||||
Pivot Base64 `json:"pivot" yaml:"pivot"`
|
||||
Result [][]int `json:"result,omitempty" yaml:"result,omitempty"`
|
||||
} `json:"placement,omitempty" yaml:"placement,omitempty"`
|
||||
Pivot []byte
|
||||
Result [][]int
|
||||
} `json:"placement,omitempty"`
|
||||
}
|
||||
}
|
||||
|
||||
// Base64 is a type that will hold the decoded Base64 data.
|
||||
type Base64 []byte
|
||||
|
||||
func (b *Base64) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var base64Str string
|
||||
if err := unmarshal(&base64Str); err != nil {
|
||||
return err
|
||||
}
|
||||
decodedBytes, err := base64.StdEncoding.DecodeString(base64Str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = decodedBytes
|
||||
return nil
|
||||
}
|
||||
|
||||
var _, _ json.Unmarshaler = new(NodeInfo), new(PlacementPolicy)
|
||||
|
||||
func compareNodes(t testing.TB, expected [][]int, nodes nodes, actual [][]NodeInfo) {
|
||||
|
@ -57,7 +39,7 @@ func compareNodes(t testing.TB, expected [][]int, nodes nodes, actual [][]NodeIn
|
|||
}
|
||||
|
||||
func TestPlacementPolicy_Interopability(t *testing.T) {
|
||||
const testsDir = "./yml_tests"
|
||||
const testsDir = "./json_tests"
|
||||
|
||||
f, err := os.Open(testsDir)
|
||||
require.NoError(t, err)
|
||||
|
@ -71,7 +53,7 @@ func TestPlacementPolicy_Interopability(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
var tc TestCase
|
||||
require.NoError(t, yaml.Unmarshal(bs, &tc), "cannot unmarshal %s", ds[i].Name())
|
||||
require.NoError(t, json.Unmarshal(bs, &tc), "cannot unmarshal %s", ds[i].Name())
|
||||
|
||||
srcNodes := make([]NodeInfo, len(tc.Nodes))
|
||||
copy(srcNodes, tc.Nodes)
|
||||
|
@ -106,7 +88,7 @@ func TestPlacementPolicy_Interopability(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkPlacementPolicyInteropability(b *testing.B) {
|
||||
const testsDir = "./yml_tests"
|
||||
const testsDir = "./json_tests"
|
||||
|
||||
f, err := os.Open(testsDir)
|
||||
require.NoError(b, err)
|
||||
|
@ -119,7 +101,7 @@ func BenchmarkPlacementPolicyInteropability(b *testing.B) {
|
|||
require.NoError(b, err)
|
||||
|
||||
var tc TestCase
|
||||
require.NoError(b, yaml.Unmarshal(bs, &tc), "cannot unmarshal %s", ds[i].Name())
|
||||
require.NoError(b, json.Unmarshal(bs, &tc), "cannot unmarshal %s", ds[i].Name())
|
||||
|
||||
b.Run(tc.Name, func(b *testing.B) {
|
||||
var nm NetMap
|
||||
|
@ -158,12 +140,12 @@ func BenchmarkPlacementPolicyInteropability(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkManySelects(b *testing.B) {
|
||||
testsFile := filepath.Join("yml_tests", "many_selects.yml")
|
||||
testsFile := filepath.Join("json_tests", "many_selects.json")
|
||||
bs, err := os.ReadFile(testsFile)
|
||||
require.NoError(b, err)
|
||||
|
||||
var tc TestCase
|
||||
require.NoError(b, yaml.Unmarshal(bs, &tc))
|
||||
require.NoError(b, json.Unmarshal(bs, &tc))
|
||||
tt, ok := tc.Tests["Select"]
|
||||
require.True(b, ok)
|
||||
|
99
netmap/json_tests/cbf_default.json
Normal file
99
netmap/json_tests/cbf_default.json
Normal file
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"name": "default CBF is 3",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "DE"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Berlin"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "FR"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Paris"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"set default CBF": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "EU"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 0,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "EU",
|
||||
"count": 1,
|
||||
"clause": "SAME",
|
||||
"attribute": "Location",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
99
netmap/json_tests/cbf_minimal.json
Normal file
99
netmap/json_tests/cbf_minimal.json
Normal file
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"name": "Real node count multiplier is in range [1, specified CBF]",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "DE"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "DE"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "DE"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"select 2, CBF is 2": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "X"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 2,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "X",
|
||||
"count": 2,
|
||||
"clause": "SAME",
|
||||
"attribute": "Country",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
},
|
||||
"select 3, CBF is 2": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "X"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 2,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "X",
|
||||
"count": 3,
|
||||
"clause": "SAME",
|
||||
"attribute": "Country",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
155
netmap/json_tests/cbf_requirements.json
Normal file
155
netmap/json_tests/cbf_requirements.json
Normal file
|
@ -0,0 +1,155 @@
|
|||
{
|
||||
"name": "CBF requirements",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "Attr",
|
||||
"value": "Same"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Attr",
|
||||
"value": "Same"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "Attr",
|
||||
"value": "Same"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "Attr",
|
||||
"value": "Same"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"default CBF, no selector": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 2,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 0,
|
||||
"selectors": [],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
]
|
||||
]
|
||||
},
|
||||
"explicit CBF, no selector": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 2,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 3,
|
||||
"selectors": [],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
]
|
||||
]
|
||||
},
|
||||
"select distinct, weak CBF": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 2,
|
||||
"selector": "X"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 3,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "X",
|
||||
"count": 2,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
]
|
||||
]
|
||||
},
|
||||
"select same, weak CBF": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 2,
|
||||
"selector": "X"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 3,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "X",
|
||||
"count": 2,
|
||||
"clause": "SAME",
|
||||
"attribute": "Attr",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
383
netmap/json_tests/filter_complex.json
Normal file
383
netmap/json_tests/filter_complex.json
Normal file
|
@ -0,0 +1,383 @@
|
|||
{
|
||||
"name": "compound filter",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Storage",
|
||||
"value": "SSD"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "10"
|
||||
},
|
||||
{
|
||||
"key": "IntField",
|
||||
"value": "100"
|
||||
},
|
||||
{
|
||||
"key": "Param",
|
||||
"value": "Value1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"good": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "Storage",
|
||||
"op": "EQ",
|
||||
"value": "SSD",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "",
|
||||
"op": "AND",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "IntField",
|
||||
"op": "LT",
|
||||
"value": "123",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "",
|
||||
"op": "OR",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value1",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value2",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"bad storage type": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "Storage",
|
||||
"op": "EQ",
|
||||
"value": "HDD",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "",
|
||||
"op": "AND",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "IntField",
|
||||
"op": "LT",
|
||||
"value": "123",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "",
|
||||
"op": "OR",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value1",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value2",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"bad rating": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "Storage",
|
||||
"op": "EQ",
|
||||
"value": "SSD",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "15",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "",
|
||||
"op": "AND",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "IntField",
|
||||
"op": "LT",
|
||||
"value": "123",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "",
|
||||
"op": "OR",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value1",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value2",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"bad param": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "Storage",
|
||||
"op": "EQ",
|
||||
"value": "SSD",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "",
|
||||
"op": "AND",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "StorageSSD",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "IntField",
|
||||
"op": "LT",
|
||||
"value": "123",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "GoodRating",
|
||||
"key": "",
|
||||
"op": "OPERATION_UNSPECIFIED",
|
||||
"value": "",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "",
|
||||
"op": "OR",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value0",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "Param",
|
||||
"op": "EQ",
|
||||
"value": "Value2",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
}
|
||||
}
|
||||
}
|
83
netmap/json_tests/filter_invalid_integer.json
Normal file
83
netmap/json_tests/filter_invalid_integer.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"name": "invalid integer field",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "IntegerField",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "IntegerField",
|
||||
"value": "str"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"empty string is not casted to 0": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "IntegerField",
|
||||
"op": "LE",
|
||||
"value": "8",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"non-empty string is not casted to a number": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "IntegerField",
|
||||
"op": "GE",
|
||||
"value": "0",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
}
|
||||
}
|
||||
}
|
403
netmap/json_tests/filter_simple.json
Normal file
403
netmap/json_tests/filter_simple.json
Normal file
|
@ -0,0 +1,403 @@
|
|||
{
|
||||
"name": "single-op filters",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"GE true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"GE false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "GE",
|
||||
"value": "5",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"GT true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "GT",
|
||||
"value": "3",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"GT false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "GT",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"LE true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "LE",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"LE false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "LE",
|
||||
"value": "3",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"LT true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "LT",
|
||||
"value": "5",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"LT false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Rating",
|
||||
"op": "LT",
|
||||
"value": "4",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"EQ true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "Germany",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"EQ false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "China",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
},
|
||||
"NE true": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Country",
|
||||
"op": "NE",
|
||||
"value": "France",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"NE false": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "S"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "S",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "Main"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "Main",
|
||||
"key": "Country",
|
||||
"op": "NE",
|
||||
"value": "Germany",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
}
|
||||
}
|
||||
}
|
165
netmap/json_tests/hrw_sort.json
Normal file
165
netmap/json_tests/hrw_sort.json
Normal file
|
@ -0,0 +1,165 @@
|
|||
{
|
||||
"name": "HRW ordering",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "France"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "France"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "100"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "France"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "7"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "10000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Price",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Capacity",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"select 3 nodes in 3 distinct countries, same placement": {
|
||||
"policy": {"replicas":[{"count":1,"selector":"Main"}],"containerBackupFactor":1,"selectors":[{"name":"Main","count":3,"clause":"DISTINCT","attribute":"Country","filter":"*"}],"filters":[]},
|
||||
"pivot": "Y29udGFpbmVySUQ=",
|
||||
"result": [[0, 2, 3]],
|
||||
"placement": {
|
||||
"pivot": "b2JqZWN0SUQ=",
|
||||
"result": [[0, 2, 3]]
|
||||
}
|
||||
},
|
||||
"select 6 nodes in 3 distinct countries, different placement": {
|
||||
"policy": {"replicas":[{"count":1,"selector":"Main"}],"containerBackupFactor":2,"selectors":[{"name":"Main","count":3,"clause":"DISTINCT","attribute":"Country","filter":"*"}],"filters":[]},
|
||||
"pivot": "Y29udGFpbmVySUQ=",
|
||||
"result": [[0, 1, 2, 6, 3, 4]],
|
||||
"placement": {
|
||||
"pivot": "b2JqZWN0SUQ=",
|
||||
"result": [[0, 1, 2, 6, 3, 4]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
netmap/json_tests/issue213.json
Normal file
108
netmap/json_tests/issue213.json
Normal file
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"name": "unnamed selector (nspcc-dev/neofs-api-go#213)",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Saint-Petersburg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Sweden"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Stockholm"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Location",
|
||||
"value": "Europe"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Finalnd"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Helsinki"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"test": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 4,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "",
|
||||
"count": 4,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "LOC_EU"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "LOC_EU",
|
||||
"key": "Location",
|
||||
"op": "EQ",
|
||||
"value": "Europe",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
192
netmap/json_tests/many_selects.json
Normal file
192
netmap/json_tests/many_selects.json
Normal file
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"name": "single-op filters",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "SPB"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Berlin"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "France"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Paris"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "France"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Lyon"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "SPB"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "7"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Darmstadt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "7"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Frankfurt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "9"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "SPB"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
},
|
||||
{
|
||||
"key": "Rating",
|
||||
"value": "9"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "SPB"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"Select": {
|
||||
"policy": {"replicas":[{"count":1,"selector":"SameRU"},{"count":1,"selector":"DistinctRU"},{"count":1,"selector":"Good"},{"count":1,"selector":"Main"}],"containerBackupFactor":2,"selectors":[{"name":"SameRU","count":2,"clause":"SAME","attribute":"City","filter":"FromRU"},{"name":"DistinctRU","count":2,"clause":"DISTINCT","attribute":"City","filter":"FromRU"},{"name":"Good","count":2,"clause":"DISTINCT","attribute":"Country","filter":"Good"},{"name":"Main","count":3,"clause":"DISTINCT","attribute":"Country","filter":"*"}],"filters":[{"name":"FromRU","key":"Country","op":"EQ","value":"Russia"},{"name":"Good","key":"Rating","op":"GE","value":"4"}]},
|
||||
"result": [
|
||||
[0, 5, 9, 10],
|
||||
[2, 6, 0, 5],
|
||||
[1, 8, 2, 5],
|
||||
[3, 4, 1, 7, 0, 2]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
94
netmap/json_tests/multiple_rep.json
Normal file
94
netmap/json_tests/multiple_rep.json
Normal file
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"name": "multiple replicas (#215)",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Saint-Petersburg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Berlin"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Paris"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"test": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "LOC_SPB_PLACE"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "LOC_MSK_PLACE"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "LOC_SPB_PLACE",
|
||||
"count": 1,
|
||||
"clause": "CLAUSE_UNSPECIFIED",
|
||||
"attribute": "",
|
||||
"filter": "LOC_SPB"
|
||||
},
|
||||
{
|
||||
"name": "LOC_MSK_PLACE",
|
||||
"count": 1,
|
||||
"clause": "CLAUSE_UNSPECIFIED",
|
||||
"attribute": "",
|
||||
"filter": "LOC_MSK"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "LOC_SPB",
|
||||
"key": "City",
|
||||
"op": "EQ",
|
||||
"value": "Saint-Petersburg",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "LOC_MSK",
|
||||
"key": "City",
|
||||
"op": "EQ",
|
||||
"value": "Moscow",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
],
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
331
netmap/json_tests/multiple_rep_asymmetric.json
Normal file
331
netmap/json_tests/multiple_rep_asymmetric.json
Normal file
|
@ -0,0 +1,331 @@
|
|||
{
|
||||
"name": "multiple REP, asymmetric",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "NA"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "NewYork"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "7"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "AF"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Cairo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "8"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "AF"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Cairo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "9"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "SA"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Lima"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "10"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "AF"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Cairo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "11"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "NA"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "NewYork"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "12"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "NA"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "LosAngeles"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "13"
|
||||
},
|
||||
{
|
||||
"key": "Continent",
|
||||
"value": "SA"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Lima"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"test": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "SPB"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"selector": "Americas"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 2,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "SPB",
|
||||
"count": 1,
|
||||
"clause": "SAME",
|
||||
"attribute": "City",
|
||||
"filter": "SPBSSD"
|
||||
},
|
||||
{
|
||||
"name": "Americas",
|
||||
"count": 2,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "City",
|
||||
"filter": "Americas"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "SPBSSD",
|
||||
"key": "",
|
||||
"op": "AND",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "RU",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "City",
|
||||
"op": "EQ",
|
||||
"value": "St.Petersburg",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "SSD",
|
||||
"op": "EQ",
|
||||
"value": "1",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Americas",
|
||||
"key": "",
|
||||
"op": "OR",
|
||||
"value": "",
|
||||
"filters": [
|
||||
{
|
||||
"name": "",
|
||||
"key": "Continent",
|
||||
"op": "EQ",
|
||||
"value": "NA",
|
||||
"filters": []
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"key": "Continent",
|
||||
"op": "EQ",
|
||||
"value": "SA",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
1,
|
||||
4
|
||||
],
|
||||
[
|
||||
8,
|
||||
12,
|
||||
5,
|
||||
10
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
95
netmap/json_tests/non_strict.json
Normal file
95
netmap/json_tests/non_strict.json
Normal file
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"name": "non-strict selections",
|
||||
"comment": "These test specify loose selection behaviour, to allow fetching already PUT objects even when there is not enough nodes to select from.",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [ ]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"not enough nodes (backup factor)": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "MyStore"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 2,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "MyStore",
|
||||
"count": 2,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "Country",
|
||||
"filter": "FromRU"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "FromRU",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "Russia",
|
||||
"filters": [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
"not enough nodes (buckets)": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "MyStore"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "MyStore",
|
||||
"count": 2,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "Country",
|
||||
"filter": "FromRU"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "FromRU",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "Russia",
|
||||
"filters": [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
117
netmap/json_tests/rep_only.json
Normal file
117
netmap/json_tests/rep_only.json
Normal file
|
@ -0,0 +1,117 @@
|
|||
{
|
||||
"name": "REP X",
|
||||
"nodes": [
|
||||
{
|
||||
"publicKey": "",
|
||||
"addresses": [],
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Saint-Petersburg",
|
||||
"parents": []
|
||||
}
|
||||
],
|
||||
"state": "UNSPECIFIED"
|
||||
},
|
||||
{
|
||||
"publicKey": "",
|
||||
"addresses": [],
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow",
|
||||
"parents": []
|
||||
}
|
||||
],
|
||||
"state": "UNSPECIFIED"
|
||||
},
|
||||
{
|
||||
"publicKey": "",
|
||||
"addresses": [],
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Berlin",
|
||||
"parents": []
|
||||
}
|
||||
],
|
||||
"state": "UNSPECIFIED"
|
||||
},
|
||||
{
|
||||
"publicKey": "",
|
||||
"addresses": [],
|
||||
"attributes": [
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Paris",
|
||||
"parents": []
|
||||
}
|
||||
],
|
||||
"state": "UNSPECIFIED"
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"REP 1": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 0,
|
||||
"selectors": [],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
},
|
||||
"REP 3": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 3,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 0,
|
||||
"selectors": [],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
},
|
||||
"REP 5": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 5,
|
||||
"selector": ""
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 0,
|
||||
"selectors": [],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
116
netmap/json_tests/select_no_attribute.json
Normal file
116
netmap/json_tests/select_no_attribute.json
Normal file
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"name": "select with unspecified attribute",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "St.Petersburg"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "ID",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "RU"
|
||||
},
|
||||
{
|
||||
"key": "City",
|
||||
"value": "Moscow"
|
||||
},
|
||||
{
|
||||
"key": "SSD",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"test": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "X"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "X",
|
||||
"count": 4,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "",
|
||||
"filter": "*"
|
||||
}
|
||||
],
|
||||
"filters": []
|
||||
},
|
||||
"result": [
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
86
netmap/json_tests/selector_invalid.json
Normal file
86
netmap/json_tests/selector_invalid.json
Normal file
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"name": "invalid selections",
|
||||
"nodes": [
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Russia"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": [
|
||||
{
|
||||
"key": "Country",
|
||||
"value": "Germany"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attributes": []
|
||||
}
|
||||
],
|
||||
"tests": {
|
||||
"missing filter": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "MyStore"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 1,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "MyStore",
|
||||
"count": 1,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "Country",
|
||||
"filter": "FromNL"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "FromRU",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "Russia",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "filter not found"
|
||||
},
|
||||
"not enough nodes (filter results in empty set)": {
|
||||
"policy": {
|
||||
"replicas": [
|
||||
{
|
||||
"count": 1,
|
||||
"selector": "MyStore"
|
||||
}
|
||||
],
|
||||
"containerBackupFactor": 2,
|
||||
"selectors": [
|
||||
{
|
||||
"name": "MyStore",
|
||||
"count": 2,
|
||||
"clause": "DISTINCT",
|
||||
"attribute": "Country",
|
||||
"filter": "FromMoon"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "FromMoon",
|
||||
"key": "Country",
|
||||
"op": "EQ",
|
||||
"value": "Moon",
|
||||
"filters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": "not enough nodes"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -113,10 +113,9 @@ func (n nodes) Hash() uint64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (n nodes) appendWeightsTo(wf weightFunc, w []float64) []float64 {
|
||||
if cap(w) < len(n) {
|
||||
w = make([]float64, 0, len(n))
|
||||
}
|
||||
// weights returns slice of nodes weights W.
|
||||
func (n nodes) weights(wf weightFunc) []float64 {
|
||||
w := make([]float64, 0, len(n))
|
||||
for i := range n {
|
||||
w = append(w, wf(n[i]))
|
||||
}
|
||||
|
@ -150,13 +149,10 @@ func (m NetMap) PlacementVectors(vectors [][]NodeInfo, pivot []byte) ([][]NodeIn
|
|||
wf := defaultWeightFunc(m.nodes)
|
||||
result := make([][]NodeInfo, len(vectors))
|
||||
|
||||
var ws []float64
|
||||
|
||||
for i := range vectors {
|
||||
result[i] = make([]NodeInfo, len(vectors[i]))
|
||||
copy(result[i], vectors[i])
|
||||
ws = nodes(result[i]).appendWeightsTo(wf, ws[:0])
|
||||
hrw.SortHasherSliceByWeightValue(result[i], ws, h)
|
||||
hrw.SortHasherSliceByWeightValue(result[i], nodes(result[i]).weights(wf), h)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
@ -213,25 +209,6 @@ func (m NetMap) SelectFilterNodes(expr *SelectFilterExpr) ([][]NodeInfo, error)
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func countNodes(r netmap.Replica) uint32 {
|
||||
if r.GetCount() != 0 {
|
||||
return r.GetCount()
|
||||
}
|
||||
return r.GetECDataCount() + r.GetECParityCount()
|
||||
}
|
||||
|
||||
func (p PlacementPolicy) isUnique() bool {
|
||||
if p.unique {
|
||||
return true
|
||||
}
|
||||
for _, r := range p.replicas {
|
||||
if r.GetECDataCount() != 0 || r.GetECParityCount() != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainerNodes returns two-dimensional list of nodes as a result of applying
|
||||
// given PlacementPolicy to the NetMap. Each line of the list corresponds to a
|
||||
// replica descriptor. Line order corresponds to order of ReplicaDescriptor list
|
||||
|
@ -253,7 +230,6 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, pivot []byte) ([][]NodeInfo, e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
unique := p.isUnique()
|
||||
result := make([][]NodeInfo, len(p.replicas))
|
||||
|
||||
// Note that the cached selectors are not used when the policy contains the UNIQUE flag.
|
||||
|
@ -264,7 +240,7 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, pivot []byte) ([][]NodeInfo, e
|
|||
sName := p.replicas[i].GetSelector()
|
||||
if sName == "" && !(len(p.replicas) == 1 && len(p.selectors) == 1) {
|
||||
var s netmap.Selector
|
||||
s.SetCount(countNodes(p.replicas[i]))
|
||||
s.SetCount(p.replicas[i].GetCount())
|
||||
s.SetFilter(mainFilterName)
|
||||
|
||||
nodes, err := c.getSelection(s)
|
||||
|
@ -274,14 +250,14 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, pivot []byte) ([][]NodeInfo, e
|
|||
|
||||
result[i] = append(result[i], flattenNodes(nodes)...)
|
||||
|
||||
if unique {
|
||||
if p.unique {
|
||||
c.addUsedNodes(result[i]...)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if unique {
|
||||
if p.unique {
|
||||
if c.processedSelectors[sName] == nil {
|
||||
return nil, fmt.Errorf("selector not found: '%s'", sName)
|
||||
}
|
||||
|
|
|
@ -49,6 +49,11 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool)
|
|||
mNames[name] = struct{}{}
|
||||
|
||||
switch name {
|
||||
default:
|
||||
if len(prm.GetValue()) == 0 {
|
||||
err = fmt.Errorf("empty attribute value %s", name)
|
||||
return true
|
||||
}
|
||||
case
|
||||
configAuditFee,
|
||||
configStoragePrice,
|
||||
|
@ -57,8 +62,6 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool)
|
|||
configEpochDuration,
|
||||
configIRCandidateFee,
|
||||
configMaxObjSize,
|
||||
configMaxECDataCount,
|
||||
configMaxECParityCount,
|
||||
configWithdrawalFee:
|
||||
_, err = decodeConfigValueUint64(prm.GetValue())
|
||||
case configHomomorphicHashingDisabled,
|
||||
|
@ -231,8 +234,6 @@ func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []by
|
|||
configEpochDuration,
|
||||
configIRCandidateFee,
|
||||
configMaxObjSize,
|
||||
configMaxECDataCount,
|
||||
configMaxECParityCount,
|
||||
configWithdrawalFee,
|
||||
configHomomorphicHashingDisabled,
|
||||
configMaintenanceModeAllowed:
|
||||
|
@ -431,34 +432,6 @@ func (x NetworkInfo) MaxObjectSize() uint64 {
|
|||
return x.configUint64(configMaxObjSize)
|
||||
}
|
||||
|
||||
const configMaxECDataCount = "MaxECDataCount"
|
||||
|
||||
// SetMaxECDataCount sets maximum number of data shards for erasure codes.
|
||||
//
|
||||
// Zero means no restrictions.
|
||||
func (x *NetworkInfo) SetMaxECDataCount(dataCount uint64) {
|
||||
x.setConfigUint64(configMaxECDataCount, dataCount)
|
||||
}
|
||||
|
||||
// MaxECDataCount returns maximum number of data shards for erasure codes.
|
||||
func (x NetworkInfo) MaxECDataCount() uint64 {
|
||||
return x.configUint64(configMaxECDataCount)
|
||||
}
|
||||
|
||||
const configMaxECParityCount = "MaxECParityCount"
|
||||
|
||||
// SetMaxECParityCount sets maximum number of parity shards for erasure codes.
|
||||
//
|
||||
// Zero means no restrictions.
|
||||
func (x *NetworkInfo) SetMaxECParityCount(parityCount uint64) {
|
||||
x.setConfigUint64(configMaxECParityCount, parityCount)
|
||||
}
|
||||
|
||||
// MaxECParityCount returns maximum number of parity shards for erasure codes.
|
||||
func (x NetworkInfo) MaxECParityCount() uint64 {
|
||||
return x.configUint64(configMaxECParityCount)
|
||||
}
|
||||
|
||||
const configWithdrawalFee = "WithdrawFee"
|
||||
|
||||
// SetWithdrawalFee sets fee for withdrawals from the FrostFS accounts that
|
||||
|
|
|
@ -173,32 +173,6 @@ func TestNetworkInfo_MaxObjectSize(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
func TestNetworkInfo_MaxECDataCount(t *testing.T) {
|
||||
testConfigValue(t,
|
||||
func(x NetworkInfo) any { return x.MaxECDataCount() },
|
||||
func(info *NetworkInfo, val any) { info.SetMaxECDataCount(val.(uint64)) },
|
||||
uint64(1), uint64(2),
|
||||
"MaxECDataCount", func(val any) []byte {
|
||||
data := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(data, val.(uint64))
|
||||
return data
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestNetworkInfo_MaxECParityCount(t *testing.T) {
|
||||
testConfigValue(t,
|
||||
func(x NetworkInfo) any { return x.MaxECParityCount() },
|
||||
func(info *NetworkInfo, val any) { info.SetMaxECParityCount(val.(uint64)) },
|
||||
uint64(1), uint64(2),
|
||||
"MaxECParityCount", func(val any) []byte {
|
||||
data := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(data, val.(uint64))
|
||||
return data
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestNetworkInfo_WithdrawalFee(t *testing.T) {
|
||||
testConfigValue(t,
|
||||
func(x NetworkInfo) any { return x.WithdrawalFee() },
|
||||
|
|
|
@ -3,7 +3,7 @@ package netmap
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -227,6 +227,14 @@ func (x NodeInfo) Hash() uint64 {
|
|||
return hrw.Hash(x.m.GetPublicKey())
|
||||
}
|
||||
|
||||
// less declares "less than" comparison between two NodeInfo instances:
|
||||
// x1 is less than x2 if it has less Hash().
|
||||
//
|
||||
// Method is needed for internal placement needs.
|
||||
func less(x1, x2 NodeInfo) bool {
|
||||
return x1.Hash() < x2.Hash()
|
||||
}
|
||||
|
||||
func (x *NodeInfo) setNumericAttribute(key string, num uint64) {
|
||||
x.SetAttribute(key, strconv.FormatUint(num, 10))
|
||||
}
|
||||
|
@ -447,11 +455,15 @@ func (x *NodeInfo) SortAttributes() {
|
|||
return
|
||||
}
|
||||
|
||||
slices.SortFunc(as, func(ai, aj netmap.Attribute) int {
|
||||
if r := strings.Compare(ai.GetKey(), aj.GetKey()); r != 0 {
|
||||
return r
|
||||
sort.Slice(as, func(i, j int) bool {
|
||||
switch strings.Compare(as[i].GetKey(), as[j].GetKey()) {
|
||||
case -1:
|
||||
return true
|
||||
case 1:
|
||||
return false
|
||||
default:
|
||||
return as[i].GetValue() < as[j].GetValue()
|
||||
}
|
||||
return strings.Compare(ai.GetValue(), aj.GetValue())
|
||||
})
|
||||
|
||||
x.m.SetAttributes(as)
|
||||
|
|
|
@ -4,14 +4,10 @@ options {
|
|||
tokenVocab = QueryLexer;
|
||||
}
|
||||
|
||||
policy: UNIQUE? (repStmt | ecStmt)+ cbfStmt? selectStmt* filterStmt* EOF;
|
||||
policy: UNIQUE? repStmt+ cbfStmt? selectStmt* filterStmt* EOF;
|
||||
|
||||
selectFilterExpr: cbfStmt? selectStmt? filterStmt* EOF;
|
||||
|
||||
ecStmt:
|
||||
EC Data = NUMBER1 DOT Parity = NUMBER1 // erasure code configuration
|
||||
(IN Selector = ident)?; // optional selector name
|
||||
|
||||
repStmt:
|
||||
REP Count = NUMBER1 // number of object replicas
|
||||
(IN Selector = ident)?; // optional selector name
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -7,7 +7,6 @@ SIMPLE_OP : 'EQ' | 'NE' | 'GE' | 'GT' | 'LT' | 'LE';
|
|||
|
||||
UNIQUE : 'UNIQUE';
|
||||
REP : 'REP';
|
||||
EC : 'EC';
|
||||
IN : 'IN';
|
||||
AS : 'AS';
|
||||
CBF : 'CBF';
|
||||
|
@ -15,7 +14,6 @@ SELECT : 'SELECT';
|
|||
FROM : 'FROM';
|
||||
FILTER : 'FILTER';
|
||||
WILDCARD : '*';
|
||||
DOT : '.';
|
||||
|
||||
CLAUSE_SAME : 'SAME';
|
||||
CLAUSE_DISTINCT : 'DISTINCT';
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
// Code generated from /repo/frostfs/sdk-go/netmap/parser/Query.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
// Code generated from Query.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser // Query
|
||||
|
||||
|
@ -16,10 +16,6 @@ func (v *BaseQueryVisitor) VisitSelectFilterExpr(ctx *SelectFilterExprContext) i
|
|||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseQueryVisitor) VisitEcStmt(ctx *EcStmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseQueryVisitor) VisitRepStmt(ctx *RepStmtContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Code generated from /repo/frostfs/sdk-go/netmap/parser/QueryLexer.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
// Code generated from QueryLexer.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser
|
||||
|
||||
|
@ -43,123 +43,119 @@ func querylexerLexerInit() {
|
|||
"DEFAULT_MODE",
|
||||
}
|
||||
staticData.LiteralNames = []string{
|
||||
"", "'NOT'", "'AND'", "'OR'", "", "'UNIQUE'", "'REP'", "'EC'", "'IN'",
|
||||
"'AS'", "'CBF'", "'SELECT'", "'FROM'", "'FILTER'", "'*'", "'.'", "'SAME'",
|
||||
"'DISTINCT'", "'('", "')'", "'@'", "", "", "'0'",
|
||||
"", "'NOT'", "'AND'", "'OR'", "", "'UNIQUE'", "'REP'", "'IN'", "'AS'",
|
||||
"'CBF'", "'SELECT'", "'FROM'", "'FILTER'", "'*'", "'SAME'", "'DISTINCT'",
|
||||
"'('", "')'", "'@'", "", "", "'0'",
|
||||
}
|
||||
staticData.SymbolicNames = []string{
|
||||
"", "NOT_OP", "AND_OP", "OR_OP", "SIMPLE_OP", "UNIQUE", "REP", "EC",
|
||||
"IN", "AS", "CBF", "SELECT", "FROM", "FILTER", "WILDCARD", "DOT", "CLAUSE_SAME",
|
||||
"", "NOT_OP", "AND_OP", "OR_OP", "SIMPLE_OP", "UNIQUE", "REP", "IN",
|
||||
"AS", "CBF", "SELECT", "FROM", "FILTER", "WILDCARD", "CLAUSE_SAME",
|
||||
"CLAUSE_DISTINCT", "L_PAREN", "R_PAREN", "AT", "IDENT", "NUMBER1", "ZERO",
|
||||
"STRING", "WS",
|
||||
}
|
||||
staticData.RuleNames = []string{
|
||||
"NOT_OP", "AND_OP", "OR_OP", "SIMPLE_OP", "UNIQUE", "REP", "EC", "IN",
|
||||
"AS", "CBF", "SELECT", "FROM", "FILTER", "WILDCARD", "DOT", "CLAUSE_SAME",
|
||||
"CLAUSE_DISTINCT", "L_PAREN", "R_PAREN", "AT", "IDENT", "Digit", "Nondigit",
|
||||
"NUMBER1", "ZERO", "STRING", "ESC", "UNICODE", "HEX", "SAFECODEPOINTSINGLE",
|
||||
"SAFECODEPOINTDOUBLE", "WS",
|
||||
"NOT_OP", "AND_OP", "OR_OP", "SIMPLE_OP", "UNIQUE", "REP", "IN", "AS",
|
||||
"CBF", "SELECT", "FROM", "FILTER", "WILDCARD", "CLAUSE_SAME", "CLAUSE_DISTINCT",
|
||||
"L_PAREN", "R_PAREN", "AT", "IDENT", "Digit", "Nondigit", "NUMBER1",
|
||||
"ZERO", "STRING", "ESC", "UNICODE", "HEX", "SAFECODEPOINTSINGLE", "SAFECODEPOINTDOUBLE",
|
||||
"WS",
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 0, 25, 222, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
|
||||
4, 0, 23, 213, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
|
||||
4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2,
|
||||
10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15,
|
||||
7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7,
|
||||
20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25,
|
||||
2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2,
|
||||
31, 7, 31, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2,
|
||||
1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 3, 3, 89, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1,
|
||||
5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1,
|
||||
9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1,
|
||||
11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12,
|
||||
1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1,
|
||||
16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17,
|
||||
1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 161, 8, 20, 10,
|
||||
20, 12, 20, 164, 9, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 5, 23,
|
||||
172, 8, 23, 10, 23, 12, 23, 175, 9, 23, 1, 24, 1, 24, 1, 25, 1, 25, 1,
|
||||
25, 5, 25, 182, 8, 25, 10, 25, 12, 25, 185, 9, 25, 1, 25, 1, 25, 1, 25,
|
||||
1, 25, 5, 25, 191, 8, 25, 10, 25, 12, 25, 194, 9, 25, 1, 25, 3, 25, 197,
|
||||
8, 25, 1, 26, 1, 26, 1, 26, 3, 26, 202, 8, 26, 1, 27, 1, 27, 1, 27, 1,
|
||||
27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 4, 31,
|
||||
217, 8, 31, 11, 31, 12, 31, 218, 1, 31, 1, 31, 0, 0, 32, 1, 1, 3, 2, 5,
|
||||
3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25,
|
||||
13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43,
|
||||
0, 45, 0, 47, 22, 49, 23, 51, 24, 53, 0, 55, 0, 57, 0, 59, 0, 61, 0, 63,
|
||||
25, 1, 0, 8, 1, 0, 48, 57, 3, 0, 65, 90, 95, 95, 97, 122, 1, 0, 49, 57,
|
||||
9, 0, 34, 34, 39, 39, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114,
|
||||
114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 0, 31, 39, 39, 92,
|
||||
92, 3, 0, 0, 31, 34, 34, 92, 92, 3, 0, 9, 10, 13, 13, 32, 32, 229, 0, 1,
|
||||
1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9,
|
||||
1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0,
|
||||
17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0,
|
||||
0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0,
|
||||
0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0,
|
||||
0, 0, 0, 41, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1,
|
||||
0, 0, 0, 0, 63, 1, 0, 0, 0, 1, 65, 1, 0, 0, 0, 3, 69, 1, 0, 0, 0, 5, 73,
|
||||
1, 0, 0, 0, 7, 88, 1, 0, 0, 0, 9, 90, 1, 0, 0, 0, 11, 97, 1, 0, 0, 0, 13,
|
||||
101, 1, 0, 0, 0, 15, 104, 1, 0, 0, 0, 17, 107, 1, 0, 0, 0, 19, 110, 1,
|
||||
0, 0, 0, 21, 114, 1, 0, 0, 0, 23, 121, 1, 0, 0, 0, 25, 126, 1, 0, 0, 0,
|
||||
27, 133, 1, 0, 0, 0, 29, 135, 1, 0, 0, 0, 31, 137, 1, 0, 0, 0, 33, 142,
|
||||
1, 0, 0, 0, 35, 151, 1, 0, 0, 0, 37, 153, 1, 0, 0, 0, 39, 155, 1, 0, 0,
|
||||
0, 41, 157, 1, 0, 0, 0, 43, 165, 1, 0, 0, 0, 45, 167, 1, 0, 0, 0, 47, 169,
|
||||
1, 0, 0, 0, 49, 176, 1, 0, 0, 0, 51, 196, 1, 0, 0, 0, 53, 198, 1, 0, 0,
|
||||
0, 55, 203, 1, 0, 0, 0, 57, 209, 1, 0, 0, 0, 59, 211, 1, 0, 0, 0, 61, 213,
|
||||
1, 0, 0, 0, 63, 216, 1, 0, 0, 0, 65, 66, 5, 78, 0, 0, 66, 67, 5, 79, 0,
|
||||
0, 67, 68, 5, 84, 0, 0, 68, 2, 1, 0, 0, 0, 69, 70, 5, 65, 0, 0, 70, 71,
|
||||
5, 78, 0, 0, 71, 72, 5, 68, 0, 0, 72, 4, 1, 0, 0, 0, 73, 74, 5, 79, 0,
|
||||
0, 74, 75, 5, 82, 0, 0, 75, 6, 1, 0, 0, 0, 76, 77, 5, 69, 0, 0, 77, 89,
|
||||
5, 81, 0, 0, 78, 79, 5, 78, 0, 0, 79, 89, 5, 69, 0, 0, 80, 81, 5, 71, 0,
|
||||
0, 81, 89, 5, 69, 0, 0, 82, 83, 5, 71, 0, 0, 83, 89, 5, 84, 0, 0, 84, 85,
|
||||
5, 76, 0, 0, 85, 89, 5, 84, 0, 0, 86, 87, 5, 76, 0, 0, 87, 89, 5, 69, 0,
|
||||
0, 88, 76, 1, 0, 0, 0, 88, 78, 1, 0, 0, 0, 88, 80, 1, 0, 0, 0, 88, 82,
|
||||
1, 0, 0, 0, 88, 84, 1, 0, 0, 0, 88, 86, 1, 0, 0, 0, 89, 8, 1, 0, 0, 0,
|
||||
90, 91, 5, 85, 0, 0, 91, 92, 5, 78, 0, 0, 92, 93, 5, 73, 0, 0, 93, 94,
|
||||
5, 81, 0, 0, 94, 95, 5, 85, 0, 0, 95, 96, 5, 69, 0, 0, 96, 10, 1, 0, 0,
|
||||
0, 97, 98, 5, 82, 0, 0, 98, 99, 5, 69, 0, 0, 99, 100, 5, 80, 0, 0, 100,
|
||||
12, 1, 0, 0, 0, 101, 102, 5, 69, 0, 0, 102, 103, 5, 67, 0, 0, 103, 14,
|
||||
1, 0, 0, 0, 104, 105, 5, 73, 0, 0, 105, 106, 5, 78, 0, 0, 106, 16, 1, 0,
|
||||
0, 0, 107, 108, 5, 65, 0, 0, 108, 109, 5, 83, 0, 0, 109, 18, 1, 0, 0, 0,
|
||||
110, 111, 5, 67, 0, 0, 111, 112, 5, 66, 0, 0, 112, 113, 5, 70, 0, 0, 113,
|
||||
20, 1, 0, 0, 0, 114, 115, 5, 83, 0, 0, 115, 116, 5, 69, 0, 0, 116, 117,
|
||||
5, 76, 0, 0, 117, 118, 5, 69, 0, 0, 118, 119, 5, 67, 0, 0, 119, 120, 5,
|
||||
84, 0, 0, 120, 22, 1, 0, 0, 0, 121, 122, 5, 70, 0, 0, 122, 123, 5, 82,
|
||||
0, 0, 123, 124, 5, 79, 0, 0, 124, 125, 5, 77, 0, 0, 125, 24, 1, 0, 0, 0,
|
||||
126, 127, 5, 70, 0, 0, 127, 128, 5, 73, 0, 0, 128, 129, 5, 76, 0, 0, 129,
|
||||
130, 5, 84, 0, 0, 130, 131, 5, 69, 0, 0, 131, 132, 5, 82, 0, 0, 132, 26,
|
||||
1, 0, 0, 0, 133, 134, 5, 42, 0, 0, 134, 28, 1, 0, 0, 0, 135, 136, 5, 46,
|
||||
0, 0, 136, 30, 1, 0, 0, 0, 137, 138, 5, 83, 0, 0, 138, 139, 5, 65, 0, 0,
|
||||
139, 140, 5, 77, 0, 0, 140, 141, 5, 69, 0, 0, 141, 32, 1, 0, 0, 0, 142,
|
||||
143, 5, 68, 0, 0, 143, 144, 5, 73, 0, 0, 144, 145, 5, 83, 0, 0, 145, 146,
|
||||
5, 84, 0, 0, 146, 147, 5, 73, 0, 0, 147, 148, 5, 78, 0, 0, 148, 149, 5,
|
||||
67, 0, 0, 149, 150, 5, 84, 0, 0, 150, 34, 1, 0, 0, 0, 151, 152, 5, 40,
|
||||
0, 0, 152, 36, 1, 0, 0, 0, 153, 154, 5, 41, 0, 0, 154, 38, 1, 0, 0, 0,
|
||||
155, 156, 5, 64, 0, 0, 156, 40, 1, 0, 0, 0, 157, 162, 3, 45, 22, 0, 158,
|
||||
161, 3, 43, 21, 0, 159, 161, 3, 45, 22, 0, 160, 158, 1, 0, 0, 0, 160, 159,
|
||||
1, 0, 0, 0, 161, 164, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 162, 163, 1, 0,
|
||||
0, 0, 163, 42, 1, 0, 0, 0, 164, 162, 1, 0, 0, 0, 165, 166, 7, 0, 0, 0,
|
||||
166, 44, 1, 0, 0, 0, 167, 168, 7, 1, 0, 0, 168, 46, 1, 0, 0, 0, 169, 173,
|
||||
7, 2, 0, 0, 170, 172, 3, 43, 21, 0, 171, 170, 1, 0, 0, 0, 172, 175, 1,
|
||||
0, 0, 0, 173, 171, 1, 0, 0, 0, 173, 174, 1, 0, 0, 0, 174, 48, 1, 0, 0,
|
||||
0, 175, 173, 1, 0, 0, 0, 176, 177, 5, 48, 0, 0, 177, 50, 1, 0, 0, 0, 178,
|
||||
183, 5, 34, 0, 0, 179, 182, 3, 53, 26, 0, 180, 182, 3, 61, 30, 0, 181,
|
||||
179, 1, 0, 0, 0, 181, 180, 1, 0, 0, 0, 182, 185, 1, 0, 0, 0, 183, 181,
|
||||
1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 183, 1, 0,
|
||||
0, 0, 186, 197, 5, 34, 0, 0, 187, 192, 5, 39, 0, 0, 188, 191, 3, 53, 26,
|
||||
0, 189, 191, 3, 59, 29, 0, 190, 188, 1, 0, 0, 0, 190, 189, 1, 0, 0, 0,
|
||||
191, 194, 1, 0, 0, 0, 192, 190, 1, 0, 0, 0, 192, 193, 1, 0, 0, 0, 193,
|
||||
195, 1, 0, 0, 0, 194, 192, 1, 0, 0, 0, 195, 197, 5, 39, 0, 0, 196, 178,
|
||||
1, 0, 0, 0, 196, 187, 1, 0, 0, 0, 197, 52, 1, 0, 0, 0, 198, 201, 5, 92,
|
||||
0, 0, 199, 202, 7, 3, 0, 0, 200, 202, 3, 55, 27, 0, 201, 199, 1, 0, 0,
|
||||
0, 201, 200, 1, 0, 0, 0, 202, 54, 1, 0, 0, 0, 203, 204, 5, 117, 0, 0, 204,
|
||||
205, 3, 57, 28, 0, 205, 206, 3, 57, 28, 0, 206, 207, 3, 57, 28, 0, 207,
|
||||
208, 3, 57, 28, 0, 208, 56, 1, 0, 0, 0, 209, 210, 7, 4, 0, 0, 210, 58,
|
||||
1, 0, 0, 0, 211, 212, 8, 5, 0, 0, 212, 60, 1, 0, 0, 0, 213, 214, 8, 6,
|
||||
0, 0, 214, 62, 1, 0, 0, 0, 215, 217, 7, 7, 0, 0, 216, 215, 1, 0, 0, 0,
|
||||
217, 218, 1, 0, 0, 0, 218, 216, 1, 0, 0, 0, 218, 219, 1, 0, 0, 0, 219,
|
||||
220, 1, 0, 0, 0, 220, 221, 6, 31, 0, 0, 221, 64, 1, 0, 0, 0, 12, 0, 88,
|
||||
160, 162, 173, 181, 183, 190, 192, 196, 201, 218, 1, 6, 0, 0,
|
||||
2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1,
|
||||
3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 85, 8, 3, 1, 4,
|
||||
1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6,
|
||||
1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9,
|
||||
1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11,
|
||||
1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1,
|
||||
13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15,
|
||||
1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 5, 18, 152, 8,
|
||||
18, 10, 18, 12, 18, 155, 9, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21,
|
||||
5, 21, 163, 8, 21, 10, 21, 12, 21, 166, 9, 21, 1, 22, 1, 22, 1, 23, 1,
|
||||
23, 1, 23, 5, 23, 173, 8, 23, 10, 23, 12, 23, 176, 9, 23, 1, 23, 1, 23,
|
||||
1, 23, 1, 23, 5, 23, 182, 8, 23, 10, 23, 12, 23, 185, 9, 23, 1, 23, 3,
|
||||
23, 188, 8, 23, 1, 24, 1, 24, 1, 24, 3, 24, 193, 8, 24, 1, 25, 1, 25, 1,
|
||||
25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29,
|
||||
4, 29, 208, 8, 29, 11, 29, 12, 29, 209, 1, 29, 1, 29, 0, 0, 30, 1, 1, 3,
|
||||
2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12,
|
||||
25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 0, 41, 0, 43,
|
||||
20, 45, 21, 47, 22, 49, 0, 51, 0, 53, 0, 55, 0, 57, 0, 59, 23, 1, 0, 8,
|
||||
1, 0, 48, 57, 3, 0, 65, 90, 95, 95, 97, 122, 1, 0, 49, 57, 9, 0, 34, 34,
|
||||
39, 39, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116,
|
||||
3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 0, 31, 39, 39, 92, 92, 3, 0, 0, 31,
|
||||
34, 34, 92, 92, 3, 0, 9, 10, 13, 13, 32, 32, 220, 0, 1, 1, 0, 0, 0, 0,
|
||||
3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0,
|
||||
11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0,
|
||||
0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0,
|
||||
0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0,
|
||||
0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1,
|
||||
0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 1, 61, 1, 0, 0, 0, 3, 65,
|
||||
1, 0, 0, 0, 5, 69, 1, 0, 0, 0, 7, 84, 1, 0, 0, 0, 9, 86, 1, 0, 0, 0, 11,
|
||||
93, 1, 0, 0, 0, 13, 97, 1, 0, 0, 0, 15, 100, 1, 0, 0, 0, 17, 103, 1, 0,
|
||||
0, 0, 19, 107, 1, 0, 0, 0, 21, 114, 1, 0, 0, 0, 23, 119, 1, 0, 0, 0, 25,
|
||||
126, 1, 0, 0, 0, 27, 128, 1, 0, 0, 0, 29, 133, 1, 0, 0, 0, 31, 142, 1,
|
||||
0, 0, 0, 33, 144, 1, 0, 0, 0, 35, 146, 1, 0, 0, 0, 37, 148, 1, 0, 0, 0,
|
||||
39, 156, 1, 0, 0, 0, 41, 158, 1, 0, 0, 0, 43, 160, 1, 0, 0, 0, 45, 167,
|
||||
1, 0, 0, 0, 47, 187, 1, 0, 0, 0, 49, 189, 1, 0, 0, 0, 51, 194, 1, 0, 0,
|
||||
0, 53, 200, 1, 0, 0, 0, 55, 202, 1, 0, 0, 0, 57, 204, 1, 0, 0, 0, 59, 207,
|
||||
1, 0, 0, 0, 61, 62, 5, 78, 0, 0, 62, 63, 5, 79, 0, 0, 63, 64, 5, 84, 0,
|
||||
0, 64, 2, 1, 0, 0, 0, 65, 66, 5, 65, 0, 0, 66, 67, 5, 78, 0, 0, 67, 68,
|
||||
5, 68, 0, 0, 68, 4, 1, 0, 0, 0, 69, 70, 5, 79, 0, 0, 70, 71, 5, 82, 0,
|
||||
0, 71, 6, 1, 0, 0, 0, 72, 73, 5, 69, 0, 0, 73, 85, 5, 81, 0, 0, 74, 75,
|
||||
5, 78, 0, 0, 75, 85, 5, 69, 0, 0, 76, 77, 5, 71, 0, 0, 77, 85, 5, 69, 0,
|
||||
0, 78, 79, 5, 71, 0, 0, 79, 85, 5, 84, 0, 0, 80, 81, 5, 76, 0, 0, 81, 85,
|
||||
5, 84, 0, 0, 82, 83, 5, 76, 0, 0, 83, 85, 5, 69, 0, 0, 84, 72, 1, 0, 0,
|
||||
0, 84, 74, 1, 0, 0, 0, 84, 76, 1, 0, 0, 0, 84, 78, 1, 0, 0, 0, 84, 80,
|
||||
1, 0, 0, 0, 84, 82, 1, 0, 0, 0, 85, 8, 1, 0, 0, 0, 86, 87, 5, 85, 0, 0,
|
||||
87, 88, 5, 78, 0, 0, 88, 89, 5, 73, 0, 0, 89, 90, 5, 81, 0, 0, 90, 91,
|
||||
5, 85, 0, 0, 91, 92, 5, 69, 0, 0, 92, 10, 1, 0, 0, 0, 93, 94, 5, 82, 0,
|
||||
0, 94, 95, 5, 69, 0, 0, 95, 96, 5, 80, 0, 0, 96, 12, 1, 0, 0, 0, 97, 98,
|
||||
5, 73, 0, 0, 98, 99, 5, 78, 0, 0, 99, 14, 1, 0, 0, 0, 100, 101, 5, 65,
|
||||
0, 0, 101, 102, 5, 83, 0, 0, 102, 16, 1, 0, 0, 0, 103, 104, 5, 67, 0, 0,
|
||||
104, 105, 5, 66, 0, 0, 105, 106, 5, 70, 0, 0, 106, 18, 1, 0, 0, 0, 107,
|
||||
108, 5, 83, 0, 0, 108, 109, 5, 69, 0, 0, 109, 110, 5, 76, 0, 0, 110, 111,
|
||||
5, 69, 0, 0, 111, 112, 5, 67, 0, 0, 112, 113, 5, 84, 0, 0, 113, 20, 1,
|
||||
0, 0, 0, 114, 115, 5, 70, 0, 0, 115, 116, 5, 82, 0, 0, 116, 117, 5, 79,
|
||||
0, 0, 117, 118, 5, 77, 0, 0, 118, 22, 1, 0, 0, 0, 119, 120, 5, 70, 0, 0,
|
||||
120, 121, 5, 73, 0, 0, 121, 122, 5, 76, 0, 0, 122, 123, 5, 84, 0, 0, 123,
|
||||
124, 5, 69, 0, 0, 124, 125, 5, 82, 0, 0, 125, 24, 1, 0, 0, 0, 126, 127,
|
||||
5, 42, 0, 0, 127, 26, 1, 0, 0, 0, 128, 129, 5, 83, 0, 0, 129, 130, 5, 65,
|
||||
0, 0, 130, 131, 5, 77, 0, 0, 131, 132, 5, 69, 0, 0, 132, 28, 1, 0, 0, 0,
|
||||
133, 134, 5, 68, 0, 0, 134, 135, 5, 73, 0, 0, 135, 136, 5, 83, 0, 0, 136,
|
||||
137, 5, 84, 0, 0, 137, 138, 5, 73, 0, 0, 138, 139, 5, 78, 0, 0, 139, 140,
|
||||
5, 67, 0, 0, 140, 141, 5, 84, 0, 0, 141, 30, 1, 0, 0, 0, 142, 143, 5, 40,
|
||||
0, 0, 143, 32, 1, 0, 0, 0, 144, 145, 5, 41, 0, 0, 145, 34, 1, 0, 0, 0,
|
||||
146, 147, 5, 64, 0, 0, 147, 36, 1, 0, 0, 0, 148, 153, 3, 41, 20, 0, 149,
|
||||
152, 3, 39, 19, 0, 150, 152, 3, 41, 20, 0, 151, 149, 1, 0, 0, 0, 151, 150,
|
||||
1, 0, 0, 0, 152, 155, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 153, 154, 1, 0,
|
||||
0, 0, 154, 38, 1, 0, 0, 0, 155, 153, 1, 0, 0, 0, 156, 157, 7, 0, 0, 0,
|
||||
157, 40, 1, 0, 0, 0, 158, 159, 7, 1, 0, 0, 159, 42, 1, 0, 0, 0, 160, 164,
|
||||
7, 2, 0, 0, 161, 163, 3, 39, 19, 0, 162, 161, 1, 0, 0, 0, 163, 166, 1,
|
||||
0, 0, 0, 164, 162, 1, 0, 0, 0, 164, 165, 1, 0, 0, 0, 165, 44, 1, 0, 0,
|
||||
0, 166, 164, 1, 0, 0, 0, 167, 168, 5, 48, 0, 0, 168, 46, 1, 0, 0, 0, 169,
|
||||
174, 5, 34, 0, 0, 170, 173, 3, 49, 24, 0, 171, 173, 3, 57, 28, 0, 172,
|
||||
170, 1, 0, 0, 0, 172, 171, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 172,
|
||||
1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 177, 1, 0, 0, 0, 176, 174, 1, 0,
|
||||
0, 0, 177, 188, 5, 34, 0, 0, 178, 183, 5, 39, 0, 0, 179, 182, 3, 49, 24,
|
||||
0, 180, 182, 3, 55, 27, 0, 181, 179, 1, 0, 0, 0, 181, 180, 1, 0, 0, 0,
|
||||
182, 185, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184,
|
||||
186, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 186, 188, 5, 39, 0, 0, 187, 169,
|
||||
1, 0, 0, 0, 187, 178, 1, 0, 0, 0, 188, 48, 1, 0, 0, 0, 189, 192, 5, 92,
|
||||
0, 0, 190, 193, 7, 3, 0, 0, 191, 193, 3, 51, 25, 0, 192, 190, 1, 0, 0,
|
||||
0, 192, 191, 1, 0, 0, 0, 193, 50, 1, 0, 0, 0, 194, 195, 5, 117, 0, 0, 195,
|
||||
196, 3, 53, 26, 0, 196, 197, 3, 53, 26, 0, 197, 198, 3, 53, 26, 0, 198,
|
||||
199, 3, 53, 26, 0, 199, 52, 1, 0, 0, 0, 200, 201, 7, 4, 0, 0, 201, 54,
|
||||
1, 0, 0, 0, 202, 203, 8, 5, 0, 0, 203, 56, 1, 0, 0, 0, 204, 205, 8, 6,
|
||||
0, 0, 205, 58, 1, 0, 0, 0, 206, 208, 7, 7, 0, 0, 207, 206, 1, 0, 0, 0,
|
||||
208, 209, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 209, 210, 1, 0, 0, 0, 210,
|
||||
211, 1, 0, 0, 0, 211, 212, 6, 29, 0, 0, 212, 60, 1, 0, 0, 0, 12, 0, 84,
|
||||
151, 153, 164, 172, 174, 181, 183, 187, 192, 209, 1, 6, 0, 0,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
|
@ -206,23 +202,21 @@ const (
|
|||
QueryLexerSIMPLE_OP = 4
|
||||
QueryLexerUNIQUE = 5
|
||||
QueryLexerREP = 6
|
||||
QueryLexerEC = 7
|
||||
QueryLexerIN = 8
|
||||
QueryLexerAS = 9
|
||||
QueryLexerCBF = 10
|
||||
QueryLexerSELECT = 11
|
||||
QueryLexerFROM = 12
|
||||
QueryLexerFILTER = 13
|
||||
QueryLexerWILDCARD = 14
|
||||
QueryLexerDOT = 15
|
||||
QueryLexerCLAUSE_SAME = 16
|
||||
QueryLexerCLAUSE_DISTINCT = 17
|
||||
QueryLexerL_PAREN = 18
|
||||
QueryLexerR_PAREN = 19
|
||||
QueryLexerAT = 20
|
||||
QueryLexerIDENT = 21
|
||||
QueryLexerNUMBER1 = 22
|
||||
QueryLexerZERO = 23
|
||||
QueryLexerSTRING = 24
|
||||
QueryLexerWS = 25
|
||||
QueryLexerIN = 7
|
||||
QueryLexerAS = 8
|
||||
QueryLexerCBF = 9
|
||||
QueryLexerSELECT = 10
|
||||
QueryLexerFROM = 11
|
||||
QueryLexerFILTER = 12
|
||||
QueryLexerWILDCARD = 13
|
||||
QueryLexerCLAUSE_SAME = 14
|
||||
QueryLexerCLAUSE_DISTINCT = 15
|
||||
QueryLexerL_PAREN = 16
|
||||
QueryLexerR_PAREN = 17
|
||||
QueryLexerAT = 18
|
||||
QueryLexerIDENT = 19
|
||||
QueryLexerNUMBER1 = 20
|
||||
QueryLexerZERO = 21
|
||||
QueryLexerSTRING = 22
|
||||
QueryLexerWS = 23
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
// Code generated from /repo/frostfs/sdk-go/netmap/parser/Query.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
// Code generated from Query.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser // Query
|
||||
|
||||
|
@ -14,9 +14,6 @@ type QueryVisitor interface {
|
|||
// Visit a parse tree produced by Query#selectFilterExpr.
|
||||
VisitSelectFilterExpr(ctx *SelectFilterExprContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by Query#ecStmt.
|
||||
VisitEcStmt(ctx *EcStmtContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by Query#repStmt.
|
||||
VisitRepStmt(ctx *RepStmtContext) interface{}
|
||||
|
||||
|
|
138
netmap/policy.go
138
netmap/policy.go
|
@ -34,17 +34,8 @@ type PlacementPolicy struct {
|
|||
|
||||
func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresence bool) error {
|
||||
p.replicas = m.GetReplicas()
|
||||
if checkFieldPresence {
|
||||
if len(p.replicas) == 0 {
|
||||
return errors.New("missing replicas")
|
||||
}
|
||||
if len(p.replicas) != 1 {
|
||||
for i := range p.replicas {
|
||||
if p.replicas[i].GetECDataCount() != 0 || p.replicas[i].GetECParityCount() != 0 {
|
||||
return errors.New("erasure code group must be used exclusively")
|
||||
}
|
||||
}
|
||||
}
|
||||
if checkFieldPresence && len(p.replicas) == 0 {
|
||||
return errors.New("missing replicas")
|
||||
}
|
||||
|
||||
p.backupFactor = m.GetContainerBackupFactor()
|
||||
|
@ -139,14 +130,6 @@ func (r *ReplicaDescriptor) SetNumberOfObjects(c uint32) {
|
|||
r.m.SetCount(c)
|
||||
}
|
||||
|
||||
func (r *ReplicaDescriptor) SetECDataCount(v uint32) {
|
||||
r.m.SetECDataCount(v)
|
||||
}
|
||||
|
||||
func (r *ReplicaDescriptor) SetECParityCount(v uint32) {
|
||||
r.m.SetECParityCount(v)
|
||||
}
|
||||
|
||||
// NumberOfObjects returns number set using SetNumberOfObjects.
|
||||
//
|
||||
// Zero ReplicaDescriptor has zero number of objects.
|
||||
|
@ -154,19 +137,6 @@ func (r ReplicaDescriptor) NumberOfObjects() uint32 {
|
|||
return r.m.GetCount()
|
||||
}
|
||||
|
||||
func (r ReplicaDescriptor) GetECDataCount() uint32 {
|
||||
return r.m.GetECDataCount()
|
||||
}
|
||||
|
||||
func (r ReplicaDescriptor) GetECParityCount() uint32 {
|
||||
return r.m.GetECParityCount()
|
||||
}
|
||||
|
||||
// TotalECPartCount returns total sum of ECDataCount and ECParityCount.
|
||||
func (r ReplicaDescriptor) TotalECPartCount() uint32 {
|
||||
return r.m.GetECDataCount() + r.m.GetECParityCount()
|
||||
}
|
||||
|
||||
// SetSelectorName sets name of the related Selector.
|
||||
//
|
||||
// Zero ReplicaDescriptor references to the root bucket's selector: it contains
|
||||
|
@ -200,19 +170,10 @@ func (p PlacementPolicy) NumberOfReplicas() int {
|
|||
// descriptor. Index MUST be in range [0; NumberOfReplicas()).
|
||||
//
|
||||
// Zero PlacementPolicy has no replicas.
|
||||
//
|
||||
// Deprecated: Use PlacementPolicy.ReplicaDescriptor(int).NumberOfObjects() instead.
|
||||
func (p PlacementPolicy) ReplicaNumberByIndex(i int) uint32 {
|
||||
return p.replicas[i].GetCount()
|
||||
}
|
||||
|
||||
// ReplicaDescriptor returns i-th replica descriptor. Index MUST be in range [0; NumberOfReplicas()).
|
||||
func (p PlacementPolicy) ReplicaDescriptor(i int) ReplicaDescriptor {
|
||||
return ReplicaDescriptor{
|
||||
m: p.replicas[i],
|
||||
}
|
||||
}
|
||||
|
||||
// SetContainerBackupFactor sets container backup factor: it controls how deep
|
||||
// FrostFS will search for nodes alternatives to include into container's nodes subset.
|
||||
//
|
||||
|
@ -256,11 +217,6 @@ func (s *Selector) SelectByBucketAttribute(bucket string) {
|
|||
s.m.SetAttribute(bucket)
|
||||
}
|
||||
|
||||
// SetClause sets the clause for the Selector.
|
||||
func (s *Selector) SetClause(clause netmap.Clause) {
|
||||
s.m.SetClause(clause)
|
||||
}
|
||||
|
||||
// SelectSame makes selection algorithm to select only nodes having the same values
|
||||
// of the bucket attribute.
|
||||
//
|
||||
|
@ -432,14 +388,10 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
|
|||
c := p.replicas[i].GetCount()
|
||||
s := p.replicas[i].GetSelector()
|
||||
|
||||
if c != 0 {
|
||||
_, err = w.WriteString(fmt.Sprintf("%sREP %d", delim, c))
|
||||
} else {
|
||||
ecx, ecy := p.replicas[i].GetECDataCount(), p.replicas[i].GetECParityCount()
|
||||
_, err = w.WriteString(fmt.Sprintf("%sEC %d.%d", delim, ecx, ecy))
|
||||
}
|
||||
if s != "" {
|
||||
_, err = w.WriteString(fmt.Sprintf(" IN %s", s))
|
||||
_, err = w.WriteString(fmt.Sprintf("%sREP %d IN %s", delim, c, s))
|
||||
} else {
|
||||
_, err = w.WriteString(fmt.Sprintf("%sREP %d", delim, c))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -503,7 +455,7 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
err = writeFilterStringTo(w, p.filters[i], false)
|
||||
err = writeFilterStringTo(w, p.filters[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -512,7 +464,7 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func writeFilterStringTo(w io.StringWriter, f netmap.Filter, mayNeedOuterBrackets bool) error {
|
||||
func writeFilterStringTo(w io.StringWriter, f netmap.Filter) error {
|
||||
var err error
|
||||
var s string
|
||||
op := f.GetOp()
|
||||
|
@ -537,7 +489,7 @@ func writeFilterStringTo(w io.StringWriter, f netmap.Filter, mayNeedOuterBracket
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = writeFilterStringTo(w, inner[0], false)
|
||||
err = writeFilterStringTo(w, inner[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -546,13 +498,6 @@ func writeFilterStringTo(w io.StringWriter, f netmap.Filter, mayNeedOuterBracket
|
|||
return err
|
||||
}
|
||||
} else {
|
||||
useBrackets := mayNeedOuterBrackets && op == netmap.OR && len(inner) > 1
|
||||
if useBrackets {
|
||||
_, err = w.WriteString("(")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := range inner {
|
||||
if i != 0 {
|
||||
_, err = w.WriteString(" " + op.String() + " ")
|
||||
|
@ -560,13 +505,7 @@ func writeFilterStringTo(w io.StringWriter, f netmap.Filter, mayNeedOuterBracket
|
|||
return err
|
||||
}
|
||||
}
|
||||
err = writeFilterStringTo(w, inner[i], true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if useBrackets {
|
||||
_, err = w.WriteString(")")
|
||||
err = writeFilterStringTo(w, inner[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -673,8 +612,6 @@ var (
|
|||
"make sure to pair REP and SELECT clauses: \"REP .. IN X\" + \"SELECT ... AS X\"")
|
||||
// errRedundantSelector is returned for errors found by filters policy validator.
|
||||
errRedundantFilter = errors.New("policy: found redundant filter")
|
||||
// errECFewSelectors is returned when EC keyword is used without UNIQUE keyword.
|
||||
errECFewSelectors = errors.New("policy: too few nodes to select")
|
||||
)
|
||||
|
||||
type policyVisitor struct {
|
||||
|
@ -702,18 +639,11 @@ func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any {
|
|||
|
||||
pl.unique = ctx.UNIQUE() != nil
|
||||
|
||||
stmts := ctx.GetChildren()
|
||||
for _, r := range stmts {
|
||||
var res *netmap.Replica
|
||||
var ok bool
|
||||
switch r := r.(type) {
|
||||
case parser.IRepStmtContext:
|
||||
res, ok = r.Accept(p).(*netmap.Replica)
|
||||
case parser.IEcStmtContext:
|
||||
res, ok = r.Accept(p).(*netmap.Replica)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
repStmts := ctx.AllRepStmt()
|
||||
pl.replicas = make([]netmap.Replica, 0, len(repStmts))
|
||||
|
||||
for _, r := range repStmts {
|
||||
res, ok := r.Accept(p).(*netmap.Replica)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
@ -810,28 +740,6 @@ func (p *policyVisitor) VisitRepStmt(ctx *parser.RepStmtContext) any {
|
|||
return rs
|
||||
}
|
||||
|
||||
// VisitRepStmt implements parser.QueryVisitor interface.
|
||||
func (p *policyVisitor) VisitEcStmt(ctx *parser.EcStmtContext) any {
|
||||
dataCount, err := strconv.ParseUint(ctx.GetData().GetText(), 10, 32)
|
||||
if err != nil {
|
||||
return p.reportError(errInvalidNumber)
|
||||
}
|
||||
parityCount, err := strconv.ParseUint(ctx.GetParity().GetText(), 10, 32)
|
||||
if err != nil {
|
||||
return p.reportError(errInvalidNumber)
|
||||
}
|
||||
|
||||
rs := new(netmap.Replica)
|
||||
rs.SetECDataCount(uint32(dataCount))
|
||||
rs.SetECParityCount(uint32(parityCount))
|
||||
|
||||
if sel := ctx.GetSelector(); sel != nil {
|
||||
rs.SetSelector(sel.GetText())
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// VisitSelectStmt implements parser.QueryVisitor interface.
|
||||
func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) any {
|
||||
res, err := strconv.ParseUint(ctx.GetCount().GetText(), 10, 32)
|
||||
|
@ -984,14 +892,6 @@ func validatePolicy(p PlacementPolicy) error {
|
|||
if seenSelectors[selName] == nil {
|
||||
return fmt.Errorf("%w: '%s'", errUnknownSelector, selName)
|
||||
}
|
||||
|
||||
dataCount := p.replicas[i].GetECDataCount()
|
||||
parityCount := p.replicas[i].GetECParityCount()
|
||||
if dataCount != 0 || parityCount != 0 {
|
||||
if c := seenSelectors[selName].GetCount(); c < dataCount+parityCount {
|
||||
return fmt.Errorf("%w: %d < %d + %d", errECFewSelectors, c, dataCount, parityCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1022,14 +922,10 @@ func operationFromString(s string) (op netmap.Operation) {
|
|||
return
|
||||
}
|
||||
|
||||
// escapeString returns single quote wrapped string.
|
||||
// Wrapping rules must be kept in sync with QueryLexer.g4.
|
||||
// Currently only ASCII letters, digits and underscore can be parsed without quotes.
|
||||
// escapeString returns single quote wrapped string if it contains special
|
||||
// characters '-' and whitespace.
|
||||
func escapeString(s string) string {
|
||||
for _, r := range s {
|
||||
if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || r == '_' {
|
||||
continue
|
||||
}
|
||||
if strings.ContainsAny(s, " -\t") {
|
||||
return "'" + s + "'"
|
||||
}
|
||||
return s
|
||||
|
|
|
@ -7,50 +7,43 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var validPlacementPolicy = []string{
|
||||
`REP 2
|
||||
func TestDecodeString(t *testing.T) {
|
||||
testCases := []string{
|
||||
`REP 2
|
||||
CBF 2
|
||||
SELECT 2 FROM *`,
|
||||
`REP 1 IN X
|
||||
`REP 1 IN X
|
||||
CBF 1
|
||||
SELECT 2 IN SAME Location FROM * AS X`,
|
||||
|
||||
`REP 1 IN X
|
||||
`REP 1 IN X
|
||||
REP 2 IN Y
|
||||
CBF 1
|
||||
SELECT 2 FROM * AS X
|
||||
SELECT 3 FROM * AS Y`,
|
||||
|
||||
`REP 1 IN X
|
||||
`REP 1 IN X
|
||||
SELECT 2 IN City FROM Good AS X
|
||||
FILTER Country EQ RU AS FromRU
|
||||
FILTER Country EQ EN AS FromEN
|
||||
FILTER @FromRU AND @FromEN AND Rating GT 7 AS Good`,
|
||||
|
||||
`REP 7 IN SPB
|
||||
`REP 7 IN SPB
|
||||
SELECT 1 IN City FROM SPBSSD AS SPB
|
||||
FILTER City EQ SPB AND SSD EQ true OR City EQ SPB AND Rating GE 5 AS SPBSSD`,
|
||||
|
||||
`REP 7 IN SPB
|
||||
`REP 7 IN SPB
|
||||
SELECT 1 IN City FROM SPBSSD AS SPB
|
||||
FILTER NOT (NOT (City EQ SPB) AND SSD EQ true OR City EQ SPB AND Rating GE 5) AS SPBSSD`,
|
||||
|
||||
`REP 1 IN FNODE
|
||||
CBF 1
|
||||
SELECT 1 FROM F AS FNODE
|
||||
FILTER Node EQ '10.78.8.11' AS F`,
|
||||
|
||||
`UNIQUE
|
||||
`UNIQUE
|
||||
REP 1
|
||||
REP 1`,
|
||||
`EC 1.2 IN X
|
||||
SELECT 3 IN City FROM * AS X`,
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeString(t *testing.T) {
|
||||
var p PlacementPolicy
|
||||
|
||||
for _, testCase := range validPlacementPolicy {
|
||||
for _, testCase := range testCases {
|
||||
require.NoError(t, p.DecodeString(testCase), "unable parse %s", testCase)
|
||||
var b strings.Builder
|
||||
require.NoError(t, p.WriteStringTo(&b))
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package netmap
|
||||
|
||||
func DoFuzzPlacementPolicyDecode(data []byte) int {
|
||||
p := string(data)
|
||||
if p == "" {
|
||||
return 0
|
||||
}
|
||||
var pp PlacementPolicy
|
||||
_ = pp.DecodeString(p)
|
||||
return 1
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package netmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func FuzzDecodeString(f *testing.F) {
|
||||
for _, pp := range validPlacementPolicy {
|
||||
f.Add([]byte(pp))
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
DoFuzzPlacementPolicyDecode(data)
|
||||
})
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package netmap_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
|
@ -30,79 +29,6 @@ func TestPlacementPolicyEncoding(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestPlacementPolicyWriteString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
output string // If the output is empty, make it equal to input.
|
||||
}{
|
||||
{
|
||||
name: "no compound operators",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER Color EQ Red AS Color`,
|
||||
},
|
||||
{
|
||||
name: "no brackets in single level same-operator chain",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER Color EQ Red OR Color EQ Blue OR Color EQ Green AS Color`,
|
||||
},
|
||||
{
|
||||
name: "no brackets aroung higher precedence op",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER Color EQ Red OR Color EQ Blue AND Color NE Green AS Color`,
|
||||
},
|
||||
{
|
||||
name: "no brackets aroung higher precedence op, even if present in the input",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER Color EQ Red OR (Color EQ Blue AND Color NE Green) AS Color`,
|
||||
output: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER Color EQ Red OR Color EQ Blue AND Color NE Green AS Color`,
|
||||
},
|
||||
{
|
||||
name: "brackets aroung lower precedence op",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER (Color EQ Red OR Color EQ Blue) AND Color NE Green AS Color`,
|
||||
},
|
||||
{
|
||||
name: "no extra brackets for bracketed same-operator chain",
|
||||
input: `REP 1
|
||||
CBF 1
|
||||
SELECT 1 FROM Color
|
||||
FILTER (Color EQ Red OR Color EQ Blue OR Color EQ Yellow) AND Color NE Green AS Color`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
var p PlacementPolicy
|
||||
require.NoError(t, p.DecodeString(tc.input))
|
||||
|
||||
var sb strings.Builder
|
||||
require.NoError(t, p.WriteStringTo(&sb))
|
||||
|
||||
if tc.output == "" {
|
||||
require.Equal(t, tc.input, sb.String())
|
||||
} else {
|
||||
require.Equal(t, tc.output, sb.String())
|
||||
|
||||
var p1 PlacementPolicy
|
||||
require.NoError(t, p1.DecodeString(tc.output))
|
||||
require.Equal(t, p, p1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeSelectFilterExpr(t *testing.T) {
|
||||
for _, s := range []string{
|
||||
"SELECT 1 FROM *",
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/hrw"
|
||||
|
@ -71,12 +70,12 @@ func (c *context) getSelection(s netmap.Selector) ([]nodes, error) {
|
|||
// we also need to have deterministic input to HRW sorting routine.
|
||||
if len(c.hrwSeed) == 0 {
|
||||
if s.GetAttribute() == "" {
|
||||
slices.SortFunc(buckets, func(b1, b2 nodeAttrPair) int {
|
||||
return cmp.Compare(b1.nodes[0].Hash(), b2.nodes[0].Hash())
|
||||
sort.Slice(buckets, func(i, j int) bool {
|
||||
return less(buckets[i].nodes[0], buckets[j].nodes[0])
|
||||
})
|
||||
} else {
|
||||
slices.SortFunc(buckets, func(b1, b2 nodeAttrPair) int {
|
||||
return cmp.Compare(b1.attr, b2.attr)
|
||||
sort.Slice(buckets, func(i, j int) bool {
|
||||
return buckets[i].attr < buckets[j].attr
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -104,10 +103,8 @@ func (c *context) getSelection(s netmap.Selector) ([]nodes, error) {
|
|||
|
||||
if len(c.hrwSeed) != 0 {
|
||||
weights := make([]float64, len(res))
|
||||
a := new(meanIQRAgg)
|
||||
for i := range res {
|
||||
a.clear()
|
||||
weights[i] = calcBucketWeight(res[i], a, c.weightFunc)
|
||||
weights[i] = calcBucketWeight(res[i], newMeanIQRAgg(), c.weightFunc)
|
||||
}
|
||||
|
||||
hrw.SortHasherSliceByWeightValue(res, weights, c.hrwSeedHash)
|
||||
|
@ -171,10 +168,8 @@ func (c *context) getSelectionBase(s netmap.Selector) []nodeAttrPair {
|
|||
}
|
||||
|
||||
if len(c.hrwSeed) != 0 {
|
||||
var ws []float64
|
||||
for i := range result {
|
||||
ws = result[i].nodes.appendWeightsTo(c.weightFunc, ws[:0])
|
||||
hrw.SortHasherSliceByWeightValue(result[i].nodes, ws, c.hrwSeedHash)
|
||||
hrw.SortHasherSliceByWeightValue(result[i].nodes, result[i].nodes.weights(c.weightFunc), c.hrwSeedHash)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
mrand "math/rand"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
|
@ -86,8 +85,8 @@ func BenchmarkHRWSort(b *testing.B) {
|
|||
copy(realNodes, vectors)
|
||||
b.StartTimer()
|
||||
|
||||
slices.SortFunc(vectors, func(vi, vj nodes) int {
|
||||
return cmp.Compare(vi[0].Hash(), vj[0].Hash())
|
||||
sort.Slice(vectors, func(i, j int) bool {
|
||||
return less(vectors[i][0], vectors[j][0])
|
||||
})
|
||||
hrw.SortSliceByWeightIndex(realNodes, weights, pivot)
|
||||
}
|
||||
|
@ -100,12 +99,10 @@ func BenchmarkPolicyHRWType(b *testing.B) {
|
|||
p := newPlacementPolicy(1,
|
||||
[]ReplicaDescriptor{
|
||||
newReplica(1, "loc1"),
|
||||
newReplica(1, "loc2"),
|
||||
},
|
||||
newReplica(1, "loc2")},
|
||||
[]Selector{
|
||||
newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame),
|
||||
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame),
|
||||
},
|
||||
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)},
|
||||
[]Filter{
|
||||
newFilter("loc1", "Location", "Shanghai", netmap.EQ),
|
||||
newFilter("loc2", "Location", "Shanghai", netmap.NE),
|
||||
|
@ -147,12 +144,10 @@ func TestPlacementPolicy_DeterministicOrder(t *testing.T) {
|
|||
p := newPlacementPolicy(1,
|
||||
[]ReplicaDescriptor{
|
||||
newReplica(1, "loc1"),
|
||||
newReplica(1, "loc2"),
|
||||
},
|
||||
newReplica(1, "loc2")},
|
||||
[]Selector{
|
||||
newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame),
|
||||
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame),
|
||||
},
|
||||
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)},
|
||||
[]Filter{
|
||||
newFilter("loc1", "Location", "Shanghai", netmap.EQ),
|
||||
newFilter("loc2", "Location", "Shanghai", netmap.NE),
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
name: default CBF is 3
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: Location
|
||||
value: Europe
|
||||
- key: Country
|
||||
value: RU
|
||||
- key: City
|
||||
value: St.Petersburg
|
||||
- attributes:
|
||||
- key: Location
|
||||
value: Europe
|
||||
- key: Country
|
||||
value: RU
|
||||
- key: City
|
||||
value: Moscow
|
||||
- attributes:
|
||||
- key: Location
|
||||
value: Europe
|
||||
- key: Country
|
||||
value: DE
|
||||
- key: City
|
||||
value: Berlin
|
||||
- attributes:
|
||||
- key: Location
|
||||
value: Europe
|
||||
- key: Country
|
||||
value: FR
|
||||
- key: City
|
||||
value: Paris
|
||||
tests:
|
||||
set default CBF:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: EU
|
||||
containerBackupFactor: 0
|
||||
selectors:
|
||||
- name: EU
|
||||
count: 1
|
||||
clause: SAME
|
||||
attribute: Location
|
||||
filter: '*'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 1
|
||||
- 2
|
|
@ -1,52 +0,0 @@
|
|||
name: Real node count multiplier is in range [1, specified CBF]
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '1'
|
||||
- key: Country
|
||||
value: DE
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '2'
|
||||
- key: Country
|
||||
value: DE
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '3'
|
||||
- key: Country
|
||||
value: DE
|
||||
tests:
|
||||
select 2, CBF is 2:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: X
|
||||
containerBackupFactor: 2
|
||||
selectors:
|
||||
- name: X
|
||||
count: 2
|
||||
clause: SAME
|
||||
attribute: Country
|
||||
filter: '*'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 1
|
||||
- 2
|
||||
select 3, CBF is 2:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: X
|
||||
containerBackupFactor: 2
|
||||
selectors:
|
||||
- name: X
|
||||
count: 3
|
||||
clause: SAME
|
||||
attribute: Country
|
||||
filter: '*'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 1
|
||||
- 2
|
|
@ -1,82 +0,0 @@
|
|||
name: CBF requirements
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '1'
|
||||
- key: Attr
|
||||
value: Same
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '2'
|
||||
- key: Attr
|
||||
value: Same
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '3'
|
||||
- key: Attr
|
||||
value: Same
|
||||
- attributes:
|
||||
- key: ID
|
||||
value: '4'
|
||||
- key: Attr
|
||||
value: Same
|
||||
tests:
|
||||
default CBF, no selector:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 2
|
||||
containerBackupFactor: 0
|
||||
selectors: []
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 2
|
||||
- 1
|
||||
- 3
|
||||
explicit CBF, no selector:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 2
|
||||
containerBackupFactor: 3
|
||||
selectors: []
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 2
|
||||
- 1
|
||||
- 3
|
||||
select distinct, weak CBF:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 2
|
||||
selector: X
|
||||
containerBackupFactor: 3
|
||||
selectors:
|
||||
- name: X
|
||||
count: 2
|
||||
clause: DISTINCT
|
||||
filter: '*'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 2
|
||||
- 1
|
||||
- 3
|
||||
select same, weak CBF:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 2
|
||||
selector: X
|
||||
containerBackupFactor: 3
|
||||
selectors:
|
||||
- name: X
|
||||
count: 2
|
||||
clause: SAME
|
||||
attribute: Attr
|
||||
filter: '*'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
|
@ -1,210 +0,0 @@
|
|||
name: compound filter
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: Storage
|
||||
value: SSD
|
||||
- key: Rating
|
||||
value: '10'
|
||||
- key: IntField
|
||||
value: '100'
|
||||
- key: Param
|
||||
value: Value1
|
||||
tests:
|
||||
good:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
key: Storage
|
||||
op: EQ
|
||||
value: SSD
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '4'
|
||||
filters: []
|
||||
- name: Main
|
||||
op: AND
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
key: IntField
|
||||
op: LT
|
||||
value: '123'
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- op: OR
|
||||
filters:
|
||||
- key: Param
|
||||
op: EQ
|
||||
value: Value1
|
||||
filters: []
|
||||
- key: Param
|
||||
op: EQ
|
||||
value: Value2
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
bad storage type:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
key: Storage
|
||||
op: EQ
|
||||
value: HDD
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '4'
|
||||
filters: []
|
||||
- name: Main
|
||||
op: AND
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
key: IntField
|
||||
op: LT
|
||||
value: '123'
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
op: OR
|
||||
filters:
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value1
|
||||
filters: []
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value2
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
bad rating:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
key: Storage
|
||||
op: EQ
|
||||
value: SSD
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '15'
|
||||
filters: []
|
||||
- name: Main
|
||||
op: AND
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
key: IntField
|
||||
op: LT
|
||||
value: '123'
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
op: OR
|
||||
filters:
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value1
|
||||
filters: []
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value2
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
bad param:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
key: Storage
|
||||
op: EQ
|
||||
value: SSD
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '4'
|
||||
filters: []
|
||||
- name: Main
|
||||
op: AND
|
||||
filters:
|
||||
- name: StorageSSD
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
key: IntField
|
||||
op: LT
|
||||
value: '123'
|
||||
filters: []
|
||||
- name: GoodRating
|
||||
op: OPERATION_UNSPECIFIED
|
||||
filters: []
|
||||
- name: ''
|
||||
op: OR
|
||||
filters:
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value0
|
||||
filters: []
|
||||
- name: ''
|
||||
key: Param
|
||||
op: EQ
|
||||
value: Value2
|
||||
filters: []
|
||||
error: not enough nodes
|
|
@ -1,45 +0,0 @@
|
|||
name: invalid integer field
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: IntegerField
|
||||
value: 'true'
|
||||
- attributes:
|
||||
- key: IntegerField
|
||||
value: str
|
||||
tests:
|
||||
empty string is not casted to 0:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: IntegerField
|
||||
op: LE
|
||||
value: '8'
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
non-empty string is not casted to a number:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: IntegerField
|
||||
op: GE
|
||||
value: '0'
|
||||
filters: []
|
||||
error: not enough nodes
|
|
@ -1,230 +0,0 @@
|
|||
name: single-op filters
|
||||
nodes:
|
||||
- attributes:
|
||||
- key: Rating
|
||||
value: '4'
|
||||
- key: Country
|
||||
value: Germany
|
||||
tests:
|
||||
GE true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '4'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
GE false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: GE
|
||||
value: '5'
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
GT true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: GT
|
||||
value: '3'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
GT false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: GT
|
||||
value: '4'
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
LE true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: LE
|
||||
value: '4'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
LE false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: LE
|
||||
value: '3'
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
LT true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: LT
|
||||
value: '5'
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
LT false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Rating
|
||||
op: LT
|
||||
value: '4'
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
EQ true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Country
|
||||
op: EQ
|
||||
value: Germany
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
EQ false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Country
|
||||
op: EQ
|
||||
value: China
|
||||
filters: []
|
||||
error: not enough nodes
|
||||
NE true:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Country
|
||||
op: NE
|
||||
value: France
|
||||
filters: []
|
||||
result:
|
||||
- - 0
|
||||
NE false:
|
||||
policy:
|
||||
replicas:
|
||||
- count: 1
|
||||
selector: S
|
||||
containerBackupFactor: 1
|
||||
selectors:
|
||||
- name: S
|
||||
count: 1
|
||||
clause: DISTINCT
|
||||
filter: Main
|
||||
filters:
|
||||
- name: Main
|
||||
key: Country
|
||||
op: NE
|
||||
value: Germany
|
||||
filters: []
|
||||
error: not enough nodes
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue