feature/add_multipart #80
11 changed files with 365 additions and 12 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
k6
|
||||
*.bolt
|
||||
presets
|
||||
bin
|
||||
|
|
94
Makefile
Normal file
94
Makefile
Normal file
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
# Common variables
|
||||
REPO ?= $(shell go list -m)
|
||||
VERSION ?= $(shell git describe --tags --dirty --match "v*" --always --abbrev=8 2>/dev/null || cat VERSION 2>/dev/null || echo "develop")
|
||||
GO_VERSION ?= 1.19
|
||||
LINT_VERSION ?= 1.49.0
|
||||
BINDIR = bin
|
||||
|
||||
# Binaries to build
|
||||
CMDS = $(addprefix frostfs-, $(notdir $(wildcard cmd/*)))
|
||||
BINS = $(addprefix $(BINDIR)/, $(CMDS))
|
||||
|
||||
.PHONY: all $(BINS) $(BINDIR) dep docker/ test cover format lint docker/lint pre-commit unpre-commit version clean
|
||||
|
||||
# Make all binaries
|
||||
all: $(BINS)
|
||||
|
||||
$(BINS): $(BINDIR) dep
|
||||
@echo "⇒ Build $@"
|
||||
CGO_ENABLED=0 \
|
||||
go build -v -trimpath \
|
||||
-ldflags "-X $(REPO)/internal/version.Version=$(VERSION)" \
|
||||
-o $@ ./cmd/$(subst frostfs-,,$(notdir $@))
|
||||
|
||||
$(BINDIR):
|
||||
@echo "⇒ Ensure dir: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
# Pull go dependencies
|
||||
dep:
|
||||
@printf "⇒ Download requirements: "
|
||||
@CGO_ENABLED=0 \
|
||||
go mod download && echo OK
|
||||
@printf "⇒ Tidy requirements: "
|
||||
@CGO_ENABLED=0 \
|
||||
go mod tidy -v && echo OK
|
||||
|
||||
# Run `make %` in Golang container, for more information run `make help.docker/%`
|
||||
docker/%:
|
||||
$(if $(filter $*,all $(BINS)), \
|
||||
@echo "=> Running 'make $*' in clean Docker environment" && \
|
||||
docker run --rm -t \
|
||||
-v `pwd`:/src \
|
||||
-w /src \
|
||||
-u `stat -c "%u:%g" .` \
|
||||
--env HOME=/src \
|
||||
golang:$(GO_VERSION) make $*,\
|
||||
@echo "supported docker targets: all $(BINS) lint")
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
@go test ./... -cover
|
||||
|
||||
# Run tests with race detection and produce coverage output
|
||||
cover:
|
||||
@go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic
|
||||
@go tool cover -html=coverage.txt -o coverage.html
|
||||
|
||||
# Reformat code
|
||||
format:
|
||||
@echo "⇒ Processing gofmt check"
|
||||
@gofmt -s -w ./
|
||||
|
||||
# Run linters
|
||||
lint:
|
||||
@golangci-lint --timeout=5m run
|
||||
|
||||
# Run linters in Docker
|
||||
docker/lint:
|
||||
docker run --rm -it \
|
||||
-v `pwd`:/src \
|
||||
-u `stat -c "%u:%g" .` \
|
||||
--env HOME=/src \
|
||||
golangci/golangci-lint:v$(LINT_VERSION) bash -c 'cd /src/ && make lint'
|
||||
|
||||
# Activate pre-commit hooks
|
||||
pre-commit:
|
||||
pre-commit install -t pre-commit -t commit-msg
|
||||
|
||||
# Deactivate pre-commit hooks
|
||||
unpre-commit:
|
||||
pre-commit uninstall -t pre-commit -t commit-msg
|
||||
|
||||
# Show current version
|
||||
version:
|
||||
@echo $(VERSION)
|
||||
|
||||
# Clean up files
|
||||
clean:
|
||||
rm -rf .cache
|
||||
rm -rf $(BINDIR)
|
||||
|
||||
include help.mk
|
35
README.md
35
README.md
|
@ -148,6 +148,41 @@ const local_client = local.connect("/path/to/config.yaml", params, bucketMapping
|
|||
|
||||
See native protocol and s3 test suite examples in [examples](./examples) dir.
|
||||
|
||||
# Command line utils
|
||||
|
||||
To build all command line utils just run:
|
||||
|
||||
```shell
|
||||
$ make
|
||||
```
|
||||
|
||||
All binaries will be in `bin` directory.
|
||||
|
||||
## Export registry db
|
||||
|
||||
You can export registry bolt db to json file, that can be used as pregen for scenarios (see [docs](./scenarios/run_scenarios.md)).
|
||||
To do this use `frostfs-xk6-registry-exporter`, available flags can be seen in help:
|
||||
|
||||
```shell
|
||||
$ ./bin/frostfs-xk6-registry-exporter -h
|
||||
Registry exporter for xk6
|
||||
|
||||
Usage:
|
||||
registry-exporter [flags]
|
||||
|
||||
Examples:
|
||||
registry-exporter registry.bolt
|
||||
registry-exporter --status created --out out.json registry.bolt
|
||||
|
||||
Flags:
|
||||
--age int Object age
|
||||
--format string Output format (default "json")
|
||||
-h, --help help for registry-exporter
|
||||
--out string Path to output file (default "dumped-registry.json")
|
||||
--status string Object status (default "created")
|
||||
-v, --version version for registry-exporter
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
- [GNU General Public License v3.0](LICENSE)
|
||||
|
|
18
cmd/xk6-registry-exporter/main.go
Normal file
18
cmd/xk6-registry-exporter/main.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
|
||||
if cmd, err := rootCmd.ExecuteContextC(ctx); err != nil {
|
||||
cmd.PrintErrln("Error:", err.Error())
|
||||
cmd.PrintErrf("Run '%v --help' for usage.\n", cmd.CommandPath())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
89
cmd/xk6-registry-exporter/root.go
Normal file
89
cmd/xk6-registry-exporter/root.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/registry"
|
||||
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "registry-exporter",
|
||||
Version: version.Version,
|
||||
Short: "Registry exporter",
|
||||
Long: "Registry exporter for xk6",
|
||||
Example: `registry-exporter registry.bolt
|
||||
registry-exporter --status created --out out.json registry.bolt`,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: rootCmdRun,
|
||||
}
|
||||
|
||||
const (
|
||||
outFlag = "out"
|
||||
formatFlag = "format"
|
||||
statusFlag = "status"
|
||||
ageFlag = "age"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultOutPath = "dumped-registry.json"
|
||||
|
||||
jsonFormat = "json"
|
||||
|
||||
createdStatus = "created"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.Flags().String(outFlag, defaultOutPath, "Path to output file")
|
||||
rootCmd.Flags().String(formatFlag, jsonFormat, "Output format")
|
||||
rootCmd.Flags().String(statusFlag, createdStatus, "Object status")
|
||||
rootCmd.Flags().Int(ageFlag, 0, "Object age")
|
||||
|
||||
cobra.AddTemplateFunc("runtimeVersion", runtime.Version)
|
||||
rootCmd.SetVersionTemplate(`FrostFS xk6 Registry Exporter
|
||||
{{printf "Version: %s" .Version }}
|
||||
GoVersion: {{ runtimeVersion }}
|
||||
`)
|
||||
}
|
||||
|
||||
func rootCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return fmt.Errorf("expected exacly one non-flag argumet: path to the registry, got: %s", args)
|
||||
}
|
||||
|
||||
format, err := cmd.Flags().GetString(formatFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get '%s' flag: %w", formatFlag, err)
|
||||
}
|
||||
if format != jsonFormat {
|
||||
return fmt.Errorf("unknown format '%s', only '%s' is supported", format, jsonFormat)
|
||||
}
|
||||
|
||||
out, err := cmd.Flags().GetString(outFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get '%s' flag: %w", outFlag, err)
|
||||
}
|
||||
|
||||
status, err := cmd.Flags().GetString(statusFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get '%s' flag: %w", statusFlag, err)
|
||||
}
|
||||
|
||||
age, err := cmd.Flags().GetInt(ageFlag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get '%s' flag: %w", ageFlag, err)
|
||||
}
|
||||
|
||||
objRegistry := registry.NewObjRegistry(cmd.Context(), args[0])
|
||||
objSelector := registry.NewObjSelector(objRegistry, 0, ®istry.ObjFilter{
|
||||
Status: status,
|
||||
Age: age,
|
||||
})
|
||||
objExporter := registry.NewObjExporter(objSelector)
|
||||
|
||||
cmd.Println("Writing result file:", out)
|
||||
return objExporter.ExportJSONPreGen(out)
|
||||
}
|
26
go.mod
26
go.mod
|
@ -18,6 +18,7 @@ require (
|
|||
github.com/nspcc-dev/neo-go v0.101.2
|
||||
github.com/panjf2000/ants/v2 v2.8.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
go.k6.io/k6 v0.45.0
|
||||
|
@ -34,19 +35,19 @@ require (
|
|||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.296 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bluele/gcache v0.0.2 // indirect
|
||||
|
@ -67,6 +68,7 @@ require (
|
|||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
22
help.mk
Normal file
22
help.mk
Normal file
|
@ -0,0 +1,22 @@
|
|||
.PHONY: help
|
||||
|
||||
# Show this help prompt
|
||||
help:
|
||||
@echo ' Usage:'
|
||||
@echo ''
|
||||
@echo ' make <target>'
|
||||
@echo ''
|
||||
@echo ' Targets:'
|
||||
@echo ''
|
||||
@awk '/^#/{ comment = substr($$0,3) } comment && /^[a-zA-Z][a-zA-Z0-9.%_/-]+ ?:/{ print " ", $$1, comment }' $(MAKEFILE_LIST) | column -t -s ':' | grep -v 'IGNORE' | sort | uniq
|
||||
|
||||
# Show help for docker/% IGNORE
|
||||
help.docker/%:
|
||||
$(eval TARGETS:=$(notdir all lint) ${BINS})
|
||||
@echo ' Usage:'
|
||||
@echo ''
|
||||
@echo ' make docker/% -- Run `make %` in Golang container'
|
||||
@echo ''
|
||||
@echo ' Supported docker targets:'
|
||||
@echo ''
|
||||
@$(foreach bin, $(TARGETS), echo ' ' $(bin);)
|
82
internal/registry/obj_exporter.go
Normal file
82
internal/registry/obj_exporter.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ObjExporter struct {
|
||||
selector *ObjSelector
|
||||
}
|
||||
|
||||
type PreGenerateInfo struct {
|
||||
Buckets []string `json:"buckets"`
|
||||
Objects []ObjInfo `json:"objects"`
|
||||
ObjSize string `json:"obj_size"`
|
||||
}
|
||||
|
||||
type ObjInfo struct {
|
||||
Bucket string `json:"bucket"`
|
||||
Object string `json:"object"`
|
||||
}
|
||||
|
||||
func NewObjExporter(selector *ObjSelector) *ObjExporter {
|
||||
return &ObjExporter{selector: selector}
|
||||
}
|
||||
|
||||
func (o *ObjExporter) ExportJSONPreGen(fileName string) error {
|
||||
f, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// there can be a lot of object, so manually form json
|
||||
if _, err = f.WriteString(`{"objects":[`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bucketMap := make(map[string]struct{})
|
||||
|
||||
count, err := o.selector.Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var comma string
|
||||
for i := 0; i < count; i++ {
|
||||
info := o.selector.NextObject()
|
||||
if info == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if _, err = f.WriteString(fmt.Sprintf(`%s{"bucket":"%s","object":"%s"}`, comma, info.S3Bucket, info.S3Key)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
comma = ","
|
||||
}
|
||||
|
||||
bucketMap[info.S3Bucket] = struct{}{}
|
||||
}
|
||||
|
||||
if _, err = f.WriteString(`],"buckets":[`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i := 0
|
||||
comma = ""
|
||||
for bucket := range bucketMap {
|
||||
if _, err = f.WriteString(fmt.Sprintf(`%s"%s"`, comma, bucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
if i == 0 {
|
||||
comma = ","
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
_, err = f.WriteString(`]}`)
|
||||
return err
|
||||
}
|
|
@ -94,6 +94,10 @@ func (r *Registry) GetSelector(dbFilePath string, name string, cacheSize int, fi
|
|||
return selector
|
||||
}
|
||||
|
||||
func (r *Registry) GetExporter(selector *ObjSelector) *ObjExporter {
|
||||
return NewObjExporter(selector)
|
||||
}
|
||||
|
||||
func parseFilter(filter map[string]string) (*ObjFilter, error) {
|
||||
objFilter := ObjFilter{}
|
||||
objFilter.Status = filter["status"]
|
||||
|
|
6
internal/version/version.go
Normal file
6
internal/version/version.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package version
|
||||
|
||||
var (
|
||||
// Version is the xk6 command-line utils version.
|
||||
Version = "dev"
|
||||
)
|
Loading…
Reference in a new issue