From 1c94b626c86ab0b8dc5b876864792fe34a0a43c4 Mon Sep 17 00:00:00 2001 From: hudeng Date: Tue, 8 Feb 2022 11:16:16 +0800 Subject: [PATCH 01/12] feat: Add etcd database support improve concurrent access and high availability of aptly with the help of the characteristics of etcd --- AUTHORS | 2 + Makefile | 13 +- context/context.go | 8 +- database/etcddb/batch.go | 34 +++++ database/etcddb/database.go | 45 +++++++ database/etcddb/database_test.go | 156 +++++++++++++++++++++++ database/etcddb/storage.go | 163 ++++++++++++++++++++++++ database/etcddb/transaction.go | 55 ++++++++ go.mod | 11 ++ man/aptly.1.ronn.tmpl | 4 + system/t02_config/ConfigShowTest_gold | 3 +- system/t02_config/CreateConfigTest_gold | 5 +- utils/config.go | 1 + utils/config_test.go | 3 +- 14 files changed, 497 insertions(+), 6 deletions(-) create mode 100644 database/etcddb/batch.go create mode 100644 database/etcddb/database.go create mode 100644 database/etcddb/database_test.go create mode 100644 database/etcddb/storage.go create mode 100644 database/etcddb/transaction.go diff --git a/AUTHORS b/AUTHORS index 3962217bb..70a75464b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -61,3 +61,5 @@ List of contributors, in chronological order: * iofq (https://github.com/iofq) * Noa Resare (https://github.com/nresare) * Ramón N.Rodriguez (https://github.com/runitonmetal) +* Golf Hu (https://github.com/hudeng-go) +* Cookie Fei (https://github.com/wuhuang26) diff --git a/Makefile b/Makefile index 736e1597f..217b8c82e 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,10 @@ COVERAGE_DIR?=$(shell mktemp -d) # Uncomment to update test outputs # CAPTURE := "--capture" +# etcd test env +ETCD_VER=v3.5.2 +DOWNLOAD_URL=https://storage.googleapis.com/etcd + all: modules test bench check system-test # Self-documenting Makefile @@ -22,6 +26,13 @@ help: ## Print this help prepare: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin $(GOLANGCI_LINT_VERSION) +etcd-prepare: + # etcd test prepare + rm -rf /tmp/etcd-download-test/test-data && mkdir -p /tmp/etcd-download-test/test-data + if [ ! -e /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz ]; then curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz; fi + tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1 + /tmp/etcd-download-test/etcd --data-dir /tmp/etcd-download-test/test-data & + modules: go mod download go mod verify @@ -68,7 +79,7 @@ docker-test: install export APTLY_VERSION=$(VERSION); \ $(PYTHON) system/run.py --long $(TESTS) --coverage-dir $(COVERAGE_DIR) $(CAPTURE) $(TEST) -test: +test: etcd-prepare go test -v ./... -gocheck.v=true -coverprofile=unit.out bench: diff --git a/context/context.go b/context/context.go index b6040f3b7..7f17b84d9 100644 --- a/context/context.go +++ b/context/context.go @@ -18,6 +18,7 @@ import ( "github.com/aptly-dev/aptly/azure" "github.com/aptly-dev/aptly/console" "github.com/aptly-dev/aptly/database" + "github.com/aptly-dev/aptly/database/etcddb" "github.com/aptly-dev/aptly/database/goleveldb" "github.com/aptly-dev/aptly/deb" "github.com/aptly-dev/aptly/files" @@ -288,7 +289,12 @@ func (context *AptlyContext) _database() (database.Storage, error) { if context.database == nil { var err error - context.database, err = goleveldb.NewDB(context.dbPath()) + if context.config().DatabaseEtcd != "" { + context.database, err = etcddb.NewDB(context.config().DatabaseEtcd) + } else { + context.database, err = goleveldb.NewDB(context.dbPath()) + } + if err != nil { return nil, fmt.Errorf("can't instantiate database: %s", err) } diff --git a/database/etcddb/batch.go b/database/etcddb/batch.go new file mode 100644 index 000000000..e50c11624 --- /dev/null +++ b/database/etcddb/batch.go @@ -0,0 +1,34 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +type EtcDBatch struct { + db *clientv3.Client +} + +type WriteOptions struct { + NoWriteMerge bool + Sync bool +} + +func (b *EtcDBatch) Put(key, value []byte) (err error) { + _, err = b.db.Put(Ctx, string(key), string(value)) + return +} + +func (b *EtcDBatch) Delete(key []byte) (err error) { + _, err = b.db.Delete(Ctx, string(key)) + return +} + +func (b *EtcDBatch) Write() (err error) { + return +} + +// batch should implement database.Batch +var ( + _ database.Batch = &EtcDBatch{} +) diff --git a/database/etcddb/database.go b/database/etcddb/database.go new file mode 100644 index 000000000..f69eee7e9 --- /dev/null +++ b/database/etcddb/database.go @@ -0,0 +1,45 @@ +package etcddb + +import ( + "context" + "time" + + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +var Ctx = context.TODO() + +func internalOpen(url string) (*clientv3.Client, error) { + cfg := clientv3.Config{ + Endpoints: []string{url}, + DialTimeout: 30 * time.Second, + MaxCallSendMsgSize: 2048 * 1024 * 1024, + MaxCallRecvMsgSize: 2048 * 1024 * 1024, + DialKeepAliveTimeout: 7200 * time.Second, + } + + cli, err := clientv3.New(cfg) + if err != nil { + return nil, err + } + + return cli, nil +} + +func NewDB(url string) (database.Storage, error) { + cli, err := internalOpen(url) + if err != nil { + return nil, err + } + return &EtcDStorage{url, cli}, nil +} + +func NewOpenDB(url string) (database.Storage, error) { + db, err := NewDB(url) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/database/etcddb/database_test.go b/database/etcddb/database_test.go new file mode 100644 index 000000000..1e601b4e4 --- /dev/null +++ b/database/etcddb/database_test.go @@ -0,0 +1,156 @@ +package etcddb_test + +import ( + "testing" + + "github.com/aptly-dev/aptly/database" + "github.com/aptly-dev/aptly/database/etcddb" + . "gopkg.in/check.v1" +) + +// Launch gocheck tests +func Test(t *testing.T) { + TestingT(t) +} + +type EtcDDBSuite struct { + url string + db database.Storage +} + +var _ = Suite(&EtcDDBSuite{}) + +func (s *EtcDDBSuite) SetUpTest(c *C) { + var err error + s.db, err = etcddb.NewOpenDB("127.0.0.1:2379") + c.Assert(err, IsNil) +} + +func (s *EtcDDBSuite) TestSetUpTest(c *C) { + var err error + s.db, err = etcddb.NewOpenDB("127.0.0.1:2379") + c.Assert(err, IsNil) +} + +func (s *EtcDDBSuite) TestGetPut(c *C) { + var ( + key = []byte("key") + value = []byte("value") + ) + var err error + + err = s.db.Put(key, value) + c.Assert(err, IsNil) + + result, err := s.db.Get(key) + c.Assert(err, IsNil) + c.Assert(result, DeepEquals, value) +} + +func (s *EtcDDBSuite) TestDelete(c *C) { + var ( + key = []byte("key") + value = []byte("value") + ) + + err := s.db.Put(key, value) + c.Assert(err, IsNil) + + _, err = s.db.Get(key) + c.Assert(err, IsNil) + + err = s.db.Delete(key) + c.Assert(err, IsNil) + +} + +func (s *EtcDDBSuite) TestByPrefix(c *C) { + //c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{}) + + s.db.Put([]byte{0x80, 0x01}, []byte{0x01}) + s.db.Put([]byte{0x80, 0x03}, []byte{0x03}) + s.db.Put([]byte{0x80, 0x02}, []byte{0x02}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + s.db.Put([]byte{0x90, 0x01}, []byte{0x04}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + s.db.Put([]byte{0x00, 0x01}, []byte{0x05}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + keys := [][]byte{} + values := [][]byte{} + + c.Check(s.db.ProcessByPrefix([]byte{0x80}, func(k, v []byte) error { + keys = append(keys, append([]byte(nil), k...)) + values = append(values, append([]byte(nil), v...)) + return nil + }), IsNil) + + c.Check(values, DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(keys, DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + c.Check(s.db.ProcessByPrefix([]byte{0x80}, func(k, v []byte) error { + return database.ErrNotFound + }), Equals, database.ErrNotFound) + + c.Check(s.db.ProcessByPrefix([]byte{0xa0}, func(k, v []byte) error { + return database.ErrNotFound + }), IsNil) + + c.Check(s.db.FetchByPrefix([]byte{0xa0}), DeepEquals, [][]byte{}) + c.Check(s.db.KeysByPrefix([]byte{0xa0}), DeepEquals, [][]byte{}) +} + +func (s *EtcDDBSuite) TestHasPrefix(c *C) { + //c.Check(s.db.HasPrefix([]byte(nil)), Equals, false) + //c.Check(s.db.HasPrefix([]byte{0x80}), Equals, false) + + s.db.Put([]byte{0x80, 0x01}, []byte{0x01}) + + c.Check(s.db.HasPrefix([]byte(nil)), Equals, true) + c.Check(s.db.HasPrefix([]byte{0x80}), Equals, true) + c.Check(s.db.HasPrefix([]byte{0x79}), Equals, false) +} + +func (s *EtcDDBSuite) TestTransactionCommit(c *C) { + var ( + key = []byte("key") + key2 = []byte("key2") + value = []byte("value") + value2 = []byte("value2") + ) + transaction, err := s.db.OpenTransaction() + + err = s.db.Put(key, value) + c.Assert(err, IsNil) + + c.Assert(err, IsNil) + transaction.Put(key2, value2) + v, err := s.db.Get(key) + c.Check(v, DeepEquals, value) + transaction.Delete(key) + + _, err = transaction.Get(key2) + c.Assert(err, IsNil) + + v2, err := transaction.Get(key2) + c.Check(err, IsNil) + c.Check(v2, DeepEquals, value2) + + _, err = transaction.Get(key) + c.Assert(err, IsNil) + + err = transaction.Commit() + c.Check(err, IsNil) + + v2, err = transaction.Get(key2) + c.Check(err, IsNil) + c.Check(v2, DeepEquals, value2) + + _, err = transaction.Get(key) + c.Assert(err, IsNil) +} diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go new file mode 100644 index 000000000..c36c3beac --- /dev/null +++ b/database/etcddb/storage.go @@ -0,0 +1,163 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +type EtcDStorage struct { + url string + db *clientv3.Client +} + +// CreateTemporary creates new DB of the same type in temp dir +func (s *EtcDStorage) CreateTemporary() (database.Storage, error) { + return s, nil +} + +// Get key value from etcd +func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { + getResp, err := s.db.Get(Ctx, string(key)) + if err != nil { + return + } + for _, kv := range getResp.Kvs { + value = kv.Value + } + if len(value) == 0 { + err = database.ErrNotFound + return + } + return +} + +// Put saves key to etcd, if key has the same value in DB already, it is not saved +func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { + _, err = s.db.Put(Ctx, string(key), string(value)) + if err != nil { + return + } + return +} + +// Delete removes key from etcd +func (s *EtcDStorage) Delete(key []byte) (err error) { + _, err = s.db.Delete(Ctx, string(key)) + if err != nil { + return + } + return +} + +// KeysByPrefix returns all keys that start with prefix +func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { + result := make([][]byte, 0, 20) + getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, ev := range getResp.Kvs { + key := ev.Key + keyc := make([]byte, len(key)) + copy(keyc, key) + result = append(result, key) + } + return result +} + +// FetchByPrefix returns all values with keys that start with prefix +func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { + result := make([][]byte, 0, 20) + getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, kv := range getResp.Kvs { + valc := make([]byte, len(kv.Value)) + copy(valc, kv.Value) + result = append(result, kv.Value) + } + + return result +} + +// HasPrefix checks whether it can find any key with given prefix and returns true if one exists +func (s *EtcDStorage) HasPrefix(prefix []byte) bool { + getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + if err != nil { + return false + } + if getResp.Count != 0 { + return true + } + return false +} + +// ProcessByPrefix iterates through all entries where key starts with prefix and calls +// StorageProcessor on key value pair +func (s *EtcDStorage) ProcessByPrefix(prefix []byte, proc database.StorageProcessor) error { + getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + if err != nil { + return err + } + + for _, kv := range getResp.Kvs { + err := proc(kv.Key, kv.Value) + if err != nil { + return err + } + } + return nil +} + +// Close finishes etcd connect +func (s *EtcDStorage) Close() error { + if s.db == nil { + return nil + } + err := s.db.Close() + s.db = nil + return err +} + +// Reopen tries to open (re-open) the database +func (s *EtcDStorage) Open() error { + if s.db != nil { + return nil + } + var err error + s.db, err = internalOpen(s.url) + return err +} + +// CreateBatch creates a Batch object +func (s *EtcDStorage) CreateBatch() database.Batch { + return &EtcDBatch{ + db: s.db, + } +} + +// OpenTransaction creates new transaction. +func (s *EtcDStorage) OpenTransaction() (database.Transaction, error) { + cli, err := internalOpen(s.url) + if err != nil { + return nil, err + } + kvc := clientv3.NewKV(cli) + return &transaction{t: kvc}, nil +} + +// CompactDB compacts database by merging layers +func (s *EtcDStorage) CompactDB() error { + return nil +} + +// Drop removes all the etcd files (DANGEROUS!) +func (s *EtcDStorage) Drop() error { + return nil +} + +// Check interface +var ( + _ database.Storage = &EtcDStorage{} +) diff --git a/database/etcddb/transaction.go b/database/etcddb/transaction.go new file mode 100644 index 000000000..4b0830563 --- /dev/null +++ b/database/etcddb/transaction.go @@ -0,0 +1,55 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" + "go.etcd.io/etcd/client/v3/clientv3util" +) + +type transaction struct { + t clientv3.KV +} + +// Get implements database.Reader interface. +func (t *transaction) Get(key []byte) ([]byte, error) { + getResp, err := t.t.Get(Ctx, string(key)) + if err != nil { + return nil, err + } + + var value []byte + for _, kv := range getResp.Kvs { + valc := make([]byte, len(kv.Value)) + copy(valc, kv.Value) + value = valc + } + + return value, nil +} + +// Put implements database.Writer interface. +func (t *transaction) Put(key, value []byte) (err error) { + _, err = t.t.Txn(Ctx). + If().Then(clientv3.OpPut(string(key), string(value))).Commit() + return +} + +// Delete implements database.Writer interface. +func (t *transaction) Delete(key []byte) (err error) { + _, err = t.t.Txn(Ctx). + If(clientv3util.KeyExists(string(key))). + Then(clientv3.OpDelete(string(key))).Commit() + return +} + +func (t *transaction) Commit() (err error) { + return +} + +// Discard is safe to call after Commit(), it would be no-op +func (t *transaction) Discard() { + return +} + +// transaction should implement database.Transaction +var _ database.Transaction = &transaction{} diff --git a/go.mod b/go.mod index 311217cb3..d42e38c98 100644 --- a/go.mod +++ b/go.mod @@ -63,11 +63,14 @@ require ( github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.3.1 // indirect @@ -90,10 +93,17 @@ require ( github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + go.etcd.io/etcd/api/v3 v3.5.0-rc.0 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.0-rc.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.17.0 // indirect golang.org/x/arch v0.5.0 // indirect golang.org/x/net v0.23.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.38.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -104,4 +114,5 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.13.43 github.com/aws/aws-sdk-go-v2/service/s3 v1.40.2 github.com/aws/smithy-go v1.15.0 + go.etcd.io/etcd/client/v3 v3.5.0-rc.0 ) diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index d721fe945..f892ef918 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -28,6 +28,7 @@ Configuration file is stored in JSON format (default values shown below): { "rootDir": "$HOME/.aptly", + "databaseEtcd": "", "downloadConcurrency": 4, "downloadSpeedLimit": 0, "downloadRetries": 0, @@ -119,6 +120,9 @@ Options: the default for downloaded packages (`rootDir`/pool) and the default for published repositories (`rootDir`/public) + * `databaseEtcd`: + the etcd database connection address is empty by default, which means it is not used + * `downloadConcurrency`: is a number of parallel download threads to use when downloading packages diff --git a/system/t02_config/ConfigShowTest_gold b/system/t02_config/ConfigShowTest_gold index 0ae32b672..58c65bf9c 100644 --- a/system/t02_config/ConfigShowTest_gold +++ b/system/t02_config/ConfigShowTest_gold @@ -29,5 +29,6 @@ "enableMetricsEndpoint": true, "logLevel": "debug", "logFormat": "default", - "serveInAPIMode": true + "serveInAPIMode": true, + "databaseEtcd": "" } diff --git a/system/t02_config/CreateConfigTest_gold b/system/t02_config/CreateConfigTest_gold index 0b3ed7928..2aaf7c646 100644 --- a/system/t02_config/CreateConfigTest_gold +++ b/system/t02_config/CreateConfigTest_gold @@ -29,5 +29,6 @@ "enableMetricsEndpoint": false, "logLevel": "debug", "logFormat": "default", - "serveInAPIMode": false -} \ No newline at end of file + "serveInAPIMode": false, + "databaseEtcd": "" +} diff --git a/utils/config.go b/utils/config.go index acc063d73..e9ebc5362 100644 --- a/utils/config.go +++ b/utils/config.go @@ -40,6 +40,7 @@ type ConfigStructure struct { // nolint: maligned LogLevel string `json:"logLevel"` LogFormat string `json:"logFormat"` ServeInAPIMode bool `json:"serveInAPIMode"` + DatabaseEtcd string `json:"databaseEtcd"` } type LocalPoolStorage struct { diff --git a/utils/config_test.go b/utils/config_test.go index 4304ea8be..3036e8a84 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -143,7 +143,8 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"enableMetricsEndpoint\": false,\n"+ " \"logLevel\": \"info\",\n"+ " \"logFormat\": \"json\",\n"+ - " \"serveInAPIMode\": false\n"+ + " \"serveInAPIMode\": false,\n"+ + " \"databaseEtcd\": \"\"\n"+ "}") } From dd6f0f37dd08d932c1a97fcdf40009626e3365bd Mon Sep 17 00:00:00 2001 From: hudeng Date: Wed, 9 Feb 2022 18:21:00 +0800 Subject: [PATCH 02/12] feat: Add system test for etcd --- Makefile | 24 +++++++++++------------- system/leveldb2etcd.py | 27 +++++++++++++++++++++++++++ system/lib.py | 7 ++++++- system/requirements.txt | 2 ++ 4 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 system/leveldb2etcd.py diff --git a/Makefile b/Makefile index 217b8c82e..74d069e2b 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,7 @@ COVERAGE_DIR?=$(shell mktemp -d) # Uncomment to update test outputs # CAPTURE := "--capture" -# etcd test env -ETCD_VER=v3.5.2 -DOWNLOAD_URL=https://storage.googleapis.com/etcd - -all: modules test bench check system-test +all: modules test bench check system-test system-test-etcd # Self-documenting Makefile # https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html @@ -26,13 +22,6 @@ help: ## Print this help prepare: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin $(GOLANGCI_LINT_VERSION) -etcd-prepare: - # etcd test prepare - rm -rf /tmp/etcd-download-test/test-data && mkdir -p /tmp/etcd-download-test/test-data - if [ ! -e /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz ]; then curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz; fi - tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1 - /tmp/etcd-download-test/etcd --data-dir /tmp/etcd-download-test/test-data & - modules: go mod download go mod verify @@ -79,9 +68,18 @@ docker-test: install export APTLY_VERSION=$(VERSION); \ $(PYTHON) system/run.py --long $(TESTS) --coverage-dir $(COVERAGE_DIR) $(CAPTURE) $(TEST) -test: etcd-prepare +test: go test -v ./... -gocheck.v=true -coverprofile=unit.out +system-test-etcd: install system/env +ifeq ($(RUN_LONG_TESTS), yes) + if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi + if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi + # TODO: maybe we can skip imgrading levledb data to etcd + PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_VERSION=$(VERSION) $(PYTHON) system/leveldb2etcd.py --datadir ~/aptly-fixture-db + PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_ETCD_DATABASE="127.0.0.1:2379" APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) +endif + bench: go test -v ./deb -run=nothing -bench=. -benchmem diff --git a/system/leveldb2etcd.py b/system/leveldb2etcd.py new file mode 100644 index 000000000..d7c18fdd3 --- /dev/null +++ b/system/leveldb2etcd.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import leveldb +import etcd3 +import argparse +from termcolor import cprint + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--datadir", required=True, help="leveldb data dir") + parser.add_argument("--etcdaddr", default="127.0.0.1", help="etcd server address") + parser.add_argument("--etcdport", default="2379", help="etcd server address") + + args = parser.parse_args() + + ldb = leveldb.LevelDB(args.datadir) + etcd = etcd3.client(args.etcdaddr, args.etcdport) + + for key, value in ldb.RangeIter(): + try: + keystr = str(bytes(key)) + valuestr = str(bytes(value)) + etcd.put(keystr, valuestr) + # cprint("key: "+keystr+", value: "+valuestr+"put success!\n", 'green') + except Exception as e: + cprint("key: " + keystr + ", value: " + valuestr + "put err: " + str(e) + "\n", 'red') + exit(1) diff --git a/system/lib.py b/system/lib.py index e3bf521bc..98d86d327 100644 --- a/system/lib.py +++ b/system/lib.py @@ -133,6 +133,10 @@ class BaseTest(object): aptlyDir = ".aptly" aptlyConfigFile = ".aptly.conf" expectedCode = 0 + databaseEtcd = os.environ.get("APTLY_ETCD_DATABASE") + if databaseEtcd is None: + databaseEtcd = "" + configFile = { "rootDir": f"{os.environ['HOME']}/{aptlyDir}", "downloadConcurrency": 4, @@ -151,7 +155,8 @@ class BaseTest(object): "enableMetricsEndpoint": True, "logLevel": "debug", "logFormat": "default", - "serveInAPIMode": True + "serveInAPIMode": True, + "databaseEtcd": databaseEtcd, } configOverride = {} environmentOverride = {} diff --git a/system/requirements.txt b/system/requirements.txt index 33ed79c21..b06273400 100644 --- a/system/requirements.txt +++ b/system/requirements.txt @@ -5,3 +5,5 @@ requests-unixsocket python-swiftclient flake8 termcolor +etcd3 +leveldb From 142c039cd7f942cc4b98ad2bb7a82d5c1e7b3075 Mon Sep 17 00:00:00 2001 From: hudeng Date: Fri, 11 Feb 2022 18:14:26 +0800 Subject: [PATCH 03/12] feat: Use databaseBackend config repace databaseEtcd databaseBackend config contains type and url sub config, It can facilitate the expansion of other types of databases in the future. --- Makefile | 4 ++-- context/context.go | 12 ++++++++++-- man/aptly.1.ronn.tmpl | 9 ++++++--- system/lib.py | 15 ++++++++++++--- system/t02_config/ConfigShowTest_gold | 3 ++- system/t02_config/CreateConfigTest_gold | 3 ++- utils/config.go | 8 ++++++++ utils/config_test.go | 6 +++++- 8 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 74d069e2b..fe1712925 100644 --- a/Makefile +++ b/Makefile @@ -76,8 +76,8 @@ ifeq ($(RUN_LONG_TESTS), yes) if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi # TODO: maybe we can skip imgrading levledb data to etcd - PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_VERSION=$(VERSION) $(PYTHON) system/leveldb2etcd.py --datadir ~/aptly-fixture-db - PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_ETCD_DATABASE="127.0.0.1:2379" APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) + PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && $(PYTHON) system/leveldb2etcd.py --datadir ~/aptly-fixture-db + PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_DATABASE_TYPE="etcd" APTLY_DATABASE_URL="127.0.0.1:2379" APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) endif bench: diff --git a/context/context.go b/context/context.go index 7f17b84d9..8838f26ba 100644 --- a/context/context.go +++ b/context/context.go @@ -3,6 +3,7 @@ package context import ( gocontext "context" + "errors" "fmt" "math/rand" "os" @@ -289,8 +290,15 @@ func (context *AptlyContext) _database() (database.Storage, error) { if context.database == nil { var err error - if context.config().DatabaseEtcd != "" { - context.database, err = etcddb.NewDB(context.config().DatabaseEtcd) + if context.config().DatabaseBackend.Type == "etcd" { + context.database, err = etcddb.NewDB(context.config().DatabaseBackend.URL) + } else if context.config().DatabaseBackend.Type == "leveldb" { + if context.config().DatabaseBackend.DbPath != "" { + dbPath := filepath.Join(context.config().RootDir, context.config().DatabaseBackend.DbPath) + context.database, err = goleveldb.NewDB(dbPath) + } else { + return nil, errors.New("leveldb databaseBackend config invalid") + } } else { context.database, err = goleveldb.NewDB(context.dbPath()) } diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index f892ef918..c7d7a076c 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -28,7 +28,10 @@ Configuration file is stored in JSON format (default values shown below): { "rootDir": "$HOME/.aptly", - "databaseEtcd": "", + "databaseBackend": { + "type": "", + "url": "" + }, "downloadConcurrency": 4, "downloadSpeedLimit": 0, "downloadRetries": 0, @@ -120,8 +123,8 @@ Options: the default for downloaded packages (`rootDir`/pool) and the default for published repositories (`rootDir`/public) - * `databaseEtcd`: - the etcd database connection address is empty by default, which means it is not used + * `databaseBackend`: + the database config; if this config is empty, use levledb backend by default * `downloadConcurrency`: is a number of parallel download threads to use when downloading packages diff --git a/system/lib.py b/system/lib.py index 98d86d327..d4ce5e25e 100644 --- a/system/lib.py +++ b/system/lib.py @@ -133,9 +133,17 @@ class BaseTest(object): aptlyDir = ".aptly" aptlyConfigFile = ".aptly.conf" expectedCode = 0 - databaseEtcd = os.environ.get("APTLY_ETCD_DATABASE") - if databaseEtcd is None: - databaseEtcd = "" + databaseType = os.environ.get("APTLY_DATABASE_TYPE") + databaseUrl = os.environ.get("APTLY_DATABASE_URL") + if databaseType is None: + databaseType = "" + if databaseUrl is None: + databaseUrl = "" + + databaseBackend = { + "type": databaseType, + "url": databaseUrl, + } configFile = { "rootDir": f"{os.environ['HOME']}/{aptlyDir}", @@ -157,6 +165,7 @@ class BaseTest(object): "logFormat": "default", "serveInAPIMode": True, "databaseEtcd": databaseEtcd, + "databaseBackend": databaseBackend, } configOverride = {} environmentOverride = {} diff --git a/system/t02_config/ConfigShowTest_gold b/system/t02_config/ConfigShowTest_gold index 58c65bf9c..ad12f3077 100644 --- a/system/t02_config/ConfigShowTest_gold +++ b/system/t02_config/ConfigShowTest_gold @@ -30,5 +30,6 @@ "logLevel": "debug", "logFormat": "default", "serveInAPIMode": true, - "databaseEtcd": "" + "databaseEtcd": "", + "databaseBackend": {} } diff --git a/system/t02_config/CreateConfigTest_gold b/system/t02_config/CreateConfigTest_gold index 2aaf7c646..24bed7f62 100644 --- a/system/t02_config/CreateConfigTest_gold +++ b/system/t02_config/CreateConfigTest_gold @@ -30,5 +30,6 @@ "logLevel": "debug", "logFormat": "default", "serveInAPIMode": false, - "databaseEtcd": "" + "databaseEtcd": "", + "databaseBackend": {} } diff --git a/utils/config.go b/utils/config.go index e9ebc5362..299408119 100644 --- a/utils/config.go +++ b/utils/config.go @@ -41,6 +41,14 @@ type ConfigStructure struct { // nolint: maligned LogFormat string `json:"logFormat"` ServeInAPIMode bool `json:"serveInAPIMode"` DatabaseEtcd string `json:"databaseEtcd"` + DatabaseBackend DBConfig `json:"databaseBackend"` +} + +// DBConfig +type DBConfig struct { + Type string `json:"type"` + URL string `json:"url"` + DbPath string `json:"dbPath"` } type LocalPoolStorage struct { diff --git a/utils/config_test.go b/utils/config_test.go index 3036e8a84..8760c90c5 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -144,7 +144,11 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"logLevel\": \"info\",\n"+ " \"logFormat\": \"json\",\n"+ " \"serveInAPIMode\": false,\n"+ - " \"databaseEtcd\": \"\"\n"+ + " \"databaseEtcd\": \"\",\n"+ + " \"databaseBackend\": {\n"+ + " \"type\": \"\",\n"+ + " \"url\": \"\"\n"+ + " }\n"+ "}") } From 0fd2afd86108a1ddff8e65191855f367510b8ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Tue, 23 Jul 2024 16:26:59 +0200 Subject: [PATCH 04/12] etcd: fix int overflow goxc fails with: Error: database/etcddb/database.go:17:25: cannot use 2048 * 1024 * 1024 (untyped int constant 2147483648) as int value in struct literal (overflows) --- database/etcddb/database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/etcddb/database.go b/database/etcddb/database.go index f69eee7e9..761c81fe9 100644 --- a/database/etcddb/database.go +++ b/database/etcddb/database.go @@ -14,8 +14,8 @@ func internalOpen(url string) (*clientv3.Client, error) { cfg := clientv3.Config{ Endpoints: []string{url}, DialTimeout: 30 * time.Second, - MaxCallSendMsgSize: 2048 * 1024 * 1024, - MaxCallRecvMsgSize: 2048 * 1024 * 1024, + MaxCallSendMsgSize: (2048 * 1024 * 1024) - 1, + MaxCallRecvMsgSize: (2048 * 1024 * 1024) - 1, DialKeepAliveTimeout: 7200 * time.Second, } From 43f41b439906378c934b4e32a7f87cdf7cc52a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Sat, 27 Jul 2024 17:55:07 +0200 Subject: [PATCH 05/12] etcd: fix db config and test fix unit test for adapted config file --- utils/config.go | 1 - utils/config_test.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/config.go b/utils/config.go index 299408119..e7f8c22fa 100644 --- a/utils/config.go +++ b/utils/config.go @@ -40,7 +40,6 @@ type ConfigStructure struct { // nolint: maligned LogLevel string `json:"logLevel"` LogFormat string `json:"logFormat"` ServeInAPIMode bool `json:"serveInAPIMode"` - DatabaseEtcd string `json:"databaseEtcd"` DatabaseBackend DBConfig `json:"databaseBackend"` } diff --git a/utils/config_test.go b/utils/config_test.go index 8760c90c5..c906d2a36 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -144,10 +144,10 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"logLevel\": \"info\",\n"+ " \"logFormat\": \"json\",\n"+ " \"serveInAPIMode\": false,\n"+ - " \"databaseEtcd\": \"\",\n"+ " \"databaseBackend\": {\n"+ " \"type\": \"\",\n"+ - " \"url\": \"\"\n"+ + " \"url\": \"\",\n"+ + " \"dbPath\": \"\"\n" + " }\n"+ "}") } From 1684089e72472bb89b83769f46fa3a5c8a214d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Sun, 21 Apr 2024 14:33:15 +0200 Subject: [PATCH 06/12] etcd: implement separate system tests - add t13_etcd test directory - etcd will be started for the unit tests and each system test - etcd will load fixture DB export if requested by the test - existing tests are reused for etcd testing --- .github/workflows/ci.yml | 1 + Makefile | 25 +-- system/Dockerfile | 3 +- system/leveldb2etcd.py | 12 +- system/lib.py | 100 +++++---- system/run-unit-tests | 14 ++ system/run.py | 6 + system/t02_config/ConfigShowTest_gold | 7 +- system/t02_config/CreateConfigTest_gold | 7 +- system/t06_publish/drop.py | 8 + system/t13_etcd/PublishDrop1TestEtcd_gold | 1 + system/t13_etcd/PublishDrop2TestEtcd_gold | 1 + system/t13_etcd/PublishDrop3TestEtcd_gold | 1 + system/t13_etcd/PublishDrop4TestEtcd_gold | 1 + system/t13_etcd/PublishDrop5TestEtcd_gold | 1 + system/t13_etcd/PublishDrop6TestEtcd_gold | 1 + system/t13_etcd/PublishDrop7TestEtcd_gold | 1 + system/t13_etcd/PublishDrop8TestEtcd_gold | 1 + system/t13_etcd/PublishDrop9TestEtcd_gold | 1 + system/t13_etcd/PublishList1TestEtcd_gold | 1 + system/t13_etcd/PublishList2TestEtcd_gold | 1 + system/t13_etcd/PublishList3TestEtcd_gold | 1 + system/t13_etcd/PublishList4TestEtcd_gold | 1 + system/t13_etcd/PublishList5TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror10TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror11TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror12TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror13TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror14TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror15TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror16TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror17TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror18TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror19TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror1TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror20TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror21TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror22TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror23TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror24TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror25TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror2TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror3TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror4TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror5TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror6TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror7TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror8TestEtcd_gold | 1 + system/t13_etcd/UpdateMirror9TestEtcd_gold | 1 + system/t13_etcd/__init__.py | 3 + system/t13_etcd/install-etcd.sh | 12 + system/t13_etcd/mirror_update.py | 234 ++++++++++++++++++++ system/t13_etcd/publish_drop.py | 92 ++++++++ system/t13_etcd/publish_list.py | 48 ++++ system/t13_etcd/start-etcd.sh | 23 ++ system/t13_etcd/test_release | 1 + system/t13_etcd/test_release2 | 1 + 57 files changed, 572 insertions(+), 64 deletions(-) create mode 100755 system/run-unit-tests create mode 120000 system/t13_etcd/PublishDrop1TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop2TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop3TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop4TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop5TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop6TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop7TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop8TestEtcd_gold create mode 120000 system/t13_etcd/PublishDrop9TestEtcd_gold create mode 120000 system/t13_etcd/PublishList1TestEtcd_gold create mode 120000 system/t13_etcd/PublishList2TestEtcd_gold create mode 120000 system/t13_etcd/PublishList3TestEtcd_gold create mode 120000 system/t13_etcd/PublishList4TestEtcd_gold create mode 120000 system/t13_etcd/PublishList5TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror10TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror11TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror12TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror13TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror14TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror15TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror16TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror17TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror18TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror19TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror1TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror20TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror21TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror22TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror23TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror24TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror25TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror2TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror3TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror4TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror5TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror6TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror7TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror8TestEtcd_gold create mode 120000 system/t13_etcd/UpdateMirror9TestEtcd_gold create mode 100644 system/t13_etcd/__init__.py create mode 100755 system/t13_etcd/install-etcd.sh create mode 100644 system/t13_etcd/mirror_update.py create mode 100644 system/t13_etcd/publish_drop.py create mode 100644 system/t13_etcd/publish_list.py create mode 100755 system/t13_etcd/start-etcd.sh create mode 120000 system/t13_etcd/test_release create mode 120000 system/t13_etcd/test_release2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c45e92202..71674b383 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,6 +75,7 @@ jobs: AZURE_STORAGE_ACCOUNT: "devstoreaccount1" AZURE_STORAGE_ACCESS_KEY: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" run: | + sudo mkdir -p /srv ; sudo chown runner /srv COVERAGE_DIR=${{ runner.temp }} make - name: Merge code coverage diff --git a/Makefile b/Makefile index fe1712925..7c525fa99 100644 --- a/Makefile +++ b/Makefile @@ -12,16 +12,13 @@ COVERAGE_DIR?=$(shell mktemp -d) # Uncomment to update test outputs # CAPTURE := "--capture" -all: modules test bench check system-test system-test-etcd +all: modules test bench check system-test # Self-documenting Makefile # https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html help: ## Print this help @grep -E '^[a-zA-Z][a-zA-Z0-9_-]*:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -prepare: - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin $(GOLANGCI_LINT_VERSION) - modules: go mod download go mod verify @@ -53,9 +50,14 @@ endif system-test: install system/env ifeq ($(RUN_LONG_TESTS), yes) go generate + test -d /srv/etcd || system/t13_etcd/install-etcd.sh + system/t13_etcd/start-etcd.sh & go test -v -coverpkg="./..." -c -tags testruncli + kill `cat /tmp/etcd.pid` + if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi + cd /home/runner; curl -O http://repo.aptly.info/system-tests/etcd.db PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_VERSION=$(VERSION) FORCE_COLOR=1 $(PYTHON) system/run.py --long $(TESTS) --coverage-dir $(COVERAGE_DIR) $(CAPTURE) endif @@ -69,16 +71,11 @@ docker-test: install $(PYTHON) system/run.py --long $(TESTS) --coverage-dir $(COVERAGE_DIR) $(CAPTURE) $(TEST) test: + test -d /srv/etcd || system/t13_etcd/install-etcd.sh + system/t13_etcd/start-etcd.sh & + echo Running go test go test -v ./... -gocheck.v=true -coverprofile=unit.out - -system-test-etcd: install system/env -ifeq ($(RUN_LONG_TESTS), yes) - if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi - if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi - # TODO: maybe we can skip imgrading levledb data to etcd - PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && $(PYTHON) system/leveldb2etcd.py --datadir ~/aptly-fixture-db - PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_DATABASE_TYPE="etcd" APTLY_DATABASE_URL="127.0.0.1:2379" APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) -endif + kill `cat /tmp/etcd.pid` bench: go test -v ./deb -run=nothing -bench=. -benchmem @@ -113,7 +110,7 @@ docker-build-system-tests: ## Build system-test docker image docker build -f system/Dockerfile . -t aptly-system-test docker-unit-tests: ## Run unit tests in docker container - docker run -it --rm -v ${PWD}:/app aptly-system-test go test -v ./... -gocheck.v=true + docker run -it --rm -v ${PWD}:/app aptly-system-test /app/system/run-unit-tests docker-system-tests: ## Run system tests in docker container (add TEST=t04_mirror to run only specific tests) docker run -it --rm -v ${PWD}:/app aptly-system-test /app/system/run-system-tests $(TEST) diff --git a/system/Dockerfile b/system/Dockerfile index 9988f42a0..39e82d8ba 100644 --- a/system/Dockerfile +++ b/system/Dockerfile @@ -1,6 +1,6 @@ FROM debian:bookworm-slim -RUN apt-get update -y && apt-get install -y --no-install-recommends curl gnupg apg bzip2 xz-utils ca-certificates golang golang-go golang-doc golang-src make git python3 python3-requests-unixsocket python3-termcolor python3-swiftclient python3-boto python3-azure-storage g++ && \ +RUN apt-get update -y && apt-get install -y --no-install-recommends curl gnupg apg bzip2 xz-utils ca-certificates golang golang-go golang-doc golang-src make git python3 python3-requests-unixsocket python3-termcolor python3-swiftclient python3-boto python3-azure-storage g++ python3-etcd3 python3-plyvel && \ apt-get clean && rm -rf /var/lib/apt/lists/* RUN useradd -m --shell /bin/sh --home-dir /var/lib/aptly aptly @@ -16,6 +16,7 @@ RUN cd /home/runner; curl -O http://repo.aptly.info/system-tests/etcd.db ADD . /src RUN chown aptly -R /src RUN cd /src; su aptly -c "HOME=/home/runner go mod tidy" +RUN /src/system/t13_etcd/install-etcd.sh RUN rm -rf /src CMD /app/system/run-system-tests diff --git a/system/leveldb2etcd.py b/system/leveldb2etcd.py index d7c18fdd3..65788b121 100644 --- a/system/leveldb2etcd.py +++ b/system/leveldb2etcd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import leveldb +import plyvel import etcd3 import argparse from termcolor import cprint @@ -13,15 +13,15 @@ args = parser.parse_args() - ldb = leveldb.LevelDB(args.datadir) + ldb = plyvel.DB(args.datadir) etcd = etcd3.client(args.etcdaddr, args.etcdport) - for key, value in ldb.RangeIter(): + for key, value in ldb: try: - keystr = str(bytes(key)) - valuestr = str(bytes(value)) + keystr = key + valuestr = value etcd.put(keystr, valuestr) # cprint("key: "+keystr+", value: "+valuestr+"put success!\n", 'green') except Exception as e: - cprint("key: " + keystr + ", value: " + valuestr + "put err: " + str(e) + "\n", 'red') + cprint("key: " + str(keystr) + ", value: " + str(valuestr) + "put err: " + str(e) + "\n", 'red') exit(1) diff --git a/system/lib.py b/system/lib.py index d4ce5e25e..128b0be3f 100644 --- a/system/lib.py +++ b/system/lib.py @@ -129,44 +129,14 @@ class BaseTest(object): requiresDot = False sortOutput = False debugOutput = False + EtcdServer = None aptlyDir = ".aptly" aptlyConfigFile = ".aptly.conf" expectedCode = 0 - databaseType = os.environ.get("APTLY_DATABASE_TYPE") - databaseUrl = os.environ.get("APTLY_DATABASE_URL") - if databaseType is None: - databaseType = "" - if databaseUrl is None: - databaseUrl = "" - - databaseBackend = { - "type": databaseType, - "url": databaseUrl, - } - - configFile = { - "rootDir": f"{os.environ['HOME']}/{aptlyDir}", - "downloadConcurrency": 4, - "downloadSpeedLimit": 0, - "downloadRetries": 5, - "databaseOpenAttempts": 10, - "architectures": [], - "dependencyFollowSuggests": False, - "dependencyFollowRecommends": False, - "dependencyFollowAllVariants": False, - "dependencyFollowSource": False, - "gpgDisableVerify": False, - "gpgDisableSign": False, - "ppaDistributorID": "ubuntu", - "ppaCodename": "", - "enableMetricsEndpoint": True, - "logLevel": "debug", - "logFormat": "default", - "serveInAPIMode": True, - "databaseEtcd": databaseEtcd, - "databaseBackend": databaseBackend, - } + databaseType = "" + databaseUrl = "" + configOverride = {} environmentOverride = {} @@ -209,7 +179,32 @@ def prepare_remove_all(self): os.environ["HOME"], ".gnupg", "aptlytest.gpg")) def prepare_default_config(self): - cfg = self.configFile.copy() + databaseBackend = { + "type": self.databaseType, + "url": self.databaseUrl, + } + + cfg = { + "rootDir": f"{os.environ['HOME']}/{self.aptlyDir}", + "downloadConcurrency": 4, + "downloadSpeedLimit": 0, + "downloadRetries": 5, + "databaseOpenAttempts": 10, + "architectures": [], + "dependencyFollowSuggests": False, + "dependencyFollowRecommends": False, + "dependencyFollowAllVariants": False, + "dependencyFollowSource": False, + "gpgDisableVerify": False, + "gpgDisableSign": False, + "ppaDistributorID": "ubuntu", + "ppaCodename": "", + "enableMetricsEndpoint": True, + "logLevel": "debug", + "logFormat": "default", + "serveInAPIMode": True, + "databaseBackend": databaseBackend, + } if self.requiresGPG1: cfg["gpgProvider"] = "gpg1" elif self.requiresGPG2: @@ -246,9 +241,27 @@ def prepare_fixture(self): shutil.copytree(self.fixturePoolDir, os.path.join( os.environ["HOME"], self.aptlyDir, "pool"), ignore=shutil.ignore_patterns(".git")) - if self.fixtureDB: - shutil.copytree(self.fixtureDBDir, os.path.join( - os.environ["HOME"], self.aptlyDir, "db")) + if self.databaseType == "etcd": + if not os.path.exists("/srv/etcd"): + self.run_cmd([os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "t13_etcd/install-etcd.sh")]) + + if self.fixtureDB and self.databaseType != "etcd": + shutil.copytree(self.fixtureDBDir, os.path.join(os.environ["HOME"], self.aptlyDir, "db")) + + if self.databaseType == "etcd": + if self.EtcdServer: + self.shutdown_etcd() + + # remove existing database + if os.path.exists("/tmp/etcd-data"): + shutil.rmtree("/tmp/etcd-data") + + if self.fixtureDB: + print("import etcd") + self.run_cmd(["/srv/etcd/etcdctl", "--data-dir=/tmp/etcd-data", "snapshot", "restore", os.path.join(os.environ["HOME"], "etcd.db")]) + + print("starting etcd") + self.EtcdServer = self._start_process([os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "t13_etcd/start-etcd.sh")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if self.fixtureWebServer: self.webServerUrl = self.start_webserver(os.path.join(os.path.dirname(inspect.getsourcefile(self.__class__)), @@ -499,7 +512,8 @@ def prepare(self): self.prepare_fixture() def teardown(self): - pass + if self.EtcdServer: + self.shutdown_etcd() def start_webserver(self, directory): FileHTTPServerRequestHandler.rootPath = directory @@ -515,10 +529,18 @@ def start_webserver(self, directory): def shutdown(self): if hasattr(self, 'webserver'): self.shutdown_webserver() + if self.EtcdServer: + self.shutdown_etcd() def shutdown_webserver(self): self.webserver.shutdown() + def shutdown_etcd(self): + print("stopping etcd") + self.EtcdServer.terminate() + self.EtcdServer.wait() + self.EtcdServer = None + @classmethod def shutdown_class(cls): pass diff --git a/system/run-unit-tests b/system/run-unit-tests new file mode 100755 index 000000000..80a4022cb --- /dev/null +++ b/system/run-unit-tests @@ -0,0 +1,14 @@ +#!/bin/sh + +# cleanup +rm -rf /app/tmp +rm -rf /tmp/aptly* + +mkdir -p /srv + +usermod -u `stat -c %u /app` aptly >/dev/null +chown -R `stat -c %u /app` /var/lib/aptly /srv + +# use same /home/runner dir as in github workflow +chown -R `stat -c %u /app` /home/runner +su - aptly -c "cd /app; export HOME=/home/runner; go mod tidy; make test" diff --git a/system/run.py b/system/run.py index dcc3f72b8..419dd4d1f 100755 --- a/system/run.py +++ b/system/run.py @@ -69,7 +69,13 @@ def run(include_long_tests=False, capture_results=False, tests=None, filters=Non orig_stdout.write(f"error importing: {test + '.' + fname}: {exc}\n") continue + testignore = [] + if hasattr(testModule, "TEST_IGNORE"): + testignore = testModule.TEST_IGNORE for name in sorted(dir(testModule), key=natural_key): + if name in testignore: + continue + testout.clear() o = getattr(testModule, name) diff --git a/system/t02_config/ConfigShowTest_gold b/system/t02_config/ConfigShowTest_gold index ad12f3077..3ff0ae2a8 100644 --- a/system/t02_config/ConfigShowTest_gold +++ b/system/t02_config/ConfigShowTest_gold @@ -30,6 +30,9 @@ "logLevel": "debug", "logFormat": "default", "serveInAPIMode": true, - "databaseEtcd": "", - "databaseBackend": {} + "databaseBackend": { + "type": "", + "url": "", + "dbPath": "" + } } diff --git a/system/t02_config/CreateConfigTest_gold b/system/t02_config/CreateConfigTest_gold index 24bed7f62..ab8c7de6f 100644 --- a/system/t02_config/CreateConfigTest_gold +++ b/system/t02_config/CreateConfigTest_gold @@ -30,6 +30,9 @@ "logLevel": "debug", "logFormat": "default", "serveInAPIMode": false, - "databaseEtcd": "", - "databaseBackend": {} + "databaseBackend": { + "type": "", + "url": "", + "dbPath": "" + } } diff --git a/system/t06_publish/drop.py b/system/t06_publish/drop.py index 8c4978e70..3c361cc31 100644 --- a/system/t06_publish/drop.py +++ b/system/t06_publish/drop.py @@ -5,6 +5,7 @@ class PublishDrop1Test(BaseTest): """ publish drop: existing snapshot """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -25,6 +26,7 @@ class PublishDrop2Test(BaseTest): """ publish drop: under prefix """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -46,6 +48,7 @@ class PublishDrop3Test(BaseTest): """ publish drop: drop one distribution """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -68,6 +71,7 @@ class PublishDrop4Test(BaseTest): """ publish drop: drop one of components """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -91,6 +95,7 @@ class PublishDrop5Test(BaseTest): """ publish drop: component cleanup """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", @@ -128,6 +133,7 @@ class PublishDrop7Test(BaseTest): """ publish drop: under prefix with trailing & leading slashes """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -149,6 +155,7 @@ class PublishDrop8Test(BaseTest): """ publish drop: skip component cleanup """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", @@ -178,6 +185,7 @@ class PublishDrop9Test(BaseTest): """ publish drop: component cleanup after first cleanup skipped """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", diff --git a/system/t13_etcd/PublishDrop1TestEtcd_gold b/system/t13_etcd/PublishDrop1TestEtcd_gold new file mode 120000 index 000000000..e96691b27 --- /dev/null +++ b/system/t13_etcd/PublishDrop1TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop2TestEtcd_gold b/system/t13_etcd/PublishDrop2TestEtcd_gold new file mode 120000 index 000000000..e507a2992 --- /dev/null +++ b/system/t13_etcd/PublishDrop2TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop3TestEtcd_gold b/system/t13_etcd/PublishDrop3TestEtcd_gold new file mode 120000 index 000000000..b371d5c0e --- /dev/null +++ b/system/t13_etcd/PublishDrop3TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop4TestEtcd_gold b/system/t13_etcd/PublishDrop4TestEtcd_gold new file mode 120000 index 000000000..34a46620f --- /dev/null +++ b/system/t13_etcd/PublishDrop4TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop5TestEtcd_gold b/system/t13_etcd/PublishDrop5TestEtcd_gold new file mode 120000 index 000000000..3ef738043 --- /dev/null +++ b/system/t13_etcd/PublishDrop5TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop6TestEtcd_gold b/system/t13_etcd/PublishDrop6TestEtcd_gold new file mode 120000 index 000000000..471ba43d8 --- /dev/null +++ b/system/t13_etcd/PublishDrop6TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop6Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop7TestEtcd_gold b/system/t13_etcd/PublishDrop7TestEtcd_gold new file mode 120000 index 000000000..a22742fcc --- /dev/null +++ b/system/t13_etcd/PublishDrop7TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop7Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop8TestEtcd_gold b/system/t13_etcd/PublishDrop8TestEtcd_gold new file mode 120000 index 000000000..e20efea8c --- /dev/null +++ b/system/t13_etcd/PublishDrop8TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop8Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop9TestEtcd_gold b/system/t13_etcd/PublishDrop9TestEtcd_gold new file mode 120000 index 000000000..89842314c --- /dev/null +++ b/system/t13_etcd/PublishDrop9TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop9Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList1TestEtcd_gold b/system/t13_etcd/PublishList1TestEtcd_gold new file mode 120000 index 000000000..c9ff7952b --- /dev/null +++ b/system/t13_etcd/PublishList1TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList2TestEtcd_gold b/system/t13_etcd/PublishList2TestEtcd_gold new file mode 120000 index 000000000..383fe5b8f --- /dev/null +++ b/system/t13_etcd/PublishList2TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList3TestEtcd_gold b/system/t13_etcd/PublishList3TestEtcd_gold new file mode 120000 index 000000000..09ac06cf2 --- /dev/null +++ b/system/t13_etcd/PublishList3TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList4TestEtcd_gold b/system/t13_etcd/PublishList4TestEtcd_gold new file mode 120000 index 000000000..f5b26f532 --- /dev/null +++ b/system/t13_etcd/PublishList4TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList5TestEtcd_gold b/system/t13_etcd/PublishList5TestEtcd_gold new file mode 120000 index 000000000..eb94ffde2 --- /dev/null +++ b/system/t13_etcd/PublishList5TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror10TestEtcd_gold b/system/t13_etcd/UpdateMirror10TestEtcd_gold new file mode 120000 index 000000000..efa730fa2 --- /dev/null +++ b/system/t13_etcd/UpdateMirror10TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror10Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror11TestEtcd_gold b/system/t13_etcd/UpdateMirror11TestEtcd_gold new file mode 120000 index 000000000..9fb5a6a73 --- /dev/null +++ b/system/t13_etcd/UpdateMirror11TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror11Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror12TestEtcd_gold b/system/t13_etcd/UpdateMirror12TestEtcd_gold new file mode 120000 index 000000000..653d9a72b --- /dev/null +++ b/system/t13_etcd/UpdateMirror12TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror12Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror13TestEtcd_gold b/system/t13_etcd/UpdateMirror13TestEtcd_gold new file mode 120000 index 000000000..e5f8e8cff --- /dev/null +++ b/system/t13_etcd/UpdateMirror13TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror13Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror14TestEtcd_gold b/system/t13_etcd/UpdateMirror14TestEtcd_gold new file mode 120000 index 000000000..0f7bf7469 --- /dev/null +++ b/system/t13_etcd/UpdateMirror14TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror14Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror15TestEtcd_gold b/system/t13_etcd/UpdateMirror15TestEtcd_gold new file mode 120000 index 000000000..bae34dff1 --- /dev/null +++ b/system/t13_etcd/UpdateMirror15TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror15Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror16TestEtcd_gold b/system/t13_etcd/UpdateMirror16TestEtcd_gold new file mode 120000 index 000000000..edbe7f22c --- /dev/null +++ b/system/t13_etcd/UpdateMirror16TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror16Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror17TestEtcd_gold b/system/t13_etcd/UpdateMirror17TestEtcd_gold new file mode 120000 index 000000000..eb1abbe6f --- /dev/null +++ b/system/t13_etcd/UpdateMirror17TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror17Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror18TestEtcd_gold b/system/t13_etcd/UpdateMirror18TestEtcd_gold new file mode 120000 index 000000000..c0333d25f --- /dev/null +++ b/system/t13_etcd/UpdateMirror18TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror18Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror19TestEtcd_gold b/system/t13_etcd/UpdateMirror19TestEtcd_gold new file mode 120000 index 000000000..a178fe7b4 --- /dev/null +++ b/system/t13_etcd/UpdateMirror19TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror19Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror1TestEtcd_gold b/system/t13_etcd/UpdateMirror1TestEtcd_gold new file mode 120000 index 000000000..cc5035be0 --- /dev/null +++ b/system/t13_etcd/UpdateMirror1TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror20TestEtcd_gold b/system/t13_etcd/UpdateMirror20TestEtcd_gold new file mode 120000 index 000000000..444b11dea --- /dev/null +++ b/system/t13_etcd/UpdateMirror20TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror20Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror21TestEtcd_gold b/system/t13_etcd/UpdateMirror21TestEtcd_gold new file mode 120000 index 000000000..bff753d00 --- /dev/null +++ b/system/t13_etcd/UpdateMirror21TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror21Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror22TestEtcd_gold b/system/t13_etcd/UpdateMirror22TestEtcd_gold new file mode 120000 index 000000000..54697e8cb --- /dev/null +++ b/system/t13_etcd/UpdateMirror22TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror22Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror23TestEtcd_gold b/system/t13_etcd/UpdateMirror23TestEtcd_gold new file mode 120000 index 000000000..649ac10fb --- /dev/null +++ b/system/t13_etcd/UpdateMirror23TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror23Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror24TestEtcd_gold b/system/t13_etcd/UpdateMirror24TestEtcd_gold new file mode 120000 index 000000000..317216190 --- /dev/null +++ b/system/t13_etcd/UpdateMirror24TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror24Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror25TestEtcd_gold b/system/t13_etcd/UpdateMirror25TestEtcd_gold new file mode 120000 index 000000000..a3a057cf7 --- /dev/null +++ b/system/t13_etcd/UpdateMirror25TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror25Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror2TestEtcd_gold b/system/t13_etcd/UpdateMirror2TestEtcd_gold new file mode 120000 index 000000000..9bf2cf84e --- /dev/null +++ b/system/t13_etcd/UpdateMirror2TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror3TestEtcd_gold b/system/t13_etcd/UpdateMirror3TestEtcd_gold new file mode 120000 index 000000000..3a18595bc --- /dev/null +++ b/system/t13_etcd/UpdateMirror3TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror4TestEtcd_gold b/system/t13_etcd/UpdateMirror4TestEtcd_gold new file mode 120000 index 000000000..33efda8a4 --- /dev/null +++ b/system/t13_etcd/UpdateMirror4TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror5TestEtcd_gold b/system/t13_etcd/UpdateMirror5TestEtcd_gold new file mode 120000 index 000000000..3dd08aedb --- /dev/null +++ b/system/t13_etcd/UpdateMirror5TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror6TestEtcd_gold b/system/t13_etcd/UpdateMirror6TestEtcd_gold new file mode 120000 index 000000000..3ddffa3a2 --- /dev/null +++ b/system/t13_etcd/UpdateMirror6TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror6Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror7TestEtcd_gold b/system/t13_etcd/UpdateMirror7TestEtcd_gold new file mode 120000 index 000000000..283a8c0c2 --- /dev/null +++ b/system/t13_etcd/UpdateMirror7TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror7Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror8TestEtcd_gold b/system/t13_etcd/UpdateMirror8TestEtcd_gold new file mode 120000 index 000000000..2cb66953f --- /dev/null +++ b/system/t13_etcd/UpdateMirror8TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror8Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror9TestEtcd_gold b/system/t13_etcd/UpdateMirror9TestEtcd_gold new file mode 120000 index 000000000..4105a0d6e --- /dev/null +++ b/system/t13_etcd/UpdateMirror9TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror9Test_gold \ No newline at end of file diff --git a/system/t13_etcd/__init__.py b/system/t13_etcd/__init__.py new file mode 100644 index 000000000..d3a06023b --- /dev/null +++ b/system/t13_etcd/__init__.py @@ -0,0 +1,3 @@ +""" +Testing aptly with etcd DB +""" diff --git a/system/t13_etcd/install-etcd.sh b/system/t13_etcd/install-etcd.sh new file mode 100755 index 000000000..163a3f85d --- /dev/null +++ b/system/t13_etcd/install-etcd.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# etcd test env +ETCD_VER=v3.5.2 +DOWNLOAD_URL=https://storage.googleapis.com/etcd + +if [ ! -e /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz ]; then + curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz +fi + +mkdir /srv/etcd +tar xf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /srv/etcd --strip-components=1 diff --git a/system/t13_etcd/mirror_update.py b/system/t13_etcd/mirror_update.py new file mode 100644 index 000000000..d03b2c4d5 --- /dev/null +++ b/system/t13_etcd/mirror_update.py @@ -0,0 +1,234 @@ +# reuse existing tests: +from t04_mirror.update import UpdateMirror1Test, \ + UpdateMirror2Test, \ + UpdateMirror3Test, \ + UpdateMirror4Test, \ + UpdateMirror5Test, \ + UpdateMirror6Test, \ + UpdateMirror7Test, \ + UpdateMirror8Test, \ + UpdateMirror9Test, \ + UpdateMirror10Test, \ + UpdateMirror11Test, \ + UpdateMirror12Test, \ + UpdateMirror13Test, \ + UpdateMirror14Test, \ + UpdateMirror17Test, \ + UpdateMirror18Test, \ + UpdateMirror19Test, \ + UpdateMirror20Test, \ + UpdateMirror21Test, \ + UpdateMirror22Test, \ + UpdateMirror23Test, \ + UpdateMirror24Test, \ + UpdateMirror25Test + + +TEST_IGNORE = ["UpdateMirror1Test", + "UpdateMirror2Test", + "UpdateMirror3Test", + "UpdateMirror4Test", + "UpdateMirror5Test", + "UpdateMirror6Test", + "UpdateMirror7Test", + "UpdateMirror8Test", + "UpdateMirror9Test", + "UpdateMirror10Test", + "UpdateMirror11Test", + "UpdateMirror12Test", + "UpdateMirror13Test", + "UpdateMirror14Test", + "UpdateMirror17Test", + "UpdateMirror18Test", + "UpdateMirror19Test", + "UpdateMirror20Test", + "UpdateMirror21Test", + "UpdateMirror22Test", + "UpdateMirror23Test", + "UpdateMirror24Test", + "UpdateMirror25Test" + ] + + +class UpdateMirror1TestEtcd(UpdateMirror1Test): + """ + update mirrors: regular update + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror2TestEtcd(UpdateMirror2Test): + """ + update mirrors: no such repo + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror3TestEtcd(UpdateMirror3Test): + """ + update mirrors: wrong checksum in release file + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror4TestEtcd(UpdateMirror4Test): + """ + update mirrors: wrong checksum in release file, but ignore + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror5TestEtcd(UpdateMirror5Test): + """ + update mirrors: wrong checksum in package + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror6TestEtcd(UpdateMirror6Test): + """ + update mirrors: wrong checksum in package, but ignore + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror7TestEtcd(UpdateMirror7Test): + """ + update mirrors: flat repository + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror8TestEtcd(UpdateMirror8Test): + """ + update mirrors: with sources (already in pool) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror9TestEtcd(UpdateMirror9Test): + """ + update mirrors: flat repository + sources + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror10TestEtcd(UpdateMirror10Test): + """ + update mirrors: filtered + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror11TestEtcd(UpdateMirror11Test): + """ + update mirrors: update over FTP + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror12TestEtcd(UpdateMirror12Test): + """ + update mirrors: update with udebs + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror13TestEtcd(UpdateMirror13Test): + """ + update mirrors: regular update with --skip-existing-packages option + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror14TestEtcd(UpdateMirror14Test): + """ + update mirrors: regular update with --skip-existing-packages option + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror17TestEtcd(UpdateMirror17Test): + """ + update mirrors: update for mirror but with file in pool on legacy MD5 location + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror18TestEtcd(UpdateMirror18Test): + """ + update mirrors: update for mirror but with file in pool on legacy MD5 location and disabled legacy path support + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror19TestEtcd(UpdateMirror19Test): + """ + update mirrors: correct matching of Release checksums + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror20TestEtcd(UpdateMirror20Test): + """ + update mirrors: flat repository (internal GPG implementation) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror21TestEtcd(UpdateMirror21Test): + """ + update mirrors: correct matching of Release checksums (internal pgp implementation) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror22TestEtcd(UpdateMirror22Test): + """ + update mirrors: SHA512 checksums only + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror23TestEtcd(UpdateMirror23Test): + """ + update mirrors: update with installer + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror24TestEtcd(UpdateMirror24Test): + """ + update mirrors: update with installer with separate gpg file + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror25TestEtcd(UpdateMirror25Test): + """ + update mirrors: mirror with / in distribution + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/publish_drop.py b/system/t13_etcd/publish_drop.py new file mode 100644 index 000000000..8f9f60fc3 --- /dev/null +++ b/system/t13_etcd/publish_drop.py @@ -0,0 +1,92 @@ +# reuse existing tests: +from t06_publish.drop import PublishDrop1Test, \ + PublishDrop2Test, \ + PublishDrop3Test, \ + PublishDrop4Test, \ + PublishDrop5Test, \ + PublishDrop6Test, \ + PublishDrop7Test, \ + PublishDrop8Test, \ + PublishDrop9Test + +TEST_IGNORE = ["PublishDrop1Test", + "PublishDrop2Test", + "PublishDrop3Test", + "PublishDrop4Test", + "PublishDrop5Test", + "PublishDrop6Test", + "PublishDrop7Test", + "PublishDrop8Test", + "PublishDrop9Test"] + + +class PublishDrop1TestEtcd(PublishDrop1Test): + """ + publish drop: existing snapshot + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop2TestEtcd(PublishDrop2Test): + """ + publish drop: under prefix + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop3TestEtcd(PublishDrop3Test): + """ + publish drop: drop one distribution + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop4TestEtcd(PublishDrop4Test): + """ + publish drop: drop one of components + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop5TestEtcd(PublishDrop5Test): + """ + publish drop: component cleanup + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop6TestEtcd(PublishDrop6Test): + """ + publish drop: no publish + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop7TestEtcd(PublishDrop7Test): + """ + publish drop: under prefix with trailing & leading slashes + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop8TestEtcd(PublishDrop8Test): + """ + publish drop: skip component cleanup + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop9TestEtcd(PublishDrop9Test): + """ + publish drop: component cleanup after first cleanup skipped + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/publish_list.py b/system/t13_etcd/publish_list.py new file mode 100644 index 000000000..8825d05ef --- /dev/null +++ b/system/t13_etcd/publish_list.py @@ -0,0 +1,48 @@ +# reuse existing tests: +from t06_publish.list import PublishList1Test, \ + PublishList2Test, \ + PublishList3Test, \ + PublishList4Test, \ + PublishList5Test + +TEST_IGNORE = ["PublishList1Test", "PublishList2Test", "PublishList3Test", "PublishList4Test", "PublishList5Test"] + + +class PublishList1TestEtcd(PublishList1Test): + """ + publish list: empty list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList2TestEtcd(PublishList2Test): + """ + publish list: several repos list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList3TestEtcd(PublishList3Test): + """ + publish list: several repos list, raw + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList4TestEtcd(PublishList4Test): + """ + publish list json: empty list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList5TestEtcd(PublishList5Test): + """ + publish list json: several repos list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/start-etcd.sh b/system/t13_etcd/start-etcd.sh new file mode 100755 index 000000000..ae6c0a45e --- /dev/null +++ b/system/t13_etcd/start-etcd.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ -e /tmp/etcd.pid ]; then + echo etcd already running, killing.. + etcdpid=`cat /tmp/etcd.pid` + kill $etcdpid + sleep 2 +fi + +finish() +{ + if [ -n "$etcdpid" ]; then + echo terminating etcd + kill $etcdpid + fi +} +trap finish INT + +/srv/etcd/etcd --max-request-bytes '1073741824' --data-dir /tmp/etcd-data & +echo $! > /tmp/etcd.pid +etcdpid=`cat /tmp/etcd.pid` +wait $etcdpid +echo etcd terminated diff --git a/system/t13_etcd/test_release b/system/t13_etcd/test_release new file mode 120000 index 000000000..e8d20bcbb --- /dev/null +++ b/system/t13_etcd/test_release @@ -0,0 +1 @@ +../t04_mirror/test_release \ No newline at end of file diff --git a/system/t13_etcd/test_release2 b/system/t13_etcd/test_release2 new file mode 120000 index 000000000..a77f30710 --- /dev/null +++ b/system/t13_etcd/test_release2 @@ -0,0 +1 @@ +../t04_mirror/test_release2 \ No newline at end of file From dce33a998d0841a82f167797133f0f3af2a9c3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Sat, 27 Jul 2024 17:55:00 +0200 Subject: [PATCH 07/12] etcd: implement temporary db support - temporary db support is implemented with a unique key prefix - prevent closing etcd connection when closing temporary db --- database/etcddb/database.go | 2 +- database/etcddb/storage.go | 52 +++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/database/etcddb/database.go b/database/etcddb/database.go index 761c81fe9..bdc94de74 100644 --- a/database/etcddb/database.go +++ b/database/etcddb/database.go @@ -32,7 +32,7 @@ func NewDB(url string) (database.Storage, error) { if err != nil { return nil, err } - return &EtcDStorage{url, cli}, nil + return &EtcDStorage{url, cli, ""}, nil } func NewOpenDB(url string) (database.Storage, error) { diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go index c36c3beac..221b9ebd1 100644 --- a/database/etcddb/storage.go +++ b/database/etcddb/storage.go @@ -2,21 +2,38 @@ package etcddb import ( "github.com/aptly-dev/aptly/database" + "github.com/pborman/uuid" clientv3 "go.etcd.io/etcd/client/v3" + + "fmt" ) type EtcDStorage struct { - url string - db *clientv3.Client + url string + db *clientv3.Client + tmpPrefix string // prefix for temporary DBs } // CreateTemporary creates new DB of the same type in temp dir func (s *EtcDStorage) CreateTemporary() (database.Storage, error) { - return s, nil + tmp := uuid.NewRandom().String() + return &EtcDStorage{ + url: s.url, + db: s.db, + tmpPrefix: tmp, + }, nil +} + +func (s *EtcDStorage) applyPrefix(key []byte) []byte { + if len(s.tmpPrefix) != 0 { + return append([]byte(s.tmpPrefix+"/"), key...) + } + return key } // Get key value from etcd func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { + key = s.applyPrefix(key) getResp, err := s.db.Get(Ctx, string(key)) if err != nil { return @@ -33,6 +50,7 @@ func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { // Put saves key to etcd, if key has the same value in DB already, it is not saved func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { + key = s.applyPrefix(key) _, err = s.db.Put(Ctx, string(key), string(value)) if err != nil { return @@ -42,6 +60,7 @@ func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { // Delete removes key from etcd func (s *EtcDStorage) Delete(key []byte) (err error) { + key = s.applyPrefix(key) _, err = s.db.Delete(Ctx, string(key)) if err != nil { return @@ -51,6 +70,7 @@ func (s *EtcDStorage) Delete(key []byte) (err error) { // KeysByPrefix returns all keys that start with prefix func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { + prefix = s.applyPrefix(prefix) result := make([][]byte, 0, 20) getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) if err != nil { @@ -67,6 +87,7 @@ func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { // FetchByPrefix returns all values with keys that start with prefix func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { + prefix = s.applyPrefix(prefix) result := make([][]byte, 0, 20) getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) if err != nil { @@ -83,6 +104,7 @@ func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { // HasPrefix checks whether it can find any key with given prefix and returns true if one exists func (s *EtcDStorage) HasPrefix(prefix []byte) bool { + prefix = s.applyPrefix(prefix) getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) if err != nil { return false @@ -96,6 +118,7 @@ func (s *EtcDStorage) HasPrefix(prefix []byte) bool { // ProcessByPrefix iterates through all entries where key starts with prefix and calls // StorageProcessor on key value pair func (s *EtcDStorage) ProcessByPrefix(prefix []byte, proc database.StorageProcessor) error { + prefix = s.applyPrefix(prefix) getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) if err != nil { return err @@ -112,6 +135,10 @@ func (s *EtcDStorage) ProcessByPrefix(prefix []byte, proc database.StorageProces // Close finishes etcd connect func (s *EtcDStorage) Close() error { + // do not close temporary db + if len(s.tmpPrefix) != 0 { + return nil + } if s.db == nil { return nil } @@ -132,6 +159,9 @@ func (s *EtcDStorage) Open() error { // CreateBatch creates a Batch object func (s *EtcDStorage) CreateBatch() database.Batch { + if s.db == nil { + return nil + } return &EtcDBatch{ db: s.db, } @@ -147,13 +177,25 @@ func (s *EtcDStorage) OpenTransaction() (database.Transaction, error) { return &transaction{t: kvc}, nil } -// CompactDB compacts database by merging layers +// CompactDB does nothing for etcd func (s *EtcDStorage) CompactDB() error { return nil } -// Drop removes all the etcd files (DANGEROUS!) +// Drop removes only temporary DBs with etcd (i.e. remove all prefixed keys) func (s *EtcDStorage) Drop() error { + if len(s.tmpPrefix) != 0 { + getResp, err := s.db.Get(Ctx, s.tmpPrefix, clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, kv := range getResp.Kvs { + _, err = s.db.Delete(Ctx, string(kv.Key)) + if err != nil { + return fmt.Errorf("cannot delete tempdb entry: %s", kv.Key) + } + } + } return nil } From 509207f9c360158ef9b05d497a8a65cb1e5f5464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Thu, 25 Jul 2024 11:59:38 +0200 Subject: [PATCH 08/12] etcd: implement batch operations - cache the operations internally in a list - Write() applies the list to etcd --- database/etcddb/batch.go | 27 +++++++++++++++++++++++---- database/etcddb/storage.go | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/database/etcddb/batch.go b/database/etcddb/batch.go index e50c11624..24b83de94 100644 --- a/database/etcddb/batch.go +++ b/database/etcddb/batch.go @@ -6,7 +6,8 @@ import ( ) type EtcDBatch struct { - db *clientv3.Client + s *EtcDStorage + ops []clientv3.Op } type WriteOptions struct { @@ -14,17 +15,35 @@ type WriteOptions struct { Sync bool } -func (b *EtcDBatch) Put(key, value []byte) (err error) { - _, err = b.db.Put(Ctx, string(key), string(value)) +func (b *EtcDBatch) Put(key []byte, value []byte) (err error) { + b.ops = append(b.ops, clientv3.OpPut(string(key), string(value))) return } func (b *EtcDBatch) Delete(key []byte) (err error) { - _, err = b.db.Delete(Ctx, string(key)) + b.ops = append(b.ops, clientv3.OpDelete(string(key))) return } func (b *EtcDBatch) Write() (err error) { + kv := clientv3.NewKV(b.s.db) + + batchSize := 128 + for i := 0; i < len(b.ops); i += batchSize { + txn := kv.Txn(Ctx) + end := i + batchSize + if end > len(b.ops) { + end = len(b.ops) + } + + batch := b.ops[i:end] + txn.Then(batch...) + _, err = txn.Commit() + if err != nil { + panic(err) + } + } + return } diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go index 221b9ebd1..b1faa8855 100644 --- a/database/etcddb/storage.go +++ b/database/etcddb/storage.go @@ -163,7 +163,7 @@ func (s *EtcDStorage) CreateBatch() database.Batch { return nil } return &EtcDBatch{ - db: s.db, + s: s, } } From 9182b9c1bb3ca7c26cfd8e463175736fe6a07fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Thu, 25 Jul 2024 17:39:21 +0200 Subject: [PATCH 09/12] etcd: implement transactions - use temporary db for lookups in transactions - use batch implementation to commit transaction --- database/etcddb/database_test.go | 5 +-- database/etcddb/storage.go | 6 ++-- database/etcddb/transaction.go | 58 +++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/database/etcddb/database_test.go b/database/etcddb/database_test.go index 1e601b4e4..da1a741b7 100644 --- a/database/etcddb/database_test.go +++ b/database/etcddb/database_test.go @@ -132,7 +132,8 @@ func (s *EtcDDBSuite) TestTransactionCommit(c *C) { transaction.Put(key2, value2) v, err := s.db.Get(key) c.Check(v, DeepEquals, value) - transaction.Delete(key) + err = transaction.Delete(key) + c.Assert(err, IsNil) _, err = transaction.Get(key2) c.Assert(err, IsNil) @@ -152,5 +153,5 @@ func (s *EtcDDBSuite) TestTransactionCommit(c *C) { c.Check(v2, DeepEquals, value2) _, err = transaction.Get(key) - c.Assert(err, IsNil) + c.Assert(err, NotNil) } diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go index b1faa8855..64d67eb5e 100644 --- a/database/etcddb/storage.go +++ b/database/etcddb/storage.go @@ -40,6 +40,7 @@ func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { } for _, kv := range getResp.Kvs { value = kv.Value + break } if len(value) == 0 { err = database.ErrNotFound @@ -169,12 +170,11 @@ func (s *EtcDStorage) CreateBatch() database.Batch { // OpenTransaction creates new transaction. func (s *EtcDStorage) OpenTransaction() (database.Transaction, error) { - cli, err := internalOpen(s.url) + tmpdb, err := s.CreateTemporary() if err != nil { return nil, err } - kvc := clientv3.NewKV(cli) - return &transaction{t: kvc}, nil + return &transaction{s: s, tmpdb: tmpdb}, nil } // CompactDB does nothing for etcd diff --git a/database/etcddb/transaction.go b/database/etcddb/transaction.go index 4b0830563..01f54dad1 100644 --- a/database/etcddb/transaction.go +++ b/database/etcddb/transaction.go @@ -3,51 +3,71 @@ package etcddb import ( "github.com/aptly-dev/aptly/database" clientv3 "go.etcd.io/etcd/client/v3" - "go.etcd.io/etcd/client/v3/clientv3util" ) type transaction struct { - t clientv3.KV + s *EtcDStorage + tmpdb database.Storage + ops []clientv3.Op } // Get implements database.Reader interface. -func (t *transaction) Get(key []byte) ([]byte, error) { - getResp, err := t.t.Get(Ctx, string(key)) +func (t *transaction) Get(key []byte) (value []byte, err error) { + value, err = t.tmpdb.Get(key) + // if not found, search main db if err != nil { - return nil, err + value, err = t.s.Get(key) } - - var value []byte - for _, kv := range getResp.Kvs { - valc := make([]byte, len(kv.Value)) - copy(valc, kv.Value) - value = valc - } - - return value, nil + return } // Put implements database.Writer interface. func (t *transaction) Put(key, value []byte) (err error) { - _, err = t.t.Txn(Ctx). - If().Then(clientv3.OpPut(string(key), string(value))).Commit() + err = t.tmpdb.Put(key, value) + if err != nil { + return + } + t.ops = append(t.ops, clientv3.OpPut(string(key), string(value))) return } // Delete implements database.Writer interface. func (t *transaction) Delete(key []byte) (err error) { - _, err = t.t.Txn(Ctx). - If(clientv3util.KeyExists(string(key))). - Then(clientv3.OpDelete(string(key))).Commit() + err = t.tmpdb.Delete(key) + if err != nil { + return + } + t.ops = append(t.ops, clientv3.OpDelete(string(key))) return } func (t *transaction) Commit() (err error) { + kv := clientv3.NewKV(t.s.db) + + batchSize := 128 + for i := 0; i < len(t.ops); i += batchSize { + txn := kv.Txn(Ctx) + end := i + batchSize + if end > len(t.ops) { + end = len(t.ops) + } + + batch := t.ops[i:end] + txn.Then(batch...) + _, err = txn.Commit() + if err != nil { + panic(err) + } + } + t.ops = []clientv3.Op{} + return } // Discard is safe to call after Commit(), it would be no-op func (t *transaction) Discard() { + t.ops = []clientv3.Op{} + t.tmpdb.Drop() return } From 9b428e4ace9ada8b93ae6b7b0c3ee22839094af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Tue, 23 Jul 2024 15:44:31 +0200 Subject: [PATCH 10/12] update go.mod --- go.sum | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/go.sum b/go.sum index 2de108cf8..14b0d6b72 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -15,10 +17,16 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E= github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= @@ -57,6 +65,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwF github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +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/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -66,6 +76,8 @@ github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiays github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= @@ -76,14 +88,27 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= @@ -91,10 +116,15 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -102,24 +132,49 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -133,8 +188,13 @@ github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +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/kjk/lzma v0.0.0-20161016003348-3fd93898850d h1:RnWZeH8N8KXfbwMTex/KKMYMj0FJRCF6tQubUuQ02GM= github.com/kjk/lzma v0.0.0-20161016003348-3fd93898850d/go.mod h1:phT/jsRPBAEqjAibu1BurrabCBNTYiVI+zbmyCZJY6Q= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -145,6 +205,9 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -172,6 +235,7 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da h1:Iu5QFXIMK/YrHJ0NgUnK0rqYTTyb0ldt/rqNenAj39U= @@ -179,8 +243,11 @@ github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da/go.mod h1:NfnmoBY0gGk github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= @@ -195,21 +262,36 @@ github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -218,6 +300,8 @@ github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/saracen/walker v0.1.3 h1:YtcKKmpRPy6XJTHJ75J2QYXXZYWnZNQxPCVqZSHVV/g= github.com/saracen/walker v0.1.3/go.mod h1:FU+7qU8DeQQgSZDmmThMJi93kPkLFgy0oVAcLxurjIk= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smira/commander v0.0.0-20140515201010-f408b00e68d5 h1:jLFwP6SDEUHmb6QSu5n2FHseWzMio1ou1FV9p7W6p7I= github.com/smira/commander v0.0.0-20140515201010-f408b00e68d5/go.mod h1:XTQy55hw5s3pxmC42m7X0/b+9naXQ1rGN9Of6BGIZmU= github.com/smira/flag v0.0.0-20170926215700-695ea5e84e76 h1:OM075OkN4x9IB1mbzkzaKaJjFxx8Mfss8Z3E1LHwawQ= @@ -227,9 +311,13 @@ github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d/go.mod h1:Jm github.com/smira/go-xz v0.1.0 h1:1zVLT1sITUKcWNysfHMLZWJ2Yh7yJfhREsgmUdK4zb0= github.com/smira/go-xz v0.1.0/go.mod h1:OmdEWnIIkuLzRLHGF4YtjDzF9VFUevEcP6YxDPRqVrs= 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= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -245,11 +333,29 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.0-rc.0 h1:oPIG9qBFXiGJFM1StoFd5EVllfVIhd7pPjB/mcMCzCg= +go.etcd.io/etcd/api/v3 v3.5.0-rc.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0-rc.0 h1:7mW2vCG+tthhWwORSD/G0eesRZ6ZkOh19P7CyrT9xfA= +go.etcd.io/etcd/client/pkg/v3 v3.5.0-rc.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v3 v3.5.0-rc.0 h1:W2gUtoUho3+X5tCffYA3VfA7fH9DokrhGMscvZskuXc= +go.etcd.io/etcd/client/v3 v3.5.0-rc.0/go.mod h1:5+cKiK2IEMa230cLFrLL3+3sKlPPKASjiLOmG8tZ8vY= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -257,13 +363,33 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -271,21 +397,37 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -308,6 +450,7 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -318,16 +461,52 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -335,10 +514,18 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 6fc06c527c4d8a3e5374ab621dddc18975ae144a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Mon, 29 Jul 2024 21:32:04 +0200 Subject: [PATCH 11/12] apply PR feedback --- Makefile | 2 +- context/context.go | 18 ++++++++--------- database/etcddb/database.go | 23 +++++----------------- database/etcddb/database_test.go | 5 +++-- database/etcddb/storage.go | 33 +++++++++++++++----------------- 5 files changed, 32 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 7c525fa99..0b7de186e 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ docker-test: install test: test -d /srv/etcd || system/t13_etcd/install-etcd.sh system/t13_etcd/start-etcd.sh & - echo Running go test + @echo Running go test go test -v ./... -gocheck.v=true -coverprofile=unit.out kill `cat /tmp/etcd.pid` diff --git a/context/context.go b/context/context.go index 8838f26ba..7cc7c6efd 100644 --- a/context/context.go +++ b/context/context.go @@ -289,20 +289,18 @@ func (context *AptlyContext) Database() (database.Storage, error) { func (context *AptlyContext) _database() (database.Storage, error) { if context.database == nil { var err error - - if context.config().DatabaseBackend.Type == "etcd" { - context.database, err = etcddb.NewDB(context.config().DatabaseBackend.URL) - } else if context.config().DatabaseBackend.Type == "leveldb" { - if context.config().DatabaseBackend.DbPath != "" { - dbPath := filepath.Join(context.config().RootDir, context.config().DatabaseBackend.DbPath) - context.database, err = goleveldb.NewDB(dbPath) - } else { + switch context.config().DatabaseBackend.Type { + case "leveldb": + if len(context.config().DatabaseBackend.DbPath) == 0 { return nil, errors.New("leveldb databaseBackend config invalid") } - } else { + dbPath := filepath.Join(context.config().RootDir, context.config().DatabaseBackend.DbPath) + context.database, err = goleveldb.NewDB(dbPath) + case "etcd": + context.database, err = etcddb.NewDB(context.config().DatabaseBackend.URL) + default: context.database, err = goleveldb.NewDB(context.dbPath()) } - if err != nil { return nil, fmt.Errorf("can't instantiate database: %s", err) } diff --git a/database/etcddb/database.go b/database/etcddb/database.go index bdc94de74..37a222e63 100644 --- a/database/etcddb/database.go +++ b/database/etcddb/database.go @@ -10,21 +10,17 @@ import ( var Ctx = context.TODO() -func internalOpen(url string) (*clientv3.Client, error) { +func internalOpen(url string) (cli *clientv3.Client, err error) { cfg := clientv3.Config{ Endpoints: []string{url}, DialTimeout: 30 * time.Second, - MaxCallSendMsgSize: (2048 * 1024 * 1024) - 1, - MaxCallRecvMsgSize: (2048 * 1024 * 1024) - 1, + MaxCallSendMsgSize: 2147483647, // (2048 * 1024 * 1024) - 1 + MaxCallRecvMsgSize: 2147483647, DialKeepAliveTimeout: 7200 * time.Second, } - cli, err := clientv3.New(cfg) - if err != nil { - return nil, err - } - - return cli, nil + cli, err = clientv3.New(cfg) + return } func NewDB(url string) (database.Storage, error) { @@ -34,12 +30,3 @@ func NewDB(url string) (database.Storage, error) { } return &EtcDStorage{url, cli, ""}, nil } - -func NewOpenDB(url string) (database.Storage, error) { - db, err := NewDB(url) - if err != nil { - return nil, err - } - - return db, nil -} diff --git a/database/etcddb/database_test.go b/database/etcddb/database_test.go index da1a741b7..b31e5599e 100644 --- a/database/etcddb/database_test.go +++ b/database/etcddb/database_test.go @@ -22,13 +22,13 @@ var _ = Suite(&EtcDDBSuite{}) func (s *EtcDDBSuite) SetUpTest(c *C) { var err error - s.db, err = etcddb.NewOpenDB("127.0.0.1:2379") + s.db, err = etcddb.NewDB("127.0.0.1:2379") c.Assert(err, IsNil) } func (s *EtcDDBSuite) TestSetUpTest(c *C) { var err error - s.db, err = etcddb.NewOpenDB("127.0.0.1:2379") + s.db, err = etcddb.NewDB("127.0.0.1:2379") c.Assert(err, IsNil) } @@ -155,3 +155,4 @@ func (s *EtcDDBSuite) TestTransactionCommit(c *C) { _, err = transaction.Get(key) c.Assert(err, NotNil) } + diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go index 64d67eb5e..efc4cf64d 100644 --- a/database/etcddb/storage.go +++ b/database/etcddb/storage.go @@ -33,8 +33,8 @@ func (s *EtcDStorage) applyPrefix(key []byte) []byte { // Get key value from etcd func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { - key = s.applyPrefix(key) - getResp, err := s.db.Get(Ctx, string(key)) + realKey := s.applyPrefix(key) + getResp, err := s.db.Get(Ctx, string(realKey)) if err != nil { return } @@ -51,8 +51,8 @@ func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { // Put saves key to etcd, if key has the same value in DB already, it is not saved func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { - key = s.applyPrefix(key) - _, err = s.db.Put(Ctx, string(key), string(value)) + realKey := s.applyPrefix(key) + _, err = s.db.Put(Ctx, string(realKey), string(value)) if err != nil { return } @@ -61,8 +61,8 @@ func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { // Delete removes key from etcd func (s *EtcDStorage) Delete(key []byte) (err error) { - key = s.applyPrefix(key) - _, err = s.db.Delete(Ctx, string(key)) + realKey := s.applyPrefix(key) + _, err = s.db.Delete(Ctx, string(realKey)) if err != nil { return } @@ -71,9 +71,9 @@ func (s *EtcDStorage) Delete(key []byte) (err error) { // KeysByPrefix returns all keys that start with prefix func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { - prefix = s.applyPrefix(prefix) + realPrefix := s.applyPrefix(prefix) result := make([][]byte, 0, 20) - getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) if err != nil { return nil } @@ -88,9 +88,9 @@ func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { // FetchByPrefix returns all values with keys that start with prefix func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { - prefix = s.applyPrefix(prefix) + realPrefix := s.applyPrefix(prefix) result := make([][]byte, 0, 20) - getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) if err != nil { return nil } @@ -105,22 +105,19 @@ func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { // HasPrefix checks whether it can find any key with given prefix and returns true if one exists func (s *EtcDStorage) HasPrefix(prefix []byte) bool { - prefix = s.applyPrefix(prefix) - getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + realPrefix := s.applyPrefix(prefix) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) if err != nil { return false } - if getResp.Count != 0 { - return true - } - return false + return getResp.Count > 0 } // ProcessByPrefix iterates through all entries where key starts with prefix and calls // StorageProcessor on key value pair func (s *EtcDStorage) ProcessByPrefix(prefix []byte, proc database.StorageProcessor) error { - prefix = s.applyPrefix(prefix) - getResp, err := s.db.Get(Ctx, string(prefix), clientv3.WithPrefix()) + realPrefix := s.applyPrefix(prefix) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) if err != nil { return err } From 61cb188282e445f81ffb2eba0520ed6a8c591f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Wed, 31 Jul 2024 16:43:01 +0200 Subject: [PATCH 12/12] system tests: fix expired ppa mirror key --- system/t04_mirror/CreateMirror18Test_gold | 14 ++++++-------- system/t04_mirror/CreateMirror18Test_mirror_show | 2 +- system/t04_mirror/create.py | 5 ++++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/system/t04_mirror/CreateMirror18Test_gold b/system/t04_mirror/CreateMirror18Test_gold index 905ea7687..0444a91e4 100644 --- a/system/t04_mirror/CreateMirror18Test_gold +++ b/system/t04_mirror/CreateMirror18Test_gold @@ -1,12 +1,10 @@ Downloading: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease -Error (retrying): HTTP code 404 while fetching http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease -Retrying 0 http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Download Error: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease -Downloading: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release -Downloading: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg -gpgv: can't allocate lock for '/home/runner/.gnupg/aptlytest.gpg' -gpgv: Signature made Mon Oct 22 13:19:50 2012 UTC -gpgv: using RSA key A5279A973B1F56C0 +gpgv: can't allocate lock for '/home/runner/.gnupg/ppa.gpg' +gpgv: Signature made Sun Jul 28 07:57:01 2024 UTC +gpgv: using RSA key 5BFCD481D86D5824470E469F9000B1C3A01F726C +gpgv: Good signature from "Launchpad PPA for Anton Gladky" +gpgv: Signature made Sun Jul 28 07:57:01 2024 UTC +gpgv: using RSA key 02219381E9161C78A46CB2BFA5279A973B1F56C0 gpgv: Good signature from "Launchpad sim" Mirror [mirror18]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick successfully added. diff --git a/system/t04_mirror/CreateMirror18Test_mirror_show b/system/t04_mirror/CreateMirror18Test_mirror_show index d2d32be5c..750161b0d 100644 --- a/system/t04_mirror/CreateMirror18Test_mirror_show +++ b/system/t04_mirror/CreateMirror18Test_mirror_show @@ -11,7 +11,7 @@ Information from release file: Architectures: amd64 armel i386 powerpc Codename: maverick Components: main -Date: Mon, 22 Oct 2012 13:19:50 UTC +Date: Sun, 28 Jul 2024 7:57:00 UTC Description: Ubuntu Maverick 10.10 Label: gnuplot diff --git a/system/t04_mirror/create.py b/system/t04_mirror/create.py index 6f2e413d8..d02350e49 100644 --- a/system/t04_mirror/create.py +++ b/system/t04_mirror/create.py @@ -222,7 +222,10 @@ class CreateMirror18Test(BaseTest): "ppaCodename": "maverick", } - runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror18 ppa:gladky-anton/gnuplot" + fixtureCmds = [ + "gpg --no-default-keyring --keyring=ppa.gpg --keyserver=hkp://keyserver.ubuntu.com:80 --recv-keys 5BFCD481D86D5824470E469F9000B1C3A01F726C 02219381E9161C78A46CB2BFA5279A973B1F56C0" + ] + runCmd = "aptly mirror create -keyring=ppa.gpg mirror18 ppa:gladky-anton/gnuplot" def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using', '', s)