forked from TrueCloudLab/xk6-frostfs
[#14] Add s3 local loader
Signed-off-by: Alejandro Lopez <a.lopez@yadro.com>
This commit is contained in:
parent
6832771973
commit
de6747fc0f
18 changed files with 1206 additions and 154 deletions
26
README.md
26
README.md
|
@ -117,9 +117,33 @@ const s3_cli = s3.connect("http://s3.frostfs.devenv:8080", {'no_verify_ssl': 'tr
|
|||
- `get(bucket, key)`. Returns dictionary with `success` boolean flag and `error`
|
||||
string.
|
||||
|
||||
## S3 Local
|
||||
|
||||
Create local s3 client with `connect` method. Arguments:
|
||||
- local path to frostfs storage node configuration file
|
||||
- parameter map with the following options:
|
||||
* `hex_key`: private key to use as a hexadecimal string. A random one is created if none is provided.
|
||||
* `node_position`: position of this node in the node array if loading multiple nodes independently (default: 0).
|
||||
* `node_count`: number of nodes in the node array if loading multiple nodes independently (default: 1).
|
||||
- bucket-container mapping, which is needed to resolve the container id for a given bucket name. Any bucket
|
||||
used by the client must have an entry here.
|
||||
|
||||
```js
|
||||
import local from 'k6/x/frostfs/local';
|
||||
const params = {'node_position': 1, 'node_count': 3}
|
||||
const bucketMapping = {'mytestbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6'}
|
||||
const local_client = local.connect("/path/to/config.yaml", params, bucketMapping)
|
||||
```
|
||||
|
||||
### Methods
|
||||
- `put(bucket, key, payload)`. Returns dictionary with `success` boolean flag
|
||||
and `error` string.
|
||||
- `get(bucket, key)`. Returns dictionary with `success` boolean flag and `error`
|
||||
string.
|
||||
|
||||
# Examples
|
||||
|
||||
See native protocol and s3 test suit examples in [examples](./examples) dir.
|
||||
See native protocol and s3 test suite examples in [examples](./examples) dir.
|
||||
|
||||
# License
|
||||
|
||||
|
|
15
examples/s3local.js
Normal file
15
examples/s3local.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {uuidv4} from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
|
||||
import s3local from 'k6/x/frostfs/s3local';
|
||||
|
||||
const bucket = "testbucket"
|
||||
const payload = open('../go.sum', 'b');
|
||||
const s3local_cli = s3local.connect("path/to/storage/config.yml", {}, {
|
||||
'testbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6',
|
||||
});
|
||||
|
||||
export default function () {
|
||||
const key = uuidv4();
|
||||
if (s3local_cli.put(bucket, key, payload).success) {
|
||||
s3local_cli.get(bucket, key)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
_ "git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/native"
|
||||
_ "git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/registry"
|
||||
_ "git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/s3"
|
||||
_ "git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/s3local"
|
||||
"go.k6.io/k6/js/modules"
|
||||
)
|
||||
|
||||
|
|
49
go.mod
49
go.mod
|
@ -4,7 +4,8 @@ go 1.17
|
|||
|
||||
require (
|
||||
git.frostfs.info/TrueCloudLab/frostfs-node v0.22.2-0.20230313113918-4e244686cf03
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230307124721-94476f905599
|
||||
git.frostfs.info/TrueCloudLab/frostfs-s3-gw v0.24.1-0.20230403110435-01afa1cae425
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130
|
||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.5
|
||||
|
@ -12,8 +13,8 @@ require (
|
|||
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/nspcc-dev/neo-go v0.100.1
|
||||
github.com/panjf2000/ants/v2 v2.4.0
|
||||
github.com/nspcc-dev/neo-go v0.101.0
|
||||
github.com/panjf2000/ants/v2 v2.5.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
|
@ -22,11 +23,12 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230307104236-f69d2ad83c51 // indirect
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703 // indirect
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 // indirect
|
||||
git.frostfs.info/TrueCloudLab/hrw v1.2.0 // indirect
|
||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 // indirect
|
||||
|
@ -41,6 +43,9 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect
|
||||
github.com/aws/smithy-go v1.11.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bluele/gcache v0.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
|
||||
|
@ -48,43 +53,55 @@ require (
|
|||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.15.13 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/minio/sio v0.3.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.4.1 // indirect
|
||||
github.com/nats-io/nats.go v1.22.1 // indirect
|
||||
github.com/nats-io/nkeys v0.4.4 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.14.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/spf13/viper v1.15.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221227203929-1b447090c38c // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
google.golang.org/grpc v1.52.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/guregu/null.v3 v3.3.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
99
go.sum
99
go.sum
|
@ -114,8 +114,10 @@ cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOt
|
|||
cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||
cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
|
||||
cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
|
||||
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
|
||||
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
|
||||
cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg=
|
||||
|
@ -381,15 +383,19 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS
|
|||
cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M=
|
||||
cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA=
|
||||
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.11.2-0.20230307104236-f69d2ad83c51 h1:l4+K1hN+NuWNtlZZoV8yRRP3Uu7PifL05ukEqKcb0Ks=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230307104236-f69d2ad83c51/go.mod h1:n0DxKYulu2Ar73R6OcNF34LiL/Xa+iDR7GZuaOChbLE=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703 h1:lxe0DtZq/uFZVZu9apx6OcIXCJskQBMd/GVeYGKA3wA=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703/go.mod h1:gRd5iE5A84viily6AcNBsSlTx2XgoWrwRDz7z0MayDQ=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-node v0.22.2-0.20230313113918-4e244686cf03 h1:OGLkpWNSIKEfpMEWHyK/iuid4NTipPo6xfXo1hhM2o8=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-node v0.22.2-0.20230313113918-4e244686cf03/go.mod h1:1aLnRjy4a9XjQY1oCQ98roMTLQetPAdpbPHvrR978PU=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230307124721-94476f905599 h1:mzGX2RX8R8H/tUqrUu1TcYk4QRDBcBIWGYscPncfLOQ=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-s3-gw v0.24.1-0.20230403110435-01afa1cae425 h1:vHDmz5CLJrw0JZR85TP57WqvjwgfTmbgOp/SQcmjUUg=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-s3-gw v0.24.1-0.20230403110435-01afa1cae425/go.mod h1:b0Z8M58N+uyOvfSWPO3ZWsqK1t9o/w2qj78ITNiUTOw=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230307124721-94476f905599/go.mod h1:z7zcpGY+puI5puyy5oyFbf20vWp84WtslCxcr6/kv5c=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130 h1:V+3dGwEXwEvvSvseMKn8S6ZEMNhxBBYrcyx+F7VaptM=
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130/go.mod h1:23fUGlEv/ImaOi3vck6vZj0v0b4hteOhLLPnVWHSQeA=
|
||||
git.frostfs.info/TrueCloudLab/hrw v1.2.0 h1:KvAES7xIqmQBGd2q8KanNosD9+4BhU/zqD5Kt5KSflk=
|
||||
git.frostfs.info/TrueCloudLab/hrw v1.2.0/go.mod h1:mq2sbvYfO+BB6iFZwYBkgC0yc6mJNx+qZi4jW918m+Y=
|
||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
|
||||
|
@ -434,6 +440,8 @@ github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb
|
|||
github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.44.6 h1:Y+uHxmZfhRTLX2X3khkdxCoTZAyGEX21aOUHe1U6geg=
|
||||
github.com/aws/aws-sdk-go v1.44.6/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU=
|
||||
|
@ -472,8 +480,11 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj
|
|||
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||
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=
|
||||
|
@ -488,9 +499,11 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
|
|||
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/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
|
@ -660,6 +673,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
|
@ -672,13 +686,17 @@ github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMd
|
|||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
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/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY=
|
||||
github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4=
|
||||
github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw=
|
||||
github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
|
@ -702,6 +720,7 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
|||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
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=
|
||||
|
@ -715,8 +734,10 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
|
|||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||
github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/hashicorp/serf v0.9.8/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -733,7 +754,9 @@ github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+
|
|||
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
|
||||
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
|
||||
github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
|
@ -754,6 +777,7 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
|||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
|
||||
|
@ -774,8 +798,9 @@ 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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
|
@ -796,15 +821,20 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
|
|||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa h1:lx8ZnNPwjkXSzOROz0cg69RlErRXs+L3eDkggASWKLo=
|
||||
github.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus=
|
||||
github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
|
@ -842,10 +872,19 @@ github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOEL
|
|||
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/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
||||
github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
|
||||
github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
|
||||
github.com/nats-io/nats-server/v2 v2.7.1/go.mod h1:tckmrt0M6bVaDT3kmh9UrIq/CBOBBse+TpXQi5ldaa8=
|
||||
github.com/nats-io/nats-server/v2 v2.7.4 h1:c+BZJ3rGzUKCBIM4IXO8uNT2u1vajGbD1kPA6wqCEaM=
|
||||
github.com/nats-io/nats-server/v2 v2.7.4/go.mod h1:1vZ2Nijh8tcyNe8BDVyTviCd9NYzRbubQYiEHsvOQWc=
|
||||
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nats.go v1.13.1-0.20220308171302-2f2f6968e98d/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nats.go v1.22.1 h1:XzfqDspY0RNufzdrB8c4hFR+R3dahkxlpWe5+IWJzbE=
|
||||
github.com/nats-io/nats.go v1.22.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
||||
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/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=
|
||||
|
@ -861,8 +900,9 @@ github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkP
|
|||
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.100.1 h1:yugxbQRdzM+ObVa5mtr9/n4rYjxSIrryne8MVr9NBwU=
|
||||
github.com/nspcc-dev/neo-go v0.100.1/go.mod h1:Nnp7F4e9IBccsgtCeLtUWV+0T6gk1PtP5HRtA13hUfc=
|
||||
github.com/nspcc-dev/neo-go v0.101.0 h1:JPT2DpZqVjho34TMR59dm6uxvCFttOp02Nm8qCjpfaU=
|
||||
github.com/nspcc-dev/neo-go v0.101.0/go.mod h1:Q0uWKivGc2mYgdKFmTNP49LeXwMu4x6pUzHm3OIsN2I=
|
||||
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-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
|
@ -895,16 +935,18 @@ 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/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/panjf2000/ants/v2 v2.4.0 h1:embKPQeNWMRbnrRKURv4TXJwjQRWMEAfqZT6Pe5hZNc=
|
||||
github.com/panjf2000/ants/v2 v2.4.0/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
||||
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
|
||||
github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulmach/orb v0.2.2/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU=
|
||||
github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/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=
|
||||
|
@ -923,10 +965,12 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
|
|||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
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 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
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=
|
||||
|
@ -934,6 +978,7 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
|
|||
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 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
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=
|
||||
|
@ -942,6 +987,7 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
|
|||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.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 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
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=
|
||||
|
@ -952,6 +998,7 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
|||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY=
|
||||
github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e h1:zWKUYT07mGmVBH+9UgnHXd/ekCK99C8EbDSAt5qsjXE=
|
||||
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||
|
@ -965,8 +1012,9 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
|
||||
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
|
@ -975,8 +1023,9 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq
|
|||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
|
||||
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
||||
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
|
||||
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
|
@ -992,8 +1041,9 @@ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
||||
github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
|
@ -1003,6 +1053,7 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri
|
|||
github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
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=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
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=
|
||||
|
@ -1017,9 +1068,13 @@ 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.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
|
||||
go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
|
||||
go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4=
|
||||
go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0=
|
||||
go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c=
|
||||
go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk=
|
||||
go.k6.io/k6 v0.38.2 h1:v4Dr7KhZVf+s6V6oz/pGtQ9ejTfNgUPcd/D3RH3GVdY=
|
||||
go.k6.io/k6 v0.38.2/go.mod h1:1bTdDsXTT2V3in3ZgdR15MDW6SQQh5nWni59tirqNB8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
@ -1054,6 +1109,7 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf
|
|||
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-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -1074,8 +1130,10 @@ golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0
|
|||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
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=
|
||||
|
@ -1118,6 +1176,7 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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=
|
||||
|
@ -1181,8 +1240,10 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS
|
|||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
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=
|
||||
|
@ -1325,14 +1386,18 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
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=
|
||||
|
@ -1344,8 +1409,10 @@ 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.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=
|
||||
|
@ -1417,6 +1484,7 @@ golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
|||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
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=
|
||||
|
@ -1477,6 +1545,7 @@ google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91
|
|||
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
|
||||
google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo=
|
||||
google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
|
||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
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=
|
||||
|
@ -1594,6 +1663,7 @@ google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZV
|
|||
google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
@ -1632,8 +1702,9 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
|
|||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
|
||||
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
|
|
@ -1,91 +1,39 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/stats"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local/rawclient"
|
||||
"github.com/dop251/goja"
|
||||
"go.k6.io/k6/js/modules"
|
||||
"go.k6.io/k6/metrics"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
vu modules.VU
|
||||
key ecdsa.PrivateKey
|
||||
ng *engine.StorageEngine
|
||||
rc *rawclient.RawClient
|
||||
}
|
||||
|
||||
type PutResponse struct {
|
||||
Success bool
|
||||
ObjectID string
|
||||
Error string
|
||||
}
|
||||
type (
|
||||
SuccessOrErrorResponse struct {
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
|
||||
type GetResponse struct {
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
PutResponse struct {
|
||||
Success bool
|
||||
ObjectID string
|
||||
Error string
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
GetResponse SuccessOrErrorResponse
|
||||
DeleteResponse SuccessOrErrorResponse
|
||||
)
|
||||
|
||||
func (c *Client) Put(containerID string, headers map[string]string, payload goja.ArrayBuffer) PutResponse {
|
||||
sz := len(payload.Bytes())
|
||||
|
||||
attrs := make([]object.Attribute, len(headers))
|
||||
{
|
||||
ind := 0
|
||||
for k, v := range headers {
|
||||
attrs[ind].SetKey(k)
|
||||
attrs[ind].SetValue(v)
|
||||
ind++
|
||||
}
|
||||
}
|
||||
|
||||
ownerID := &user.ID{}
|
||||
user.IDFromKey(ownerID, c.key.PublicKey)
|
||||
|
||||
obj := object.New()
|
||||
obj.SetContainerID(mustParseContainerID(containerID))
|
||||
obj.SetOwnerID(ownerID) // needed for metabase bucket name
|
||||
obj.SetAttributes(attrs...)
|
||||
obj.SetPayload(payload.Bytes())
|
||||
obj.SetPayloadSize(uint64(len(payload.Bytes())))
|
||||
object.CalculateAndSetPayloadChecksum(obj) // needed for metabase key
|
||||
|
||||
id, err := object.CalculateID(obj)
|
||||
id, err := c.rc.Put(mustParseContainerID(containerID), nil, headers, payload.Bytes())
|
||||
if err != nil {
|
||||
return PutResponse{Error: fmt.Sprintf("calculating id: %v", err)}
|
||||
}
|
||||
obj.SetID(id)
|
||||
|
||||
if err := object.CalculateAndSetSignature(c.key, obj); err != nil {
|
||||
return PutResponse{Error: fmt.Sprintf("calculating signature: %v", err)}
|
||||
}
|
||||
|
||||
var req engine.PutPrm
|
||||
req.WithObject(obj)
|
||||
|
||||
start := time.Now()
|
||||
|
||||
if _, err := c.ng.Put(req); err != nil {
|
||||
stats.Report(c.vu, objPutFails, 1)
|
||||
return PutResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
stats.Report(c.vu, objPutTotal, 1)
|
||||
stats.ReportDataSent(c.vu, float64(sz))
|
||||
stats.Report(c.vu, objPutDuration, metrics.D(time.Since(start)))
|
||||
|
||||
return PutResponse{
|
||||
Success: true,
|
||||
ObjectID: id.EncodeToString(),
|
||||
|
@ -93,44 +41,16 @@ func (c *Client) Put(containerID string, headers map[string]string, payload goja
|
|||
}
|
||||
|
||||
func (c *Client) Get(containerID, objectID string) GetResponse {
|
||||
var addr oid.Address
|
||||
addr.SetContainer(mustParseContainerID(containerID))
|
||||
addr.SetObject(mustParseObjectID(objectID))
|
||||
|
||||
var req engine.GetPrm
|
||||
req.WithAddress(addr)
|
||||
|
||||
start := time.Now()
|
||||
resp, err := c.ng.Get(req)
|
||||
if err != nil {
|
||||
stats.Report(c.vu, objGetFails, 1)
|
||||
if _, err := c.rc.Get(mustParseContainerID(containerID), mustParseObjectID(objectID)); err != nil {
|
||||
return GetResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
stats.Report(c.vu, objGetTotal, 1)
|
||||
stats.Report(c.vu, objGetDuration, metrics.D(time.Since(start)))
|
||||
stats.ReportDataReceived(c.vu, float64(len(resp.Object().Payload())))
|
||||
|
||||
return GetResponse{Success: true}
|
||||
}
|
||||
|
||||
func (c *Client) Delete(containerID, objectID string) DeleteResponse {
|
||||
var addr oid.Address
|
||||
addr.SetContainer(mustParseContainerID(containerID))
|
||||
addr.SetObject(mustParseObjectID(objectID))
|
||||
|
||||
var req engine.DeletePrm
|
||||
req.WithAddress(addr)
|
||||
|
||||
start := time.Now()
|
||||
if _, err := c.ng.Delete(req); err != nil {
|
||||
stats.Report(c.vu, objDeleteFails, 1)
|
||||
if err := c.rc.Delete(mustParseContainerID(containerID), mustParseObjectID(objectID)); err != nil {
|
||||
return DeleteResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
stats.Report(c.vu, objDeleteTotal, 1)
|
||||
stats.Report(c.vu, objDeleteDuration, metrics.D(time.Since(start)))
|
||||
|
||||
return DeleteResponse{Success: true}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
@ -22,6 +23,8 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local/rawclient"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/stats"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"go.etcd.io/bbolt"
|
||||
|
@ -44,7 +47,7 @@ type RootModule struct {
|
|||
// Local represents an instance of the module for every VU.
|
||||
type Local struct {
|
||||
vu modules.VU
|
||||
resolveEngine func(string) (*engine.StorageEngine, error)
|
||||
ResolveEngine func(context.Context, string) (*engine.StorageEngine, error)
|
||||
}
|
||||
|
||||
// Ensure the interfaces are implemented correctly.
|
||||
|
@ -64,17 +67,20 @@ func init() {
|
|||
// NewModuleInstance implements the modules.Module interface and returns
|
||||
// a new instance for each VU.
|
||||
func (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {
|
||||
mi := &Local{
|
||||
vu: vu,
|
||||
resolveEngine: r.getOrCreateEngine,
|
||||
}
|
||||
return mi
|
||||
return NewLocalModuleInstance(vu, r.GetOrCreateEngine)
|
||||
}
|
||||
|
||||
// getOrCreateEngine returns the current engine instance for the given configuration file,
|
||||
func NewLocalModuleInstance(vu modules.VU, resolveEngine func(context.Context, string) (*engine.StorageEngine, error)) *Local {
|
||||
return &Local{
|
||||
vu: vu,
|
||||
ResolveEngine: resolveEngine,
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrCreateEngine returns the current engine instance for the given configuration file,
|
||||
// creating a new one if none exists. Note that the identity of configuration files is their
|
||||
// file name for the purposes of test runs.
|
||||
func (r *RootModule) getOrCreateEngine(configFile string) (*engine.StorageEngine, error) {
|
||||
func (r *RootModule) GetOrCreateEngine(ctx context.Context, configFile string) (*engine.StorageEngine, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
|
@ -100,7 +106,7 @@ func (r *RootModule) getOrCreateEngine(configFile string) (*engine.StorageEngine
|
|||
return nil, fmt.Errorf("initializing engine: %v", err)
|
||||
}
|
||||
} else if configFile != r.configFile {
|
||||
return nil, fmt.Errorf("getOrCreateEngine called with mismatching configFile after engine was initialized: got %q, want %q", configFile, r.configFile)
|
||||
return nil, fmt.Errorf("GetOrCreateEngine called with mismatching configFile after engine was initialized: got %q, want %q", configFile, r.configFile)
|
||||
}
|
||||
|
||||
return r.ng, nil
|
||||
|
@ -112,18 +118,20 @@ func (s *Local) Exports() modules.Exports {
|
|||
return modules.Exports{Default: s}
|
||||
}
|
||||
|
||||
func (s *Local) VU() modules.VU { return s.vu }
|
||||
|
||||
func (s *Local) Connect(configFile, hexKey string) (*Client, error) {
|
||||
ng, err := s.resolveEngine(configFile)
|
||||
ng, err := s.ResolveEngine(s.VU().Context(), configFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connecting to engine for config %q: %v", configFile, err)
|
||||
}
|
||||
|
||||
key, err := parseOrCreateKey(hexKey)
|
||||
key, err := ParseOrCreateKey(hexKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating key: %v", err)
|
||||
}
|
||||
|
||||
// register metrics
|
||||
// Register metrics.
|
||||
registry := metrics.NewRegistry()
|
||||
objPutTotal, _ = registry.NewMetric("local_obj_put_total", metrics.Counter)
|
||||
objPutFails, _ = registry.NewMetric("local_obj_put_fails", metrics.Counter)
|
||||
|
@ -137,11 +145,37 @@ func (s *Local) Connect(configFile, hexKey string) (*Client, error) {
|
|||
objDeleteFails, _ = registry.NewMetric("local_obj_delete_fails", metrics.Counter)
|
||||
objDeleteDuration, _ = registry.NewMetric("local_obj_delete_duration", metrics.Trend, metrics.Time)
|
||||
|
||||
return &Client{
|
||||
vu: s.vu,
|
||||
key: key.PrivateKey,
|
||||
ng: ng,
|
||||
}, nil
|
||||
// Create raw client backed by local storage engine.
|
||||
rc := rawclient.New(ng,
|
||||
rawclient.WithKey(key.PrivateKey),
|
||||
rawclient.WithPutHandler(func(sz uint64, err error, dt time.Duration) {
|
||||
if err != nil {
|
||||
stats.Report(s.vu, objPutFails, 1)
|
||||
} else {
|
||||
stats.Report(s.vu, objPutTotal, 1)
|
||||
stats.ReportDataSent(s.vu, float64(sz))
|
||||
stats.Report(s.vu, objPutDuration, metrics.D(dt))
|
||||
}
|
||||
}),
|
||||
rawclient.WithGetHandler(func(sz uint64, err error, dt time.Duration) {
|
||||
if err != nil {
|
||||
stats.Report(s.vu, objGetFails, 1)
|
||||
} else {
|
||||
stats.Report(s.vu, objGetTotal, 1)
|
||||
stats.Report(s.vu, objGetDuration, metrics.D(dt))
|
||||
stats.ReportDataReceived(s.vu, float64(sz))
|
||||
}
|
||||
}),
|
||||
rawclient.WithDeleteHandler(func(err error, dt time.Duration) {
|
||||
if err != nil {
|
||||
stats.Report(s.vu, objDeleteFails, 1)
|
||||
} else {
|
||||
stats.Report(s.vu, objDeleteTotal, 1)
|
||||
stats.Report(s.vu, objDeleteDuration, metrics.D(dt))
|
||||
}
|
||||
}),
|
||||
)
|
||||
return &Client{rc}, nil
|
||||
}
|
||||
|
||||
type epochState struct{}
|
||||
|
@ -288,7 +322,8 @@ func storageEngineOptionsFromConfig(c *config.Config) ([]engine.Option, [][]shar
|
|||
return ngOpts, shOpts
|
||||
}
|
||||
|
||||
func parseOrCreateKey(hexKeyStr string) (*keys.PrivateKey, error) {
|
||||
// ParseOrCreateKey parses the provided key as a hex string or creates a fresh one if empty.
|
||||
func ParseOrCreateKey(hexKeyStr string) (*keys.PrivateKey, error) {
|
||||
if hexKeyStr != "" {
|
||||
return keys.NewPrivateKeyFromHex(hexKeyStr)
|
||||
}
|
||||
|
|
46
internal/local/rawclient/option.go
Normal file
46
internal/local/rawclient/option.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package rawclient
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
PutHandler func(uint64, error, time.Duration)
|
||||
GetHandler func(uint64, error, time.Duration)
|
||||
DeleteHandler func(error, time.Duration)
|
||||
)
|
||||
|
||||
type config struct {
|
||||
key ecdsa.PrivateKey
|
||||
onPut PutHandler
|
||||
onGet GetHandler
|
||||
onDelete DeleteHandler
|
||||
}
|
||||
|
||||
type Option func(*config)
|
||||
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
onPut: func(uint64, error, time.Duration) {},
|
||||
onGet: func(uint64, error, time.Duration) {},
|
||||
onDelete: func(error, time.Duration) {},
|
||||
}
|
||||
}
|
||||
|
||||
// WithKey sets the private key used by the raw client if no other key
|
||||
// is available when setting owner IDs.
|
||||
// Required.
|
||||
func WithKey(key ecdsa.PrivateKey) Option { return func(c *config) { c.key = key } }
|
||||
|
||||
// WithPutHandler sets the hook invoked on completion of Put calls.
|
||||
// This is useful for updating metrics or debugging.
|
||||
func WithPutHandler(h PutHandler) Option { return func(c *config) { c.onPut = h } }
|
||||
|
||||
// WithGetHandler sets the hook invoked on completion of Get calls.
|
||||
// This is useful for updating metrics or debugging.
|
||||
func WithGetHandler(h GetHandler) Option { return func(c *config) { c.onGet = h } }
|
||||
|
||||
// WithDeleteHandler sets the hook invoked on completion of Delete calls.
|
||||
// This is useful for updating metrics or debugging.
|
||||
func WithDeleteHandler(h DeleteHandler) Option { return func(c *config) { c.onDelete = h } }
|
120
internal/local/rawclient/rawclient.go
Normal file
120
internal/local/rawclient/rawclient.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Package rawclient provides a basic interface to the local storage engine.
|
||||
// It can be used as a base for more complex load clients backed by local storage.
|
||||
package rawclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
)
|
||||
|
||||
// RawClient is a client to the local storage engine instance.
|
||||
type RawClient struct {
|
||||
*config
|
||||
ng *engine.StorageEngine
|
||||
ownerID *user.ID
|
||||
}
|
||||
|
||||
// New returns a RawClient from the provided options.
|
||||
func New(ng *engine.StorageEngine, opts ...Option) *RawClient {
|
||||
cfg := defaultConfig()
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
client := &RawClient{cfg, ng, &user.ID{}}
|
||||
user.IDFromKey(client.ownerID, client.key.PublicKey)
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *RawClient) Put(containerID cid.ID, ownerID *user.ID, headers map[string]string, payload []byte) (oid.ID, error) {
|
||||
sz := len(payload)
|
||||
|
||||
attrs := make([]object.Attribute, len(headers))
|
||||
{
|
||||
ind := 0
|
||||
for k, v := range headers {
|
||||
attrs[ind].SetKey(k)
|
||||
attrs[ind].SetValue(v)
|
||||
ind++
|
||||
}
|
||||
}
|
||||
|
||||
// Note that the key is a required option, so this is never empty.
|
||||
if ownerID == nil {
|
||||
ownerID = c.ownerID
|
||||
}
|
||||
|
||||
obj := object.New()
|
||||
obj.SetContainerID(containerID)
|
||||
obj.SetOwnerID(ownerID)
|
||||
obj.SetAttributes(attrs...)
|
||||
obj.SetPayload(payload)
|
||||
obj.SetPayloadSize(uint64(sz))
|
||||
object.CalculateAndSetPayloadChecksum(obj) // needed for metabase key
|
||||
|
||||
id, err := object.CalculateID(obj)
|
||||
if err != nil {
|
||||
return oid.ID{}, fmt.Errorf("calculating object id: %v", err)
|
||||
}
|
||||
obj.SetID(id)
|
||||
|
||||
if err := object.CalculateAndSetSignature(c.key, obj); err != nil {
|
||||
return oid.ID{}, fmt.Errorf("calculating signature: %v", err)
|
||||
}
|
||||
|
||||
var req engine.PutPrm
|
||||
req.WithObject(obj)
|
||||
|
||||
start := time.Now()
|
||||
_, err = c.ng.Put(req)
|
||||
c.onPut(uint64(sz), err, time.Since(start))
|
||||
if err != nil {
|
||||
return oid.ID{}, err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (c *RawClient) Get(containerID cid.ID, objectID oid.ID) (*object.Object, error) {
|
||||
var addr oid.Address
|
||||
addr.SetContainer(containerID)
|
||||
addr.SetObject(objectID)
|
||||
|
||||
var req engine.GetPrm
|
||||
req.WithAddress(addr)
|
||||
|
||||
start := time.Now()
|
||||
res, err := c.ng.Get(req)
|
||||
|
||||
var sz uint64
|
||||
obj := res.Object()
|
||||
if obj != nil {
|
||||
sz = uint64(len(obj.Payload()))
|
||||
}
|
||||
|
||||
c.onGet(sz, err, time.Since(start))
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (c *RawClient) Delete(containerID cid.ID, objectID oid.ID) error {
|
||||
var addr oid.Address
|
||||
addr.SetContainer(containerID)
|
||||
addr.SetObject(objectID)
|
||||
|
||||
var req engine.DeletePrm
|
||||
req.WithAddress(addr)
|
||||
|
||||
start := time.Now()
|
||||
_, err := c.ng.Delete(req)
|
||||
c.onDelete(err, time.Since(start))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *RawClient) OwnerID() *user.ID {
|
||||
return c.ownerID
|
||||
}
|
120
internal/s3local/client.go
Normal file
120
internal/s3local/client.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
package s3local
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/stats"
|
||||
"github.com/dop251/goja"
|
||||
"go.k6.io/k6/js/modules"
|
||||
"go.k6.io/k6/metrics"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
vu modules.VU
|
||||
l layer.Client
|
||||
ownerID *user.ID
|
||||
resolver layer.BucketResolver
|
||||
}
|
||||
|
||||
type (
|
||||
SuccessOrErrorResponse struct {
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
|
||||
CreateBucketResponse SuccessOrErrorResponse
|
||||
PutResponse SuccessOrErrorResponse
|
||||
DeleteResponse SuccessOrErrorResponse
|
||||
GetResponse SuccessOrErrorResponse
|
||||
)
|
||||
|
||||
func (c *Client) Put(bucket, key string, payload goja.ArrayBuffer) PutResponse {
|
||||
cid, err := c.resolver.Resolve(c.vu.Context(), bucket)
|
||||
if err != nil {
|
||||
stats.Report(c.vu, objPutFails, 1)
|
||||
return PutResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
prm := &layer.PutObjectParams{
|
||||
BktInfo: &data.BucketInfo{
|
||||
Name: bucket,
|
||||
CID: cid,
|
||||
Owner: *c.ownerID,
|
||||
Created: time.Now(),
|
||||
},
|
||||
Header: map[string]string{},
|
||||
Object: key,
|
||||
Size: int64(len(payload.Bytes())),
|
||||
Reader: bytes.NewReader(payload.Bytes()),
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
if _, err := c.l.PutObject(c.vu.Context(), prm); err != nil {
|
||||
stats.Report(c.vu, objPutFails, 1)
|
||||
return PutResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
stats.Report(c.vu, objPutDuration, metrics.D(time.Since(start)))
|
||||
stats.Report(c.vu, objPutTotal, 1)
|
||||
stats.ReportDataSent(c.vu, float64(prm.Size))
|
||||
|
||||
return PutResponse{Success: true}
|
||||
}
|
||||
|
||||
func (c *Client) Get(bucket, key string) GetResponse {
|
||||
cid, err := c.resolver.Resolve(c.vu.Context(), bucket)
|
||||
if err != nil {
|
||||
stats.Report(c.vu, objGetFails, 1)
|
||||
return GetResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
bktInfo := &data.BucketInfo{
|
||||
Name: bucket,
|
||||
CID: cid,
|
||||
Owner: *c.ownerID,
|
||||
}
|
||||
|
||||
headPrm := &layer.HeadObjectParams{
|
||||
BktInfo: bktInfo,
|
||||
Object: key,
|
||||
}
|
||||
extInfo, err := c.l.GetExtendedObjectInfo(c.vu.Context(), headPrm)
|
||||
if err != nil {
|
||||
stats.Report(c.vu, objGetFails, 1)
|
||||
return GetResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
wr := &recvDataReporter{}
|
||||
getPrm := &layer.GetObjectParams{
|
||||
BucketInfo: bktInfo,
|
||||
ObjectInfo: extInfo.ObjectInfo,
|
||||
Range: &layer.RangeParams{
|
||||
Start: 0,
|
||||
End: uint64(extInfo.ObjectInfo.Size),
|
||||
},
|
||||
Writer: wr,
|
||||
}
|
||||
if err := c.l.GetObject(c.vu.Context(), getPrm); err != nil {
|
||||
stats.Report(c.vu, objGetFails, 1)
|
||||
return GetResponse{Error: err.Error()}
|
||||
}
|
||||
|
||||
stats.Report(c.vu, objGetDuration, metrics.D(time.Since(start)))
|
||||
stats.Report(c.vu, objGetTotal, 1)
|
||||
stats.ReportDataReceived(c.vu, wr.total)
|
||||
|
||||
return GetResponse{Success: true}
|
||||
}
|
||||
|
||||
type recvDataReporter struct{ total float64 }
|
||||
|
||||
func (r *recvDataReporter) Write(p []byte) (int, error) {
|
||||
r.total += float64(len(p))
|
||||
return len(p), nil
|
||||
}
|
90
internal/s3local/frostfs.go
Normal file
90
internal/s3local/frostfs.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package s3local
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"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/eacl"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local/rawclient"
|
||||
)
|
||||
|
||||
// frostfs implements the subset of layer.FrostFS needed for clients
|
||||
// backed by local storage engines. Attempting to call any of the
|
||||
// unimplemented methods panics.
|
||||
type frostfs struct {
|
||||
*rawclient.RawClient
|
||||
}
|
||||
|
||||
func unimplementedMessage(fname string) string {
|
||||
return fmt.Sprintf("layer.FrostFS.%s is unimplemented and should not be called. If you are seeing "+
|
||||
"this error, it probably means you tried to use the s3local scenario for "+
|
||||
"something other than filling a cluster (i.e. PUT or GET).", fname)
|
||||
}
|
||||
|
||||
func (*frostfs) CreateContainer(context.Context, layer.PrmContainerCreate) (cid.ID, error) {
|
||||
panic(unimplementedMessage("CreateContainer"))
|
||||
}
|
||||
|
||||
func (*frostfs) Container(context.Context, cid.ID) (*container.Container, error) {
|
||||
panic(unimplementedMessage("Container"))
|
||||
}
|
||||
|
||||
func (*frostfs) UserContainers(context.Context, user.ID) ([]cid.ID, error) {
|
||||
panic(unimplementedMessage("UserContainers"))
|
||||
}
|
||||
|
||||
func (*frostfs) SetContainerEACL(context.Context, eacl.Table, *session.Container) error {
|
||||
panic(unimplementedMessage("SetContainerEACL"))
|
||||
}
|
||||
|
||||
func (*frostfs) ContainerEACL(context.Context, cid.ID) (*eacl.Table, error) {
|
||||
panic(unimplementedMessage("ContainerEACL"))
|
||||
}
|
||||
|
||||
func (*frostfs) DeleteContainer(context.Context, cid.ID, *session.Container) error {
|
||||
panic(unimplementedMessage("DeleteContainer"))
|
||||
}
|
||||
|
||||
func (f *frostfs) ReadObject(ctx context.Context, prm layer.PrmObjectRead) (*layer.ObjectPart, error) {
|
||||
obj, err := f.Get(prm.Container, prm.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := &layer.ObjectPart{}
|
||||
if prm.WithHeader {
|
||||
part.Head = obj
|
||||
}
|
||||
if prm.WithPayload {
|
||||
part.Payload = io.NopCloser(bytes.NewReader(obj.Payload()))
|
||||
}
|
||||
return part, nil
|
||||
}
|
||||
|
||||
func (f *frostfs) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (oid.ID, error) {
|
||||
payload, err := io.ReadAll(prm.Payload)
|
||||
if err != nil {
|
||||
return oid.ID{}, fmt.Errorf("reading payload: %v", err)
|
||||
}
|
||||
hdrs := map[string]string{}
|
||||
for _, attr := range prm.Attributes {
|
||||
hdrs[attr[0]] = attr[1]
|
||||
}
|
||||
return f.Put(prm.Container, &prm.Creator, hdrs, payload)
|
||||
}
|
||||
|
||||
func (f *frostfs) DeleteObject(context.Context, layer.PrmObjectDelete) error {
|
||||
panic(unimplementedMessage("DeleteObject"))
|
||||
}
|
||||
|
||||
func (f *frostfs) TimeToEpoch(ctx context.Context, now time.Time, future time.Time) (uint64, uint64, error) {
|
||||
panic(unimplementedMessage("TimeToEpoch"))
|
||||
}
|
166
internal/s3local/local.go
Normal file
166
internal/s3local/local.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package s3local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local/rawclient"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/stats"
|
||||
"go.k6.io/k6/js/modules"
|
||||
"go.k6.io/k6/metrics"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RootModule is the global module object type. It is instantiated once per test
|
||||
// run and will be used to create k6/x/frostfs/s3local module instances for each VU.
|
||||
type RootModule struct {
|
||||
m *local.RootModule
|
||||
}
|
||||
|
||||
// Local represents an instance of the module for every VU.
|
||||
type Local struct {
|
||||
l *local.Local
|
||||
}
|
||||
|
||||
// Ensure the interfaces are implemented correctly.
|
||||
var (
|
||||
_ modules.Module = &RootModule{}
|
||||
_ modules.Instance = &Local{}
|
||||
|
||||
internalObjPutTotal, internalObjPutFails, internalObjPutDuration *metrics.Metric
|
||||
internalObjGetTotal, internalObjGetFails, internalObjGetDuration *metrics.Metric
|
||||
objPutTotal, objPutFails, objPutDuration *metrics.Metric
|
||||
objGetTotal, objGetFails, objGetDuration *metrics.Metric
|
||||
)
|
||||
|
||||
func init() {
|
||||
modules.Register("k6/x/frostfs/s3local", &RootModule{
|
||||
m: &local.RootModule{},
|
||||
})
|
||||
}
|
||||
|
||||
// NewModuleInstance implements the modules.Module interface and returns
|
||||
// a new instance for each VU.
|
||||
func (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {
|
||||
return &Local{local.NewLocalModuleInstance(vu, r.m.GetOrCreateEngine)}
|
||||
}
|
||||
|
||||
// Exports implements the modules.Instance interface and returns the exports
|
||||
// of the JS module.
|
||||
func (s *Local) Exports() modules.Exports {
|
||||
return modules.Exports{Default: s}
|
||||
}
|
||||
|
||||
func (s *Local) Connect(configFile string, params map[string]string, bucketMapping map[string]string) (*Client, error) {
|
||||
// Parse configuration flags.
|
||||
fs := flag.NewFlagSet("s3local", flag.ContinueOnError)
|
||||
|
||||
hexKey := fs.String("hex_key", "", "Private key to use as a hexadecimal string. A random one is created if none is provided")
|
||||
nodePosition := fs.Int("node_position", 0, "Position of this node in the node array if loading multiple nodes independently")
|
||||
nodeCount := fs.Int("node_count", 1, "Number of nodes in the node array if loading multiple nodes independently")
|
||||
|
||||
{
|
||||
args := make([]string, 0, 2*len(params))
|
||||
for k, v := range params {
|
||||
args = append(args, "-"+k, v)
|
||||
}
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, fmt.Errorf("parsing parameters: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate and read configuration flags.
|
||||
key, err := local.ParseOrCreateKey(*hexKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing hex_key: %v", err)
|
||||
}
|
||||
if *nodeCount <= 0 {
|
||||
return nil, fmt.Errorf("node_count must be positive")
|
||||
}
|
||||
if *nodePosition < 0 || *nodePosition >= *nodeCount {
|
||||
return nil, fmt.Errorf("node_position must be in the range [0, node_count-1]")
|
||||
}
|
||||
|
||||
// Register metrics.
|
||||
registry := metrics.NewRegistry()
|
||||
|
||||
internalObjPutTotal, _ = registry.NewMetric("s3local_internal_obj_put_total", metrics.Counter)
|
||||
internalObjPutFails, _ = registry.NewMetric("s3local_internal_obj_put_fails", metrics.Counter)
|
||||
internalObjPutDuration, _ = registry.NewMetric("s3local_internal_obj_put_duration", metrics.Trend, metrics.Time)
|
||||
|
||||
internalObjGetTotal, _ = registry.NewMetric("s3local_internal_obj_get_total", metrics.Counter)
|
||||
internalObjGetFails, _ = registry.NewMetric("s3local_internal_obj_get_fails", metrics.Counter)
|
||||
internalObjGetDuration, _ = registry.NewMetric("s3local_internal_obj_get_duration", metrics.Trend, metrics.Time)
|
||||
|
||||
objPutTotal, _ = registry.NewMetric("s3local_obj_put_total", metrics.Counter)
|
||||
objPutFails, _ = registry.NewMetric("s3local_obj_put_fails", metrics.Counter)
|
||||
objPutDuration, _ = registry.NewMetric("s3local_obj_put_duration", metrics.Trend, metrics.Time)
|
||||
|
||||
objGetTotal, _ = registry.NewMetric("s3local_obj_get_total", metrics.Counter)
|
||||
objGetFails, _ = registry.NewMetric("s3local_obj_get_fails", metrics.Counter)
|
||||
objGetDuration, _ = registry.NewMetric("s3local_obj_get_duration", metrics.Trend, metrics.Time)
|
||||
|
||||
// Create S3 layer backed by local storage engine and tree service.
|
||||
ng, err := s.l.ResolveEngine(s.l.VU().Context(), configFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connecting to engine for config %q: %v", configFile, err)
|
||||
}
|
||||
|
||||
treeSvc := tree.NewTree(treeServiceEngineWrapper{
|
||||
ng: ng,
|
||||
pos: *nodePosition,
|
||||
size: *nodeCount,
|
||||
})
|
||||
|
||||
rc := rawclient.New(ng,
|
||||
rawclient.WithKey(key.PrivateKey),
|
||||
rawclient.WithPutHandler(func(sz uint64, err error, dt time.Duration) {
|
||||
if err != nil {
|
||||
stats.Report(s.l.VU(), internalObjPutFails, 1)
|
||||
} else {
|
||||
stats.Report(s.l.VU(), internalObjPutTotal, 1)
|
||||
stats.Report(s.l.VU(), internalObjPutDuration, metrics.D(dt))
|
||||
}
|
||||
}),
|
||||
rawclient.WithGetHandler(func(sz uint64, err error, dt time.Duration) {
|
||||
if err != nil {
|
||||
stats.Report(s.l.VU(), internalObjGetFails, 1)
|
||||
} else {
|
||||
stats.Report(s.l.VU(), internalObjGetTotal, 1)
|
||||
stats.Report(s.l.VU(), internalObjGetDuration, metrics.D(dt))
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
resolver, err := newFixedBucketResolver(bucketMapping)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating bucket resolver: %v", err)
|
||||
}
|
||||
|
||||
cfg := &layer.Config{
|
||||
Caches: layer.DefaultCachesConfigs(zap.L()),
|
||||
AnonKey: layer.AnonymousKey{Key: key},
|
||||
Resolver: resolver,
|
||||
TreeService: treeSvc,
|
||||
}
|
||||
|
||||
l := layer.NewLayer(zap.L(), &frostfs{rc}, cfg)
|
||||
l.Initialize(s.l.VU().Context(), nopEventListener{})
|
||||
|
||||
return &Client{
|
||||
vu: s.l.VU(),
|
||||
l: l,
|
||||
ownerID: rc.OwnerID(),
|
||||
resolver: resolver,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type nopEventListener struct{}
|
||||
|
||||
func (nopEventListener) Subscribe(context.Context, string, layer.MsgHandler) error { return nil }
|
||||
func (nopEventListener) Listen(context.Context) {}
|
32
internal/s3local/resolver.go
Normal file
32
internal/s3local/resolver.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package s3local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
)
|
||||
|
||||
// fixedBucketResolver is a static bucket resolver from the provided map.
|
||||
// This is needed to replace the normal resolver for local storage engine clients, since
|
||||
// those should not use DNS or NNS for resolution.
|
||||
type fixedBucketResolver map[string]cid.ID
|
||||
|
||||
func newFixedBucketResolver(bucketMapping map[string]string) (fixedBucketResolver, error) {
|
||||
r := fixedBucketResolver{}
|
||||
for bucket, cidStr := range bucketMapping {
|
||||
var id cid.ID
|
||||
if err := id.DecodeString(cidStr); err != nil {
|
||||
return nil, fmt.Errorf("decoding container id %q: %v", cidStr, err)
|
||||
}
|
||||
r[bucket] = id
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r fixedBucketResolver) Resolve(_ context.Context, bucket string) (cid.ID, error) {
|
||||
if cid, resolved := r[bucket]; resolved {
|
||||
return cid, nil
|
||||
}
|
||||
return cid.ID{}, fmt.Errorf("bucket %s is not mapped to any container", bucket)
|
||||
}
|
211
internal/s3local/treeService.go
Normal file
211
internal/s3local/treeService.go
Normal file
|
@ -0,0 +1,211 @@
|
|||
package s3local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||
)
|
||||
|
||||
// treeServiceEngineWrapper implements the basic functioning of tree service using
|
||||
// only the local storage engine instance. The node position and count is fixed
|
||||
// beforehand in order to coordinate multiple runs on different nodes of the same
|
||||
// cluster.
|
||||
//
|
||||
// The implementation mostly emulates the following
|
||||
//
|
||||
// - https://git.frostfs.info/TrueCloudLab/frostfs-node/src/branch/master/pkg/services/tree/service.go
|
||||
// - https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/src/branch/master/internal/frostfs/services/tree_client_grpc.go
|
||||
//
|
||||
// but skips details which are irrelevant for local storage engine-backed clients.
|
||||
type treeServiceEngineWrapper struct {
|
||||
ng *engine.StorageEngine
|
||||
pos int
|
||||
size int
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
k string
|
||||
v []byte
|
||||
}
|
||||
|
||||
func (kv kv) GetKey() string { return kv.k }
|
||||
func (kv kv) GetValue() []byte { return kv.v }
|
||||
|
||||
type nodeResponse struct {
|
||||
meta []tree.Meta
|
||||
nodeID uint64
|
||||
parentID uint64
|
||||
ts uint64
|
||||
}
|
||||
|
||||
func (r nodeResponse) GetMeta() []tree.Meta { return r.meta }
|
||||
func (r nodeResponse) GetNodeID() uint64 { return r.nodeID }
|
||||
func (r nodeResponse) GetParentID() uint64 { return r.parentID }
|
||||
func (r nodeResponse) GetTimestamp() uint64 { return r.ts }
|
||||
|
||||
func (s treeServiceEngineWrapper) GetNodes(ctx context.Context, p *tree.GetNodesParams) ([]tree.NodeResponse, error) {
|
||||
nodeIDs, err := s.ng.TreeGetByPath(p.BktInfo.CID, p.TreeID, pilorama.AttributeFilename, p.Path, p.LatestOnly)
|
||||
if err != nil {
|
||||
if errors.Is(err, pilorama.ErrTreeNotFound) {
|
||||
// This is needed in order for the tree implementation to create the tree/node
|
||||
// if it doesn't exist already.
|
||||
// See: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/src/branch/master/internal/frostfs/services/tree_client_grpc.go#L306
|
||||
return nil, tree.ErrNodeNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resps := make([]tree.NodeResponse, 0, len(nodeIDs))
|
||||
for _, nodeID := range nodeIDs {
|
||||
m, parentID, err := s.ng.TreeGetMeta(p.BktInfo.CID, p.TreeID, nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := nodeResponse{
|
||||
parentID: parentID,
|
||||
nodeID: nodeID,
|
||||
ts: m.Time,
|
||||
}
|
||||
if p.AllAttrs {
|
||||
resp.meta = kvToTreeMeta(m.Items)
|
||||
} else {
|
||||
for _, it := range m.Items {
|
||||
for _, attr := range p.Meta {
|
||||
if it.Key == attr {
|
||||
resp.meta = append(resp.meta, kv{it.Key, it.Value})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
resps = append(resps, resp)
|
||||
}
|
||||
|
||||
return resps, nil
|
||||
}
|
||||
|
||||
func (s treeServiceEngineWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID uint64, depth uint32) ([]tree.NodeResponse, error) {
|
||||
var resps []tree.NodeResponse
|
||||
|
||||
var traverse func(nodeID uint64, curDepth uint32) error
|
||||
traverse = func(nodeID uint64, curDepth uint32) error {
|
||||
m, parentID, err := s.ng.TreeGetMeta(bktInfo.CID, treeID, nodeID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting meta: %v", err)
|
||||
}
|
||||
|
||||
resps = append(resps, nodeResponse{
|
||||
nodeID: nodeID,
|
||||
parentID: parentID,
|
||||
ts: m.Time,
|
||||
meta: kvToTreeMeta(m.Items),
|
||||
})
|
||||
|
||||
if curDepth >= depth {
|
||||
return nil
|
||||
}
|
||||
|
||||
children, err := s.ng.TreeGetChildren(bktInfo.CID, treeID, nodeID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting children: %v", err)
|
||||
}
|
||||
for _, child := range children {
|
||||
if err := traverse(child, curDepth+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := traverse(rootID, 0); err != nil {
|
||||
return nil, fmt.Errorf("traversing: %v", err)
|
||||
}
|
||||
|
||||
return resps, nil
|
||||
}
|
||||
|
||||
func (s treeServiceEngineWrapper) AddNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, parentID uint64, meta map[string]string) (uint64, error) {
|
||||
desc := pilorama.CIDDescriptor{
|
||||
CID: bktInfo.CID,
|
||||
Position: s.pos,
|
||||
Size: s.size,
|
||||
}
|
||||
mv, err := s.ng.TreeMove(desc, treeID, &pilorama.Move{
|
||||
Parent: parentID,
|
||||
Child: pilorama.RootID,
|
||||
Meta: pilorama.Meta{Items: mapToKV(meta)},
|
||||
})
|
||||
return mv.Child, err
|
||||
}
|
||||
|
||||
func (s treeServiceEngineWrapper) AddNodeByPath(ctx context.Context, bktInfo *data.BucketInfo, treeID string, path []string, meta map[string]string) (uint64, error) {
|
||||
desc := pilorama.CIDDescriptor{
|
||||
CID: bktInfo.CID,
|
||||
Position: s.pos,
|
||||
Size: s.size,
|
||||
}
|
||||
mvs, err := s.ng.TreeAddByPath(desc, treeID, pilorama.AttributeFilename, path, mapToKV(meta))
|
||||
if err != nil {
|
||||
return pilorama.TrashID, err
|
||||
}
|
||||
return mvs[len(mvs)-1].Child, nil
|
||||
}
|
||||
|
||||
func (s treeServiceEngineWrapper) MoveNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID, parentID uint64, meta map[string]string) error {
|
||||
if nodeID == pilorama.RootID {
|
||||
return fmt.Errorf("node with ID %d is the root and can't be moved", nodeID)
|
||||
}
|
||||
desc := pilorama.CIDDescriptor{
|
||||
CID: bktInfo.CID,
|
||||
Position: s.pos,
|
||||
Size: s.size,
|
||||
}
|
||||
_, err := s.ng.TreeMove(desc, treeID, &pilorama.Move{
|
||||
Parent: parentID,
|
||||
Child: nodeID,
|
||||
Meta: pilorama.Meta{
|
||||
Items: mapToKV(meta),
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s treeServiceEngineWrapper) RemoveNode(ctx context.Context, bktInfo *data.BucketInfo, treeID string, nodeID uint64) error {
|
||||
if nodeID == pilorama.RootID {
|
||||
return fmt.Errorf("node with ID %d is the root and can't be removed", nodeID)
|
||||
}
|
||||
desc := pilorama.CIDDescriptor{
|
||||
CID: bktInfo.CID,
|
||||
Position: s.pos,
|
||||
Size: s.size,
|
||||
}
|
||||
_, err := s.ng.TreeMove(desc, treeID, &pilorama.Move{
|
||||
Parent: pilorama.TrashID,
|
||||
Child: nodeID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func mapToKV(m map[string]string) []pilorama.KeyValue {
|
||||
var kvs []pilorama.KeyValue
|
||||
for k, v := range m {
|
||||
kvs = append(kvs, pilorama.KeyValue{
|
||||
Key: k,
|
||||
Value: []byte(v),
|
||||
})
|
||||
}
|
||||
return kvs
|
||||
}
|
||||
|
||||
func kvToTreeMeta(x []pilorama.KeyValue) []tree.Meta {
|
||||
ret := make([]tree.Meta, 0, len(x))
|
||||
for _, x := range x {
|
||||
ret = append(ret, kv{x.Key, x.Value})
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -11,9 +11,9 @@ def create_bucket(endpoint, versioning, location):
|
|||
bucket_name = str(uuid.uuid4())
|
||||
|
||||
cmd_line = f"aws --no-verify-ssl s3api create-bucket --bucket {bucket_name} " \
|
||||
f"--endpoint http://{endpoint} {location}"
|
||||
f"--endpoint https://{endpoint} {location}"
|
||||
cmd_line_ver = f"aws --no-verify-ssl s3api put-bucket-versioning --bucket {bucket_name} " \
|
||||
f"--versioning-configuration Status=Enabled --endpoint http://{endpoint} "
|
||||
f"--versioning-configuration Status=Enabled --endpoint https://{endpoint} "
|
||||
|
||||
out, success = execute_cmd(cmd_line)
|
||||
|
||||
|
@ -21,7 +21,7 @@ def create_bucket(endpoint, versioning, location):
|
|||
if "succeeded and you already own it" in out:
|
||||
bucket_create_marker = True
|
||||
else:
|
||||
print(f" > Bucket {bucket_name} has not been created.")
|
||||
print(f" > Bucket {bucket_name} has not been created:\n{out}")
|
||||
else:
|
||||
bucket_create_marker = True
|
||||
print(f"cmd: {cmd_line}")
|
||||
|
@ -29,7 +29,7 @@ def create_bucket(endpoint, versioning, location):
|
|||
if bucket_create_marker and versioning == "True":
|
||||
out, success = execute_cmd(cmd_line_ver)
|
||||
if not success:
|
||||
print(f" > Bucket versioning has not been applied for bucket {bucket_name}.")
|
||||
print(f" > Bucket versioning has not been applied for bucket {bucket_name}:\n{out}")
|
||||
else:
|
||||
print(f" > Bucket versioning has been applied.")
|
||||
|
||||
|
@ -39,8 +39,8 @@ def create_bucket(endpoint, versioning, location):
|
|||
def upload_object(bucket, payload_filepath, endpoint):
|
||||
object_name = str(uuid.uuid4())
|
||||
|
||||
cmd_line = f"aws s3api put-object --bucket {bucket} --key {object_name} " \
|
||||
f"--body {payload_filepath} --endpoint http://{endpoint}"
|
||||
cmd_line = f"aws --no-verify-ssl s3api put-object --bucket {bucket} --key {object_name} " \
|
||||
f"--body {payload_filepath} --endpoint https://{endpoint}"
|
||||
out, success = execute_cmd(cmd_line)
|
||||
|
||||
if not success:
|
||||
|
|
29
scenarios/preset/resolve_containers_in_preset.py
Executable file
29
scenarios/preset/resolve_containers_in_preset.py
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import requests
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--endpoint', help='Endpoint of the S3 gateway')
|
||||
parser.add_argument('--preset_file', help='JSON file path with s3 preset')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
def main():
|
||||
with open(args.preset_file) as f:
|
||||
preset_text = f.read()
|
||||
|
||||
preset = json.loads(preset_text)
|
||||
|
||||
containers = []
|
||||
for bucket in preset.get('buckets'):
|
||||
resp = requests.head(f'{args.endpoint}/{bucket}', verify=False)
|
||||
containers.append(resp.headers['X-Container-Id'])
|
||||
|
||||
preset['containers'] = containers
|
||||
with open(args.preset_file, 'w+') as f:
|
||||
json.dump(preset, f, ensure_ascii=False, indent=2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -6,7 +6,7 @@
|
|||
$ ./k6 run -e ENV_FILE=.env some-scenario.js
|
||||
```
|
||||
|
||||
## Common options for gRPC, local, HTTP, S3 scenarios:
|
||||
## Common options for all scenarios:
|
||||
|
||||
Scenarios `grpc.js`, `local.js`, `http.js` and `s3.js` support the following options:
|
||||
* `DURATION` - duration of scenario in seconds.
|
||||
|
@ -124,6 +124,29 @@ Options (in addition to the common options):
|
|||
* `SLEEP_DELETE` - time interval (in seconds) between deleting VU iterations.
|
||||
* `OBJ_NAME` - if specified, this name will be used for all write operations instead of random generation.
|
||||
|
||||
## S3 Local
|
||||
|
||||
1. Follow steps 1. and 2. from the normal S3 scenario in order to obtain credentials and a preset file with the information about the buckets and objects that were pre-created.
|
||||
2. Assuming the preset file was named `pregen.json`, we need to populate the bucket-to-container mapping before running the local S3 scenario:
|
||||
|
||||
**WARNING**: Be aware that this command will overwrite the `containers` list field in `pregen.json` file. Make a backup if needed beforehand.
|
||||
|
||||
```shell
|
||||
$ ./scenarios/preset/resolve_containers_in_preset.py --endpoint s3host:8080 --preset_file pregen.json
|
||||
```
|
||||
|
||||
After this, the `pregen.json` file will contain a `containers` list field the same length as `buckets`, which is the mapping of bucket name to container ID in the order they appear.
|
||||
|
||||
3. Execute the scenario with the desired options. For example:
|
||||
```shell
|
||||
$ ./k6 run -e DURATION=60 -e WRITE_OBJ_SIZE=8192 -e READERS=20 -e WRITERS=20 -e CONFIG_FILE=/path/to/node/config.yml -e PREGEN_JSON=pregen.json scenarios/s3local.js
|
||||
```
|
||||
|
||||
Note that the `s3local` scenario currently does not support deleters.
|
||||
|
||||
Options (in addition to the common options):
|
||||
* `OBJ_NAME` - if specified, this name will be used for all write operations instead of random generation.
|
||||
|
||||
## Verify
|
||||
|
||||
This scenario allows to verify that objects created by a previous run are really stored in the system and their data is not corrupted. Running this scenario assumes that you've already run gRPC or HTTP or S3 scenario with option `REGISTRY_FILE`.
|
||||
|
|
132
scenarios/s3local.js
Normal file
132
scenarios/s3local.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
import datagen from 'k6/x/frostfs/datagen';
|
||||
import logging from 'k6/x/frostfs/logging';
|
||||
import registry from 'k6/x/frostfs/registry';
|
||||
import s3local from 'k6/x/frostfs/s3local';
|
||||
import { SharedArray } from 'k6/data';
|
||||
import { textSummary } from './libs/k6-summary-0.0.2.js';
|
||||
import { parseEnv } from './libs/env-parser.js';
|
||||
|
||||
parseEnv();
|
||||
|
||||
const obj_list = new SharedArray('obj_list', function () {
|
||||
return JSON.parse(open(__ENV.PREGEN_JSON)).objects;
|
||||
});
|
||||
|
||||
const container_list = new SharedArray('container_list', function () {
|
||||
return JSON.parse(open(__ENV.PREGEN_JSON)).containers;
|
||||
});
|
||||
|
||||
const bucket_list = new SharedArray('bucket_list', function () {
|
||||
return JSON.parse(open(__ENV.PREGEN_JSON)).buckets;
|
||||
});
|
||||
|
||||
function bucket_mapping() {
|
||||
if (container_list.length != bucket_list.length) {
|
||||
throw 'The number of containers and buckets in the preset file must be the same.';
|
||||
}
|
||||
let mapping = {};
|
||||
for (let i = 0; i < container_list.length; ++i) {
|
||||
mapping[bucket_list[i]] = container_list[i];
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
const read_size = JSON.parse(open(__ENV.PREGEN_JSON)).obj_size;
|
||||
const summary_json = __ENV.SUMMARY_JSON || "/tmp/summary.json";
|
||||
|
||||
const config_file = __ENV.CONFIG_FILE;
|
||||
const s3_client = s3local.connect(config_file, {}, bucket_mapping());
|
||||
const log = logging.new().withField("config", config_file);
|
||||
|
||||
const registry_enabled = !!__ENV.REGISTRY_FILE;
|
||||
const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;
|
||||
|
||||
const duration = __ENV.DURATION;
|
||||
|
||||
const generator = datagen.generator(1024 * parseInt(__ENV.WRITE_OBJ_SIZE));
|
||||
|
||||
const scenarios = {};
|
||||
|
||||
const write_vu_count = parseInt(__ENV.WRITERS || '0');
|
||||
if (write_vu_count > 0) {
|
||||
scenarios.write = {
|
||||
executor: 'constant-vus',
|
||||
vus: write_vu_count,
|
||||
duration: `${duration}s`,
|
||||
exec: 'obj_write',
|
||||
gracefulStop: '5s',
|
||||
};
|
||||
}
|
||||
|
||||
const read_vu_count = parseInt(__ENV.READERS || '0');
|
||||
if (read_vu_count > 0) {
|
||||
scenarios.read = {
|
||||
executor: 'constant-vus',
|
||||
vus: read_vu_count,
|
||||
duration: `${duration}s`,
|
||||
exec: 'obj_read',
|
||||
gracefulStop: '5s',
|
||||
};
|
||||
}
|
||||
|
||||
export const options = {
|
||||
scenarios,
|
||||
setupTimeout: '5s',
|
||||
};
|
||||
|
||||
export function setup() {
|
||||
const total_vu_count = write_vu_count + read_vu_count;
|
||||
|
||||
console.log(`Pregenerated buckets: ${bucket_list.length}`);
|
||||
console.log(`Pregenerated read object size: ${read_size}`);
|
||||
console.log(`Pregenerated total objects: ${obj_list.length}`);
|
||||
console.log(`Reading VUs: ${read_vu_count}`);
|
||||
console.log(`Writing VUs: ${write_vu_count}`);
|
||||
console.log(`Total VUs: ${total_vu_count}`);
|
||||
}
|
||||
|
||||
export function teardown(data) {
|
||||
if (obj_registry) {
|
||||
obj_registry.close();
|
||||
}
|
||||
}
|
||||
|
||||
export function handleSummary(data) {
|
||||
return {
|
||||
'stdout': textSummary(data, { indent: ' ', enableColors: false }),
|
||||
[summary_json]: JSON.stringify(data),
|
||||
};
|
||||
}
|
||||
|
||||
export function obj_write() {
|
||||
const key = __ENV.OBJ_NAME || uuidv4();
|
||||
const bucket = bucket_list[Math.floor(Math.random() * bucket_list.length)];
|
||||
|
||||
const { payload, hash } = generator.genPayload(registry_enabled);
|
||||
const resp = s3_client.put(bucket, key, payload);
|
||||
if (!resp.success) {
|
||||
log.withFields({bucket: bucket, key: key}).error(resp.error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj_registry) {
|
||||
obj_registry.addObject("", "", bucket, key, hash);
|
||||
}
|
||||
}
|
||||
|
||||
export function obj_read() {
|
||||
const obj = obj_list[Math.floor(Math.random() * obj_list.length)];
|
||||
|
||||
const resp = s3_client.get(obj.bucket, obj.object);
|
||||
if (!resp.success) {
|
||||
log.withFields({bucket: obj.bucket, key: obj.object}).error(resp.error);
|
||||
}
|
||||
}
|
||||
|
||||
export function uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in a new issue