diff --git a/go.mod b/go.mod index 49e76b0a7..d6c1f1fb2 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20220329045155-d2a8118ac5c7 github.com/aws/aws-sdk-go v1.40.39 github.com/codeskyblue/go-sh v0.0.0-20170112005953-b097669b1569 + github.com/coreos/etcd v3.3.27+incompatible github.com/golang/mock v1.4.4 github.com/google/uuid v1.1.2 github.com/hashicorp/go-version v1.2.1 @@ -18,6 +19,7 @@ require ( github.com/libopenstorage/secrets v0.0.0-20210908194121-a1d19aa9713a github.com/oracle/oci-go-sdk/v65 v65.13.1 github.com/pborman/uuid v1.2.0 + github.com/portworx/kvdb v0.0.0-20230326003017-21a38cf82d4b github.com/portworx/sched-ops v1.20.4-rc1.0.20211217234328-ead591c0f22d github.com/prometheus/client_golang v1.9.0 github.com/sirupsen/logrus v1.8.1 @@ -74,6 +76,7 @@ require ( github.com/prometheus/procfs v0.2.0 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.2.0 // indirect go.opencensus.io v0.22.4 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.6.0 // indirect diff --git a/go.sum b/go.sum index 55da5e3ef..dea1c0e88 100644 --- a/go.sum +++ b/go.sum @@ -317,6 +317,8 @@ github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA= +github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= @@ -1223,7 +1225,12 @@ github.com/portworx/kvdb v0.0.0-20190105022415-cccaa09abfc9/go.mod h1:Q8YyrNDvPp github.com/portworx/kvdb v0.0.0-20191223203141-f42097b1fcd8/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= github.com/portworx/kvdb v0.0.0-20200311180812-b2c72382d652/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= github.com/portworx/kvdb v0.0.0-20200723230726-2734b7f40194/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= +github.com/portworx/kvdb v0.0.0-20200929023115-b312c7519467 h1:jkqzdbOnejgSN5HG/FLt4enNrozWT/K+nlmaRm3P1II= github.com/portworx/kvdb v0.0.0-20200929023115-b312c7519467/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= +github.com/portworx/kvdb v0.0.0-20221027170939-f1680e5db6db h1:ycu2xaymWoDkRgIUadkX1XjlKs0RWHtkk5HI/JjF59g= +github.com/portworx/kvdb v0.0.0-20221027170939-f1680e5db6db/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= +github.com/portworx/kvdb v0.0.0-20230326003017-21a38cf82d4b h1:nP+m9tYQv2cWbN9wAwjlhJU9FZRs7GaYszhLJBLAg/I= +github.com/portworx/kvdb v0.0.0-20230326003017-21a38cf82d4b/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M= github.com/portworx/px-backup-api v1.0.1-0.20200915150042-274508e876ef/go.mod h1:puy7YVXeb6glot1vVCIePIiRLSwB//+rFtN2ZjvXeEw= github.com/portworx/pxc v0.33.0/go.mod h1:Tl7hf4K2CDr0XtxzM08sr9H/KsMhscjf9ydb+MnT0U4= github.com/portworx/sched-ops v0.0.0-20200123020607-b0799c4686f5/go.mod h1:yb1ypNIiZQAmM7xAWGzO6dydwl/+vNC0WjUm5IvHUEY= diff --git a/store/store.go b/store/store.go new file mode 100644 index 000000000..245217523 --- /dev/null +++ b/store/store.go @@ -0,0 +1,126 @@ +package store + +import ( + "fmt" + "github.com/portworx/kvdb" + "time" +) + +// PX specific scheduler constants +const ( + // Kubernetes identifies kubernetes as the scheduler + Kubernetes = "kubernetes" +) + +// Params is the parameters to use for the Store object +type Params struct { + // Kv is the bootstrap kvdb instance + Kv kvdb.Kvdb + // InternalKvdb indicates if PX is using internal kvdb or not + InternalKvdb bool + // SchedulerType indicates the platform pods are running on. e.g Kubernetes + SchedulerType string +} + +// Lock identifies a lock taken over CloudDrive store +type Lock struct { + // Key is the name on which the lock is acquired. + // This is used by the callers for logging purpose. Hence public + Key string + // Name of the owner who acquired the lock + owner string + // true if this lock was acquired using LockWithKey() interface + lockedWithKey bool + // lock structure as returned from the KVDB interface + internalLock interface{} +} + +// KeyDoesNotExist is error type when the key does not exist +type KeyDoesNotExist struct { + Key string +} + +func (e *KeyDoesNotExist) Error() string { + return fmt.Sprintf("key %s does not exist", e.Key) +} + +// KeyExists is error type when the key already exist in store +type KeyExists struct { + // Key that exists + Key string + // Message is an optional message to the user + Message string +} + +func (e *KeyExists) Error() string { + errMsg := fmt.Sprintf("key %s already exists in store", e.Key) + if len(e.Message) > 0 { + errMsg += " " + e.Message + } + return errMsg +} + +// Store provides a set of APIs to CloudDrive to store its metadata +// in a persistent store +type Store interface { + // Lock locks the cloud drive store for a node to perform operations + Lock(owner string) (*Lock, error) + // Unlock unlocks the cloud drive store + Unlock(storeLock *Lock) error + // LockWithKey locks the cloud drive store with an arbitrary key + LockWithKey(owner, key string) (*Lock, error) + // IsKeyLocked checks if the specified key is currently locked + IsKeyLocked(key string) (bool, string, error) + // CreateKey creates the given key with the value + CreateKey(key string, value []byte) error + // PutKey updates the given key with the value + PutKey(key string, value []byte) error + // GetKey returns the value for the given key + GetKey(key string) ([]byte, error) + // DeleteKey deletes the given key + DeleteKey(key string) error + // EnumerateWithKeyPrefix enumerates all keys in the store that begin with the given key + EnumerateWithKeyPrefix(key string) ([]string, error) +} + +// GetStoreWithParams returns instance for Store +// kv: bootstrap kvdb +// schedulerType: node scheduler type e.g Kubernetes +// internalKvdb: If the cluster is configured to have internal kvdb +// name: Name for the store +// lockTryDuration: Total time to try acquiring the lock for +// lockHoldTimeout: Once a lock is acquired, if it's held beyond this time, there will be panic +func GetStoreWithParams( + kv kvdb.Kvdb, + schedulerType string, + internalKvdb bool, + name string, + lockTryDuration time.Duration, + lockHoldTimeout time.Duration, +) (Store, error) { + if len(name) == 0 { + return nil, fmt.Errorf("name required to create Store") + } + var ( + s Store + err error + ) + + if internalKvdb && schedulerType == Kubernetes { + s, _, err = newK8sStoreWithParams(name, lockTryDuration, lockHoldTimeout) + } else if internalKvdb && kv == nil { + return nil, fmt.Errorf("bootstrap kvdb cannot be empty") + } else { + // Two cases: + // internal kvdb && kv is not nil + // external kvdb + if !internalKvdb { + if kvdb.Instance() == nil { + return nil, fmt.Errorf("kvdb is not initialized") + } + kv = kvdb.Instance() + } + s, err = newKVStoreWithParams(kv, name, lockTryDuration, lockHoldTimeout) + } + return s, err +} diff --git a/store/store_k8s.go b/store/store_k8s.go new file mode 100644 index 000000000..274158e29 --- /dev/null +++ b/store/store_k8s.go @@ -0,0 +1,257 @@ +package store + +import ( + "fmt" + "math" + "regexp" + "strings" + "time" + + "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" + "github.com/portworx/sched-ops/k8s/core/configmap" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/wait" +) + +const ( + confgMapPrefix = "px-cloud-drive-" + cloudDriveEntry = "cloud-drive" + waitDuration = 2 * time.Second + waitFactor = 1.5 + waitSteps = 5 +) + +// GetSanitizedK8sName will sanitize the name conforming to RFC 1123 standards so that it's a "qualified name" per k8s +func GetSanitizedK8sName(k8sName string) string { + sanitizedString := "" + if len(k8sName) > 0 { + k8sName = strings.ToLower(k8sName) + k8sName = strings.ReplaceAll(k8sName, " ", "-") + if msgs := validation.IsDNS1123Subdomain(k8sName); len(msgs) > 0 { + for _, z := range k8sName { + // Names are expected to start and end with alphanumeric characters. Hence adding "a" + if msgs := validation.IsDNS1123Subdomain("a" + string(z) + "a"); len(msgs) == 0 { + sanitizedString += string(z) + } else { + sanitizedString += "." + } + } + //After sanitizing, we need the first and last letter to be alphanumeric + isAlpha := regexp.MustCompile(`^[A-Za-z0-9]+$`).MatchString + first := float64(len(sanitizedString)) + last := float64(0) + for i, s := range sanitizedString { + if isAlpha(string(s)) { + first = float64(math.Min(first, float64(i))) + last = float64(math.Max(last, float64(i))) + } + } + sanitizedString = sanitizedString[int(first) : int(last)+1] + logrus.Infof("k8s name is not per RFC 1123 standard sanitized %s to %s", k8sName, sanitizedString) + } else { + sanitizedString = k8sName + } + } + return sanitizedString +} + +var ( + // total wait time: 16.25 seconds + waitBackoff = wait.Backoff{ + Duration: waitDuration, // the base duration + Factor: waitFactor, // Duration is multiplied by factor each iteration + Steps: waitSteps, // Exit with error after this many steps + } + errorsToRetryOn = []error{rpctypes.ErrLeaderChanged} +) + +type k8sStore struct { + cm configmap.ConfigMap +} + +// NewK8sStore returns a Store implementation which uses +// k8s configmaps to store data. +func NewK8sStore(clusterID string) (Store, configmap.ConfigMap, error) { + k8sStore, cm, err := newK8sStoreWithParams( + configmap.GetName(confgMapPrefix, clusterID), + configmap.DefaultK8sLockTimeout, + configmap.DefaultK8sLockAttempts*time.Second, + ) + if err != nil { + return nil, nil, err + } + return k8sStore, cm, nil +} + +// newK8sStoreWithParams returns a Store implementation which uses +// k8s configmaps to store data. ConfigMap properties can be customized. +func newK8sStoreWithParams( + name string, + lockTryDuration time.Duration, + lockTimeout time.Duration, +) (Store, configmap.ConfigMap, error) { + lockAttempts := uint((lockTryDuration / time.Second)) + cm, err := configmap.New( + name, + nil, + lockTimeout, + lockAttempts, + 0, + 0, + ) + if err != nil { + return nil, nil, err + } + return &k8sStore{cm}, cm, nil +} + +func (k8s *k8sStore) Lock(owner string) (*Lock, error) { + if err := k8s.cm.Lock(owner); err != nil { + return nil, err + } + return &Lock{owner: owner}, nil +} + +func (k8s *k8sStore) LockWithKey(owner, key string) (*Lock, error) { + if err := k8s.cm.LockWithKey(owner, key); err != nil { + return nil, err + } + return &Lock{Key: key, owner: owner, lockedWithKey: true}, nil +} + +func (k8s *k8sStore) Unlock(storeLock *Lock) error { + if storeLock.lockedWithKey { + return k8s.cm.UnlockWithKey(storeLock.Key) + } + return k8s.cm.Unlock() +} + +func (k8s *k8sStore) IsKeyLocked(key string) (bool, string, error) { + return k8s.cm.IsKeyLocked(key) +} + +func (k8s *k8sStore) CreateKey(key string, value []byte) error { + sanitizedKey := GetSanitizedK8sName(key) + err := k8s.cm.LockWithKey(string(value), sanitizedKey) + if err != nil { + logrus.Errorf("unable to lock with key %v", key) + return err + } + defer func() { + err := k8s.cm.UnlockWithKey(sanitizedKey) + if err != nil { + logrus.Warnf("unable to unlock with key %v", key) + } + }() + + data, err := k8s.cm.Get() + if err != nil { + return err + } + + if _, ok := data[key]; ok { + return &KeyExists{ + Key: key, + Message: "Use PutKey API", + } + } + + if data == nil { + data = make(map[string]string) + } + data[key] = string(value) + return k8s.patchWithRetries(data) +} + +func (k8s *k8sStore) PutKey(key string, value []byte) error { + data, err := k8s.cm.Get() + if err != nil { + return err + } + + data[key] = string(value) + return k8s.patchWithRetries(data) +} + +func (k8s *k8sStore) GetKey(key string) ([]byte, error) { + data, err := k8s.cm.Get() + if err != nil { + return nil, err + } + + value, ok := data[key] + if !ok { + return nil, &KeyDoesNotExist{ + Key: key, + } + } + + return []byte(value), nil +} + +func (k8s *k8sStore) DeleteKey(key string) error { + sanitizedKey := GetSanitizedK8sName(key) + // Let's use the sanitized key itself as the owner. + err := k8s.cm.LockWithKey(sanitizedKey, sanitizedKey) + if err != nil { + logrus.Errorf("unable to lock with key %v", key) + return err + } + defer func() { + err := k8s.cm.UnlockWithKey(sanitizedKey) + if err != nil { + logrus.Infof("unable to unlock with key %v", key) + } + }() + data, err := k8s.cm.Get() + if err != nil { + return err + } + + if _, ok := data[key]; !ok { + return nil + } + + delete(data, key) + return k8s.cm.Update(data) +} + +func (k8s *k8sStore) EnumerateWithKeyPrefix(key string) ([]string, error) { + data, err := k8s.cm.Get() + if err != nil { + return nil, err + } + + returnKeys := make([]string, 0) + for k := range data { + if strings.HasPrefix(k, key) { + returnKeys = append(returnKeys, k) + } + } + + return returnKeys, nil +} + +func (k8s *k8sStore) patchWithRetries(data map[string]string) error { + f := func() (bool, error) { + err := k8s.cm.Patch(data) + + for _, retryErr := range errorsToRetryOn { + if err == retryErr { + logrus.Warnf("patch operation on config map failed with an error: %v, retrying", err) + return false, nil // retry + } + } + + if err != nil { + return false, err + } + + return true, nil + } + if err := wait.ExponentialBackoff(waitBackoff, f); err != nil { + return fmt.Errorf("failed to patch configmap data: %s, %w", data, err) + } + return nil +} diff --git a/store/store_kv.go b/store/store_kv.go new file mode 100644 index 000000000..f7b96d446 --- /dev/null +++ b/store/store_kv.go @@ -0,0 +1,146 @@ +package store + +import ( + "errors" + "fmt" + "time" + + "github.com/portworx/kvdb" +) + +const ( + cloudDriveKey = "clouddrive/" + cloudDriveLockKey = "_lock" + defaultLockTryDuration = 1 * time.Minute + defaultLockHoldDuration = 3 * time.Minute +) + +var ( + // ErrKvdbNotInitialized is returned when kvdb is not initialized + ErrKvdbNotInitialized = errors.New("KVDB is not initialized") +) + +type kvStore struct { + k kvdb.Kvdb + lockPrefix string + lockTryDuration time.Duration + lockHoldDuration time.Duration +} + +// NewKVStore returns a Store implementation which is a wrapper over +// kvdb. +func NewKVStore(kv kvdb.Kvdb) (Store, error) { + return newKVStoreWithParams(kv, cloudDriveKey, 0, 0) +} + +// NewKVStoreWithParams returns a Store implementation which is a wrapper over +// kvdb. +func newKVStoreWithParams( + kv kvdb.Kvdb, + name string, + lockTryDuration time.Duration, + lockHoldDuration time.Duration, +) (Store, error) { + kstore := kvStore{} + if kv == nil { + return nil, ErrKvdbNotInitialized + } + if len(name) == 0 { + return nil, fmt.Errorf("name cannot be empty") + } + if lockTryDuration != 0 { + kstore.lockTryDuration = lockTryDuration + } else { + kstore.lockTryDuration = kv.GetLockTryDuration() + } + if kstore.lockTryDuration == 0 { + kstore.lockTryDuration = defaultLockTryDuration + } + + if lockHoldDuration != 0 { + kstore.lockHoldDuration = lockHoldDuration + } else { + kstore.lockHoldDuration = kv.GetLockHoldDuration() + } + if kstore.lockHoldDuration == 0 { + kstore.lockHoldDuration = defaultLockHoldDuration + } + + kstore.k = kv + kstore.lockPrefix = name + return &kstore, nil +} + +func (kv *kvStore) Lock(owner string) (*Lock, error) { + return kv.lockWithKeyHelper(owner, kv.getFullLockPath(cloudDriveLockKey)) +} + +func (kv *kvStore) Unlock(storeLock *Lock) error { + kvp, ok := storeLock.internalLock.(*kvdb.KVPair) + if !ok { + return fmt.Errorf("invalid store lock provided") + } + return kv.k.Unlock(kvp) +} + +func (kv *kvStore) getFullLockPath(key string) string { + return kv.lockPrefix + "/" + key +} + +func (kv *kvStore) LockWithKey(owner, key string) (*Lock, error) { + fullPath := kv.getFullLockPath(key) + kvPair, err := kv.lockWithKeyHelper(owner, fullPath) + kvPair.lockedWithKey = true + return kvPair, err +} + +func (kv *kvStore) lockWithKeyHelper(owner, key string) (*Lock, error) { + kvLock, err := kv.k.LockWithTimeout(key, owner, kv.lockTryDuration, kv.lockHoldDuration) + if err != nil { + return nil, err + } + return &Lock{Key: key, internalLock: kvLock}, nil +} + +func (kv *kvStore) IsKeyLocked(key string) (bool, string, error) { + fullPath := kv.getFullLockPath(key) + return kv.k.IsKeyLocked(fullPath) +} + +func (kv *kvStore) CreateKey(key string, value []byte) error { + _, err := kv.k.Create(key, string(value), 0) + return err +} + +func (kv *kvStore) PutKey(key string, value []byte) error { + _, err := kv.k.Put(key, string(value), 0) + return err +} + +func (kv *kvStore) GetKey(key string) ([]byte, error) { + keyData, err := kv.k.Get(key) + if err != nil { + return nil, err + } + + return keyData.Value, nil +} + +func (kv *kvStore) DeleteKey(key string) error { + _, err := kv.k.Delete(key) + return err +} + +func (kv *kvStore) EnumerateWithKeyPrefix(key string) ([]string, error) { + output, err := kv.k.Enumerate(key) + if err != nil { + return nil, err + } + + returnKeys := make([]string, 0) + for _, entry := range output { + returnKeys = append(returnKeys, entry.Key) + } + + return returnKeys, nil +} diff --git a/vendor/github.com/coreos/etcd/LICENSE b/vendor/github.com/coreos/etcd/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/coreos/etcd/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/coreos/etcd/NOTICE b/vendor/github.com/coreos/etcd/NOTICE new file mode 100644 index 000000000..b39ddfa5c --- /dev/null +++ b/vendor/github.com/coreos/etcd/NOTICE @@ -0,0 +1,5 @@ +CoreOS Project +Copyright 2014 CoreOS, Inc + +This product includes software developed at CoreOS, Inc. +(http://www.coreos.com/). diff --git a/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/doc.go b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/doc.go new file mode 100644 index 000000000..f72c6a644 --- /dev/null +++ b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/doc.go @@ -0,0 +1,16 @@ +// Copyright 2016 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package rpctypes has types and values shared by the etcd server and client for v3 RPC interaction. +package rpctypes diff --git a/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/error.go b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/error.go new file mode 100644 index 000000000..bc1ad7bbd --- /dev/null +++ b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/error.go @@ -0,0 +1,217 @@ +// Copyright 2015 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpctypes + +import ( + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// server-side error +var ( + ErrGRPCEmptyKey = status.New(codes.InvalidArgument, "etcdserver: key is not provided").Err() + ErrGRPCKeyNotFound = status.New(codes.InvalidArgument, "etcdserver: key not found").Err() + ErrGRPCValueProvided = status.New(codes.InvalidArgument, "etcdserver: value is provided").Err() + ErrGRPCLeaseProvided = status.New(codes.InvalidArgument, "etcdserver: lease is provided").Err() + ErrGRPCTooManyOps = status.New(codes.InvalidArgument, "etcdserver: too many operations in txn request").Err() + ErrGRPCDuplicateKey = status.New(codes.InvalidArgument, "etcdserver: duplicate key given in txn request").Err() + ErrGRPCCompacted = status.New(codes.OutOfRange, "etcdserver: mvcc: required revision has been compacted").Err() + ErrGRPCFutureRev = status.New(codes.OutOfRange, "etcdserver: mvcc: required revision is a future revision").Err() + ErrGRPCNoSpace = status.New(codes.ResourceExhausted, "etcdserver: mvcc: database space exceeded").Err() + + ErrGRPCLeaseNotFound = status.New(codes.NotFound, "etcdserver: requested lease not found").Err() + ErrGRPCLeaseExist = status.New(codes.FailedPrecondition, "etcdserver: lease already exists").Err() + ErrGRPCLeaseTTLTooLarge = status.New(codes.OutOfRange, "etcdserver: too large lease TTL").Err() + + ErrGRPCMemberExist = status.New(codes.FailedPrecondition, "etcdserver: member ID already exist").Err() + ErrGRPCPeerURLExist = status.New(codes.FailedPrecondition, "etcdserver: Peer URLs already exists").Err() + ErrGRPCMemberNotEnoughStarted = status.New(codes.FailedPrecondition, "etcdserver: re-configuration failed due to not enough started members").Err() + ErrGRPCMemberBadURLs = status.New(codes.InvalidArgument, "etcdserver: given member URLs are invalid").Err() + ErrGRPCMemberNotFound = status.New(codes.NotFound, "etcdserver: member not found").Err() + + ErrGRPCRequestTooLarge = status.New(codes.InvalidArgument, "etcdserver: request is too large").Err() + ErrGRPCRequestTooManyRequests = status.New(codes.ResourceExhausted, "etcdserver: too many requests").Err() + + ErrGRPCRootUserNotExist = status.New(codes.FailedPrecondition, "etcdserver: root user does not exist").Err() + ErrGRPCRootRoleNotExist = status.New(codes.FailedPrecondition, "etcdserver: root user does not have root role").Err() + ErrGRPCUserAlreadyExist = status.New(codes.FailedPrecondition, "etcdserver: user name already exists").Err() + ErrGRPCUserEmpty = status.New(codes.InvalidArgument, "etcdserver: user name is empty").Err() + ErrGRPCUserNotFound = status.New(codes.FailedPrecondition, "etcdserver: user name not found").Err() + ErrGRPCRoleAlreadyExist = status.New(codes.FailedPrecondition, "etcdserver: role name already exists").Err() + ErrGRPCRoleNotFound = status.New(codes.FailedPrecondition, "etcdserver: role name not found").Err() + ErrGRPCAuthFailed = status.New(codes.InvalidArgument, "etcdserver: authentication failed, invalid user ID or password").Err() + ErrGRPCPermissionDenied = status.New(codes.PermissionDenied, "etcdserver: permission denied").Err() + ErrGRPCRoleNotGranted = status.New(codes.FailedPrecondition, "etcdserver: role is not granted to the user").Err() + ErrGRPCPermissionNotGranted = status.New(codes.FailedPrecondition, "etcdserver: permission is not granted to the role").Err() + ErrGRPCAuthNotEnabled = status.New(codes.FailedPrecondition, "etcdserver: authentication is not enabled").Err() + ErrGRPCInvalidAuthToken = status.New(codes.Unauthenticated, "etcdserver: invalid auth token").Err() + ErrGRPCInvalidAuthMgmt = status.New(codes.InvalidArgument, "etcdserver: invalid auth management").Err() + + ErrGRPCNoLeader = status.New(codes.Unavailable, "etcdserver: no leader").Err() + ErrGRPCNotLeader = status.New(codes.FailedPrecondition, "etcdserver: not leader").Err() + ErrGRPCLeaderChanged = status.New(codes.Unavailable, "etcdserver: leader changed").Err() + ErrGRPCNotCapable = status.New(codes.Unavailable, "etcdserver: not capable").Err() + ErrGRPCStopped = status.New(codes.Unavailable, "etcdserver: server stopped").Err() + ErrGRPCTimeout = status.New(codes.Unavailable, "etcdserver: request timed out").Err() + ErrGRPCTimeoutDueToLeaderFail = status.New(codes.Unavailable, "etcdserver: request timed out, possibly due to previous leader failure").Err() + ErrGRPCTimeoutDueToConnectionLost = status.New(codes.Unavailable, "etcdserver: request timed out, possibly due to connection lost").Err() + ErrGRPCUnhealthy = status.New(codes.Unavailable, "etcdserver: unhealthy cluster").Err() + ErrGRPCCorrupt = status.New(codes.DataLoss, "etcdserver: corrupt cluster").Err() + + errStringToError = map[string]error{ + ErrorDesc(ErrGRPCEmptyKey): ErrGRPCEmptyKey, + ErrorDesc(ErrGRPCKeyNotFound): ErrGRPCKeyNotFound, + ErrorDesc(ErrGRPCValueProvided): ErrGRPCValueProvided, + ErrorDesc(ErrGRPCLeaseProvided): ErrGRPCLeaseProvided, + + ErrorDesc(ErrGRPCTooManyOps): ErrGRPCTooManyOps, + ErrorDesc(ErrGRPCDuplicateKey): ErrGRPCDuplicateKey, + ErrorDesc(ErrGRPCCompacted): ErrGRPCCompacted, + ErrorDesc(ErrGRPCFutureRev): ErrGRPCFutureRev, + ErrorDesc(ErrGRPCNoSpace): ErrGRPCNoSpace, + + ErrorDesc(ErrGRPCLeaseNotFound): ErrGRPCLeaseNotFound, + ErrorDesc(ErrGRPCLeaseExist): ErrGRPCLeaseExist, + ErrorDesc(ErrGRPCLeaseTTLTooLarge): ErrGRPCLeaseTTLTooLarge, + + ErrorDesc(ErrGRPCMemberExist): ErrGRPCMemberExist, + ErrorDesc(ErrGRPCPeerURLExist): ErrGRPCPeerURLExist, + ErrorDesc(ErrGRPCMemberNotEnoughStarted): ErrGRPCMemberNotEnoughStarted, + ErrorDesc(ErrGRPCMemberBadURLs): ErrGRPCMemberBadURLs, + ErrorDesc(ErrGRPCMemberNotFound): ErrGRPCMemberNotFound, + + ErrorDesc(ErrGRPCRequestTooLarge): ErrGRPCRequestTooLarge, + ErrorDesc(ErrGRPCRequestTooManyRequests): ErrGRPCRequestTooManyRequests, + + ErrorDesc(ErrGRPCRootUserNotExist): ErrGRPCRootUserNotExist, + ErrorDesc(ErrGRPCRootRoleNotExist): ErrGRPCRootRoleNotExist, + ErrorDesc(ErrGRPCUserAlreadyExist): ErrGRPCUserAlreadyExist, + ErrorDesc(ErrGRPCUserEmpty): ErrGRPCUserEmpty, + ErrorDesc(ErrGRPCUserNotFound): ErrGRPCUserNotFound, + ErrorDesc(ErrGRPCRoleAlreadyExist): ErrGRPCRoleAlreadyExist, + ErrorDesc(ErrGRPCRoleNotFound): ErrGRPCRoleNotFound, + ErrorDesc(ErrGRPCAuthFailed): ErrGRPCAuthFailed, + ErrorDesc(ErrGRPCPermissionDenied): ErrGRPCPermissionDenied, + ErrorDesc(ErrGRPCRoleNotGranted): ErrGRPCRoleNotGranted, + ErrorDesc(ErrGRPCPermissionNotGranted): ErrGRPCPermissionNotGranted, + ErrorDesc(ErrGRPCAuthNotEnabled): ErrGRPCAuthNotEnabled, + ErrorDesc(ErrGRPCInvalidAuthToken): ErrGRPCInvalidAuthToken, + ErrorDesc(ErrGRPCInvalidAuthMgmt): ErrGRPCInvalidAuthMgmt, + + ErrorDesc(ErrGRPCNoLeader): ErrGRPCNoLeader, + ErrorDesc(ErrGRPCNotLeader): ErrGRPCNotLeader, + ErrorDesc(ErrGRPCNotCapable): ErrGRPCNotCapable, + ErrorDesc(ErrGRPCStopped): ErrGRPCStopped, + ErrorDesc(ErrGRPCTimeout): ErrGRPCTimeout, + ErrorDesc(ErrGRPCTimeoutDueToLeaderFail): ErrGRPCTimeoutDueToLeaderFail, + ErrorDesc(ErrGRPCTimeoutDueToConnectionLost): ErrGRPCTimeoutDueToConnectionLost, + ErrorDesc(ErrGRPCUnhealthy): ErrGRPCUnhealthy, + ErrorDesc(ErrGRPCCorrupt): ErrGRPCCorrupt, + } +) + +// client-side error +var ( + ErrEmptyKey = Error(ErrGRPCEmptyKey) + ErrKeyNotFound = Error(ErrGRPCKeyNotFound) + ErrValueProvided = Error(ErrGRPCValueProvided) + ErrLeaseProvided = Error(ErrGRPCLeaseProvided) + ErrTooManyOps = Error(ErrGRPCTooManyOps) + ErrDuplicateKey = Error(ErrGRPCDuplicateKey) + ErrCompacted = Error(ErrGRPCCompacted) + ErrFutureRev = Error(ErrGRPCFutureRev) + ErrNoSpace = Error(ErrGRPCNoSpace) + + ErrLeaseNotFound = Error(ErrGRPCLeaseNotFound) + ErrLeaseExist = Error(ErrGRPCLeaseExist) + ErrLeaseTTLTooLarge = Error(ErrGRPCLeaseTTLTooLarge) + + ErrMemberExist = Error(ErrGRPCMemberExist) + ErrPeerURLExist = Error(ErrGRPCPeerURLExist) + ErrMemberNotEnoughStarted = Error(ErrGRPCMemberNotEnoughStarted) + ErrMemberBadURLs = Error(ErrGRPCMemberBadURLs) + ErrMemberNotFound = Error(ErrGRPCMemberNotFound) + + ErrRequestTooLarge = Error(ErrGRPCRequestTooLarge) + ErrTooManyRequests = Error(ErrGRPCRequestTooManyRequests) + + ErrRootUserNotExist = Error(ErrGRPCRootUserNotExist) + ErrRootRoleNotExist = Error(ErrGRPCRootRoleNotExist) + ErrUserAlreadyExist = Error(ErrGRPCUserAlreadyExist) + ErrUserEmpty = Error(ErrGRPCUserEmpty) + ErrUserNotFound = Error(ErrGRPCUserNotFound) + ErrRoleAlreadyExist = Error(ErrGRPCRoleAlreadyExist) + ErrRoleNotFound = Error(ErrGRPCRoleNotFound) + ErrAuthFailed = Error(ErrGRPCAuthFailed) + ErrPermissionDenied = Error(ErrGRPCPermissionDenied) + ErrRoleNotGranted = Error(ErrGRPCRoleNotGranted) + ErrPermissionNotGranted = Error(ErrGRPCPermissionNotGranted) + ErrAuthNotEnabled = Error(ErrGRPCAuthNotEnabled) + ErrInvalidAuthToken = Error(ErrGRPCInvalidAuthToken) + ErrInvalidAuthMgmt = Error(ErrGRPCInvalidAuthMgmt) + + ErrNoLeader = Error(ErrGRPCNoLeader) + ErrNotLeader = Error(ErrGRPCNotLeader) + ErrLeaderChanged = Error(ErrGRPCLeaderChanged) + ErrNotCapable = Error(ErrGRPCNotCapable) + ErrStopped = Error(ErrGRPCStopped) + ErrTimeout = Error(ErrGRPCTimeout) + ErrTimeoutDueToLeaderFail = Error(ErrGRPCTimeoutDueToLeaderFail) + ErrTimeoutDueToConnectionLost = Error(ErrGRPCTimeoutDueToConnectionLost) + ErrUnhealthy = Error(ErrGRPCUnhealthy) + ErrCorrupt = Error(ErrGRPCCorrupt) +) + +// EtcdError defines gRPC server errors. +// (https://github.com/grpc/grpc-go/blob/master/rpc_util.go#L319-L323) +type EtcdError struct { + code codes.Code + desc string +} + +// Code returns grpc/codes.Code. +// TODO: define clientv3/codes.Code. +func (e EtcdError) Code() codes.Code { + return e.code +} + +func (e EtcdError) Error() string { + return e.desc +} + +func Error(err error) error { + if err == nil { + return nil + } + verr, ok := errStringToError[ErrorDesc(err)] + if !ok { // not gRPC error + return err + } + ev, ok := status.FromError(verr) + var desc string + if ok { + desc = ev.Message() + } else { + desc = verr.Error() + } + return EtcdError{code: ev.Code(), desc: desc} +} + +func ErrorDesc(err error) string { + if s, ok := status.FromError(err); ok { + return s.Message() + } + return err.Error() +} diff --git a/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/md.go b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/md.go new file mode 100644 index 000000000..90b8b835b --- /dev/null +++ b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/md.go @@ -0,0 +1,22 @@ +// Copyright 2016 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpctypes + +var ( + MetadataRequireLeaderKey = "hasleader" + MetadataHasLeader = "true" + + MetadataClientAPIVersionKey = "client-api-version" +) diff --git a/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/metadatafields.go b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/metadatafields.go new file mode 100644 index 000000000..8f8ac60ff --- /dev/null +++ b/vendor/github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes/metadatafields.go @@ -0,0 +1,20 @@ +// Copyright 2018 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpctypes + +var ( + TokenFieldNameGRPC = "token" + TokenFieldNameSwagger = "authorization" +) diff --git a/vendor/github.com/portworx/kvdb/.gitignore b/vendor/github.com/portworx/kvdb/.gitignore new file mode 100644 index 000000000..95f7a016e --- /dev/null +++ b/vendor/github.com/portworx/kvdb/.gitignore @@ -0,0 +1,9 @@ +.idea +coverage.txt +profile.out +vendor +zookeeper/zookeeper.out +consul/kvdb_audit.log +etcd/v2/kvdb_audit.log +etcd/v3/kvdb_audit.log +mem/kvdb_audit.log diff --git a/vendor/github.com/portworx/kvdb/.travis.yml b/vendor/github.com/portworx/kvdb/.travis.yml new file mode 100644 index 000000000..20387ad86 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/.travis.yml @@ -0,0 +1,24 @@ +sudo: required +dist: trusty +services: +- docker +language: go +go: +- 1.17.13 +install: +- curl -s -L https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 -o $GOPATH/bin/dep +- chmod +x $GOPATH/bin/dep +- go get -u github.com/vbatts/git-validation +script: +- git-validation -run DCO,short-subject +- make deps docker-test +notifications: + email: + recipients: + - eng@portworx.com + on_success: change + on_failure: always + slack: + secure: fBa9ZJTNr3NfSHSDxzCgmZ1iMs+UaEDcGk1t1VhkYJq8QWey8EZn7HzO5QNh3nmE93U9rt/yFa/1mCTxAVuoFeB47aVLI2zB/N95PFLi4OyBdJAbpZRH57zbre7N4AUlueoUQMpshNDYV66JalL0N7WS2fNy1CLn/IH8y90nR82Sr0nubA09NU9NpZy6CQqRkGUl9ri+n12bxZa8tvN3fuME/zi7MyPRg26xfINMuxF5226aHqhP3cBKzud/1uKO2F9OKxbQhn3rrEnjLKsBreGwy4QVs+rFGtO0DJdCspLCbbFbatSY6lgbpFF1Txw+CQ6k3LxXznHGtZ9rl/ghqy/EXbsB/zS65TrCZu6DG59yZlB47ou13ikuDECeJPntUvCCfIQfBQIgn1HjiCuzvEzTNqhKltNw0+ah+HvAJk6o4bjtC+1sw52MOy31w9NBrzsacMBXacAfyJSMnCYgzZejOp07/Q+H71LqCBu6IUdskBjVNmTo6NMudT3m9/9ArE8qKVhFe2H4KEbHCgyZRdz1mrIdEXPYwMd+Byqr+HA6esoYGHecZ8A8pbf9DHhkjuwdUuxQ/k0pKr80sSBB8WSxOGVM43H6sFCyTAV56Vp4Ul7fR8f+W4O0cRGonl7a/EkqHBC86CgejD4aiI2M5dnxKEaNtCBoOw8qdiud3Lw= +after_success: +- bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/portworx/kvdb/DCO b/vendor/github.com/portworx/kvdb/DCO new file mode 100644 index 000000000..0cdce0c39 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/DCO @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. \ No newline at end of file diff --git a/vendor/github.com/portworx/kvdb/Dockerfile.kvdb b/vendor/github.com/portworx/kvdb/Dockerfile.kvdb new file mode 100644 index 000000000..ffd91eb25 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/Dockerfile.kvdb @@ -0,0 +1,40 @@ +FROM ubuntu +MAINTAINER support@portworx.com + +RUN \ + apt-get update -yq && \ + apt-get install -yq --no-install-recommends \ + btrfs-tools \ + gcc \ + g++ \ + ca-certificates && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN apt-get update && \ + apt-get -y install unzip curl make git default-jre + + +RUN curl -s -L https://dl.google.com/go/go1.10.7.linux-amd64.tar.gz | tar -C /usr/local/ -xz && \ + curl -s -L https://github.com/coreos/etcd/releases/download/v3.2.15/etcd-v3.2.15-linux-amd64.tar.gz -o /tmp/etcd-v3.2.15-linux-amd64.tar.gz && \ + mkdir -p /tmp/test-etcd && tar xzvf /tmp/etcd-v3.2.15-linux-amd64.tar.gz -C /tmp/test-etcd --strip-components=1 && cp /tmp/test-etcd/etcd /usr/local/bin && \ + curl -s -L https://releases.hashicorp.com/consul/1.0.0/consul_1.0.0_linux_amd64.zip -o /tmp/consul.zip && \ + mkdir -p /tmp/test-consul && unzip /tmp/consul.zip -d /tmp/test-consul && cp /tmp/test-consul/consul /usr/local/bin/ && \ + curl -s -L https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/zookeeper-3.4.13.tar.gz -o /tmp/zookeeper-3.4.13.tar.gz && \ + mkdir -p /tmp/test-zookeeper && tar -xvf /tmp/zookeeper-3.4.13.tar.gz -C /tmp/test-zookeeper --strip-components=1 && mkdir -p /data/zookeeper + +ENV PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin +ENV GOPATH /go +ENV GOROOT /usr/local/go + +RUN mkdir -p /go/src/github.com/portworx/kvdb +ADD . /go/src/github.com/portworx/kvdb + +RUN echo $'tickTime=2000 \n\ +dataDir=/data/zookeeper \n\ +clientPort=2181 \n\ +initLimit=5 \n\ +syncLimit=2 \n\ +server.1=127.0.0.1:2888:3888' > /tmp/test-zookeeper/conf/zoo.cfg + +WORKDIR /go/src/github.com/portworx/kvdb diff --git a/vendor/github.com/portworx/kvdb/Gopkg.lock b/vendor/github.com/portworx/kvdb/Gopkg.lock new file mode 100644 index 000000000..6899f13a9 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/Gopkg.lock @@ -0,0 +1,561 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + digest = "1:ef5b0622d834c139454148b8fd0c92bb314828900532b267ae62da9fec109866" + name = "github.com/armon/go-metrics" + packages = ["."] + pruneopts = "UT" + revision = "f0300d1749da6fa982027e449ec0c7a145510c3c" + +[[projects]] + branch = "master" + digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" + name = "github.com/beorn7/perks" + packages = ["quantile"] + pruneopts = "UT" + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + digest = "1:0f98f59e9a2f4070d66f0c9c39561f68fcd1dc837b22a852d28d0003aebd1b1e" + name = "github.com/boltdb/bolt" + packages = ["."] + pruneopts = "UT" + revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8" + version = "v1.3.1" + +[[projects]] + digest = "1:6bda4e232607261eeaee45b0a0e8a2ef097bd44e8a44d9b7ca1badb36e523891" + name = "github.com/coreos/bbolt" + packages = ["."] + pruneopts = "UT" + revision = "48ea1b39c25fc1bab3506fbc712ecbaa842c4d2d" + version = "v1.3.1-coreos.6" + +[[projects]] + digest = "1:34b80e6d27279735a8abf66cee67bde0f9011d3ff8e2812af6400ba498ec55c7" + name = "github.com/coreos/etcd" + packages = [ + "alarm", + "auth", + "auth/authpb", + "client", + "clientv3", + "clientv3/concurrency", + "compactor", + "discovery", + "error", + "etcdserver", + "etcdserver/api", + "etcdserver/api/v2http/httptypes", + "etcdserver/api/v3rpc/rpctypes", + "etcdserver/etcdserverpb", + "etcdserver/membership", + "etcdserver/stats", + "lease", + "lease/leasehttp", + "lease/leasepb", + "mvcc", + "mvcc/backend", + "mvcc/mvccpb", + "pkg/adt", + "pkg/contention", + "pkg/cpuutil", + "pkg/crc", + "pkg/fileutil", + "pkg/httputil", + "pkg/idutil", + "pkg/ioutil", + "pkg/logutil", + "pkg/netutil", + "pkg/pathutil", + "pkg/pbutil", + "pkg/runtime", + "pkg/schedule", + "pkg/srv", + "pkg/tlsutil", + "pkg/transport", + "pkg/types", + "pkg/wait", + "raft", + "raft/raftpb", + "rafthttp", + "snap", + "snap/snappb", + "store", + "version", + "wal", + "wal/walpb", + ] + pruneopts = "UT" + revision = "98d308426819d892e149fe45f6fd542464cb1f9d" + version = "v3.3.13" + +[[projects]] + digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" + name = "github.com/coreos/go-semver" + packages = ["semver"] + pruneopts = "UT" + revision = "8ab6407b697782a06568d4b7f1db25550ec2e4c6" + version = "v0.2.0" + +[[projects]] + digest = "1:5c1e58f68ac83cf9c05c6c6748cd91b830dd94be9d2e6480add3c6524bb86b68" + name = "github.com/coreos/go-systemd" + packages = ["journal"] + pruneopts = "UT" + revision = "9002847aa1425fb6ac49077c0a630b3b67e0fbfd" + version = "v18" + +[[projects]] + digest = "1:39ff4d4d6baca1ac63c6a03404b761d664be14a71bb5a4aca8fef643d0f66fef" + name = "github.com/coreos/pkg" + packages = ["capnslog"] + pruneopts = "UT" + revision = "97fdf19511ea361ae1c100dd393cc47f8dcfa1e1" + version = "v4" + +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55" + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + pruneopts = "UT" + revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" + version = "v3.2.0" + +[[projects]] + digest = "1:a9c85389dbd301c97a3499fe15a2b65b505b5f0cb0f1120dea59f1f3d6b11d96" + name = "github.com/gogo/protobuf" + packages = [ + "gogoproto", + "proto", + "protoc-gen-gogo/descriptor", + ] + pruneopts = "UT" + revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7" + version = "v1.2.0" + +[[projects]] + digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "UT" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" + +[[projects]] + branch = "master" + digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df" + name = "github.com/google/btree" + packages = ["."] + pruneopts = "UT" + revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" + +[[projects]] + digest = "1:4757b468ebb23df6c20e23e5df6d8616222cad3f724f5c4c4986ed720ed561d7" + name = "github.com/hashicorp/consul" + packages = ["api"] + pruneopts = "UT" + revision = "51ea240df8476e02215d53fbfad5838bf0d44d21" + version = "v1.0.0" + +[[projects]] + digest = "1:0ade334594e69404d80d9d323445d2297ff8161637f9b2d347cc6973d2d6f05b" + name = "github.com/hashicorp/errwrap" + packages = ["."] + pruneopts = "UT" + revision = "8a6fb523712970c966eefc6b39ed2c5e74880354" + version = "v1.0.0" + +[[projects]] + digest = "1:f47d6109c2034cb16bd62b220e18afd5aa9d5a1630fe5d937ad96a4fb7cbb277" + name = "github.com/hashicorp/go-cleanhttp" + packages = ["."] + pruneopts = "UT" + revision = "e8ab9daed8d1ddd2d3c4efba338fe2eeae2e4f18" + version = "v0.5.0" + +[[projects]] + digest = "1:2be5a35f0c5b35162c41bb24971e5dcf6ce825403296ee435429cdcc4e1e847e" + name = "github.com/hashicorp/go-immutable-radix" + packages = ["."] + pruneopts = "UT" + revision = "27df80928bb34bb1b0d6d0e01b9e679902e7a6b5" + version = "v1.0.0" + +[[projects]] + digest = "1:b8ba23b0b493e601d5ebaf21079bd3433eb304a5d73c0fb40b8aea526e94f46b" + name = "github.com/hashicorp/go-msgpack" + packages = ["codec"] + pruneopts = "UT" + revision = "be3a5be7ee2202386d02936a19ae4fbde1c77800" + version = "v0.5.3" + +[[projects]] + digest = "1:f668349b83f7d779567c880550534addeca7ebadfdcf44b0b9c39be61864b4b7" + name = "github.com/hashicorp/go-multierror" + packages = ["."] + pruneopts = "UT" + revision = "886a7fbe3eb1c874d46f623bfa70af45f425b3d1" + version = "v1.0.0" + +[[projects]] + digest = "1:a54ada9beb59fdc35b69322979e870ff0b780e03f4dc309c4c8674b94927df75" + name = "github.com/hashicorp/go-rootcerts" + packages = ["."] + pruneopts = "UT" + revision = "63503fb4e1eca22f9ae0f90b49c5d5538a0e87eb" + version = "v1.0.0" + +[[projects]] + digest = "1:3c4c27026ab6a3218dbde897568f651c81062e2ee6e617e57ae46ca95bb1db6b" + name = "github.com/hashicorp/go-sockaddr" + packages = ["."] + pruneopts = "UT" + revision = "3aed17b5ee41761cc2b04f2a94c7107d428967e5" + version = "v1.0.1" + +[[projects]] + digest = "1:67474f760e9ac3799f740db2c489e6423a4cde45520673ec123ac831ad849cb8" + name = "github.com/hashicorp/golang-lru" + packages = ["simplelru"] + pruneopts = "UT" + revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" + version = "v0.5.0" + +[[projects]] + digest = "1:c839c9a399b78daeff75848565aff9ece9a389e50b77926065b6e504ed088bb5" + name = "github.com/hashicorp/memberlist" + packages = ["."] + pruneopts = "UT" + revision = "a9da52f0668fc4321ec18e9e28dd8141621a808f" + version = "v0.1.3" + +[[projects]] + digest = "1:0dd7b7b01769f9df356dc99f9e4144bdbabf6c79041ea7c0892379c5737f3c44" + name = "github.com/hashicorp/serf" + packages = ["coordinate"] + pruneopts = "UT" + revision = "d6574a5bb1226678d7010325fb6c985db20ee458" + version = "v0.8.1" + +[[projects]] + digest = "1:75ab90ae3f5d876167e60f493beadfe66f0ed861a710f283fb06c86437a09538" + name = "github.com/jonboulle/clockwork" + packages = ["."] + pruneopts = "UT" + revision = "2eee05ed794112d45db504eb05aa693efd2b8b09" + version = "v0.1.0" + +[[projects]] + digest = "1:7d7ccfe00918baede5a3daf233bad41bb922692f58a57a687f8b010e207a167b" + name = "github.com/json-iterator/go" + packages = ["."] + pruneopts = "UT" + revision = "a1ca0830781e007c66b225121d2cdb3a649421f6" + version = "v1.1.10" + +[[projects]] + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + +[[projects]] + digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + pruneopts = "UT" + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + +[[projects]] + digest = "1:d64a0aa67f715fd28f5ddfe0d74c06b6d6fe0fed931d77e662f2c4694f6854dc" + name = "github.com/miekg/dns" + packages = ["."] + pruneopts = "UT" + revision = "56be65265e34e731425e0269a301774938827c60" + version = "v1.1.3" + +[[projects]] + digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + pruneopts = "UT" + revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4" + version = "v1.0.0" + +[[projects]] + digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563" + name = "github.com/modern-go/concurrent" + packages = ["."] + pruneopts = "UT" + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" + name = "github.com/modern-go/reflect2" + packages = ["."] + pruneopts = "UT" + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[[projects]] + branch = "master" + digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2" + name = "github.com/petar/GoLLRB" + packages = ["llrb"] + pruneopts = "UT" + revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" + +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:75d51eeab0df85a3cea9e1297ccd3183b20a10cb4b48c753d8ec8d113cc14250" + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/internal", + ] + pruneopts = "UT" + revision = "505eaef017263e299324067d40ca2c48f6a2cf50" + version = "v0.9.2" + +[[projects]] + branch = "master" + digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" + name = "github.com/prometheus/client_model" + packages = ["go"] + pruneopts = "UT" + revision = "56726106282f1985ea77d5305743db7231b0c0a8" + +[[projects]] + branch = "master" + digest = "1:ce62b400185bf6b16ef6088011b719e449f5c15c4adb6821589679f752c2788e" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model", + ] + pruneopts = "UT" + revision = "2998b132700a7d019ff618c06a234b47c1f3f681" + +[[projects]] + branch = "master" + digest = "1:f532f2cdb9e9e4a8fad5a7e944482f4dd12650228e4a7a6c8492a0d069ce0690" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs", + ] + pruneopts = "UT" + revision = "bf6a532e95b1f7a62adf0ab5050a5bb2237ad2f4" + +[[projects]] + branch = "master" + digest = "1:4d92d3bcd412de705100c10f0428a0b63b12f3d12455ebae46e9ea384c23b333" + name = "github.com/samuel/go-zookeeper" + packages = ["zk"] + pruneopts = "UT" + revision = "c4fab1ac1bec58281ad0667dc3f0907a9476ac47" + +[[projects]] + branch = "master" + digest = "1:579c4bbcc2e16d4caf871ba91c0e2c331b07c5560c80d142d82c0de01c57fa96" + name = "github.com/sean-/seed" + packages = ["."] + pruneopts = "UT" + revision = "e2103e2c35297fb7e17febb81e49b312087a2372" + +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" + +[[projects]] + digest = "1:5da8ce674952566deae4dbc23d07c85caafc6cfa815b0b3e03e41979cedb8750" + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require", + ] + pruneopts = "UT" + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[[projects]] + digest = "1:36775a135c00ff94c2ab9d4de842ae9bf95f45d2159ade2b033f3ecbafa69423" + name = "github.com/xiang90/probing" + packages = ["."] + pruneopts = "UT" + revision = "43a291ad63a214a207fefbf03c7d9d78b703162b" + version = "0.0.2" + +[[projects]] + branch = "master" + digest = "1:0f1e4f4c52bb58cfc3f6b8a22e62470fcc2faf83563fdda3123b33ef48fdf61f" + name = "golang.org/x/crypto" + packages = [ + "bcrypt", + "blowfish", + "ed25519", + "ed25519/internal/edwards25519", + "ssh/terminal", + ] + pruneopts = "UT" + revision = "64072686203f69e3fd20143576b27200f18ab0fa" + +[[projects]] + branch = "master" + digest = "1:d31df9cc7e6f49d558c7ba0ec75993b3630e78db24fa3a3da2ef490f05adf550" + name = "golang.org/x/net" + packages = [ + "bpf", + "context", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/iana", + "internal/socket", + "internal/timeseries", + "ipv4", + "ipv6", + "trace", + ] + pruneopts = "UT" + revision = "ed066c81e75eba56dd9bd2139ade88125b855585" + +[[projects]] + branch = "master" + digest = "1:9d6fee48d0bab077ed9cc08f69e902615f02b3e30f945334bdf902abb9e2af7c" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "054c452bb702e465e95ce8e7a3d9a6cf0cd1188d" + +[[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90" + name = "golang.org/x/time" + packages = ["rate"] + pruneopts = "UT" + revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd" + +[[projects]] + branch = "master" + digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + pruneopts = "UT" + revision = "eef12c790cc0dd8c2f45010a7f88e60f49521c9f" + +[[projects]] + digest = "1:45101b53b1b93d50e2464e3b164bfa72cc77229fb998cfcd029987006488c641" + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "codes", + "connectivity", + "credentials", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "health/grpc_health_v1", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "stats", + "status", + "tap", + "transport", + ] + pruneopts = "UT" + revision = "5b3c4e850e90a4cf6a20ebd46c8b32a0a3afcb9e" + version = "v1.7.5" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/boltdb/bolt", + "github.com/coreos/etcd/client", + "github.com/coreos/etcd/clientv3", + "github.com/coreos/etcd/clientv3/concurrency", + "github.com/coreos/etcd/etcdserver", + "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes", + "github.com/coreos/etcd/mvcc/mvccpb", + "github.com/coreos/etcd/pkg/transport", + "github.com/coreos/etcd/version", + "github.com/hashicorp/consul/api", + "github.com/hashicorp/memberlist", + "github.com/samuel/go-zookeeper/zk", + "github.com/sirupsen/logrus", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/require", + "golang.org/x/net/context", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/status", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/portworx/kvdb/Gopkg.toml b/vendor/github.com/portworx/kvdb/Gopkg.toml new file mode 100644 index 000000000..3aa5c21d3 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/Gopkg.toml @@ -0,0 +1,70 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/boltdb/bolt" + version = "1.3.1" + +[[constraint]] + name = "github.com/coreos/etcd" + version = "=3.3.13" + +[[constraint]] + name = "google.golang.org/grpc" + version = "=1.7.5" + +[[constraint]] + name = "github.com/hashicorp/consul" + version = "=1.0.0" + +[[constraint]] + name = "github.com/hashicorp/memberlist" + version = "0.1.3" + +[[constraint]] + branch = "master" + name = "github.com/samuel/go-zookeeper" + +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.3.0" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.3.0" + +[[constraint]] + branch = "master" + name = "golang.org/x/net" + +[[override]] + name = "github.com/coreos/bbolt" + version = "=1.3.1-coreos.6" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/portworx/kvdb/LICENSE b/vendor/github.com/portworx/kvdb/LICENSE new file mode 100644 index 000000000..245b737d6 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015-2020 Portworx, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/portworx/kvdb/Makefile b/vendor/github.com/portworx/kvdb/Makefile new file mode 100644 index 000000000..d90d04a9c --- /dev/null +++ b/vendor/github.com/portworx/kvdb/Makefile @@ -0,0 +1,79 @@ +ifndef PKGS +PKGS := $(shell go list ./... 2>&1 | grep -v test) +endif + +all: test + +deps: + dep ensure -v + +updatedeps: + dep ensure -update -v + +build: deps + go build ./... + +install: deps + go install ./... + +lint: + go get -v github.com/golang/lint/golint + for file in $$(find . -name '*.go' | grep -v '\.pb\.go' | grep -v '\.pb\.gw\.go'); do \ + golint $${file}; \ + if [ -n "$$(golint $${file})" ]; then \ + exit 1; \ + fi; \ + done + +vet: + go vet ./... + +errcheck: + go get -v github.com/kisielk/errcheck + errcheck \ + github.com/portworx/kvdb \ + github.com/portworx/kvdb/common \ + github.com/portworx/kvdb/consul \ + github.com/portworx/kvdb/mem \ + github.com/portworx/kvdb/wrappers \ + github.com/portworx/kvdb/zookeeper + +pretest: deps errcheck lint vet + +gotest: + for pkg in $(PKGS); \ + do \ + go test --timeout 1h -v -tags unittest -coverprofile=profile.out -covermode=atomic $(BUILD_OPTIONS) $${pkg} || exit 1; \ + if [ -f profile.out ]; then \ + cat profile.out >> coverage.txt; \ + rm profile.out; \ + fi; \ + done + +test: pretest gotest + +docker-build-kvdb-dev: + docker build -t portworx/kvdb:test_container -f $(GOPATH)/src/github.com/portworx/kvdb/Dockerfile.kvdb . + +docker-test: + docker run --rm \ + -v $(GOPATH)/src/github.com/portworx/kvdb:/go/src/github.com/portworx/kvdb \ + portworx/kvdb:test_container \ + make gotest + +clean: + go clean -i ./... + +.PHONY: \ + all \ + deps \ + updatedeps \ + build \ + install \ + lint \ + vet \ + errcheck \ + pretest \ + gotest \ + test \ + clean diff --git a/vendor/github.com/portworx/kvdb/README.md b/vendor/github.com/portworx/kvdb/README.md new file mode 100644 index 000000000..a54152790 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/README.md @@ -0,0 +1,154 @@ +# kvdb + +[![GoDoc](https://godoc.org/github.com/portworx/kvdb?status.png)](https://godoc.org/github.com/portworx/kvdb) +[![Travis branch](https://img.shields.io/travis/portworx/kvdb/master.svg)](https://travis-ci.org/portworx/kvdb) +[![Go Report Card](https://goreportcard.com/badge/github.com/portworx/kvdb)](https://goreportcard.com/report/github.com/portworx/kvdb) +[![Code Coverage](https://codecov.io/gh/portworx/kvdb/branch/master/graph/badge.svg)](https://codecov.io/gh/portworx/kvdb) + +Key Value Store abstraction library. + +The kvdb library abstracts the caller from the specific key-value database implementation. The main goal of the kvdb library is to provide simple APIs to deal with only keys and values, and abstract away the intricate details of a specific key value stores. It also provides support for complex APIs like Snapshot, Watch and Lock which are built using the basic APIs. + +### Supported key value stores + +* `Etcd v2` +* `Etcd v3` +* `Consul` +* `In-memory store` (local to the node) +* `Bolt DB` (local to the node) +* `Zookeeper` + +### Usage + +The kvdb library is easy to use and requires you to create a new instance of the Kvdb object + +``` +package main + +import ( + "github.com/portworx/kvdb" + "github.com/portworx/kvdb/etcd/v3" + "github.com/libopenstorage/openstorage/pkg/dbg" +) + +func getKvdb( + kvdbName string, // Use one of the kv store implementation names + basePath string, // The path under which all the keys will be created by this kv instance + discoveryEndpoints []string, // A list of kv store endpoints + options map[string]string, // Options that need to be passed to the kv store + panicHandler kvdb.FatalErrorCB, // A callback function to execute when the library needs to panic +) (kvdb.Kvdb, error) { + + kv, err := kvdb.New( + kvdbName, + basePath, + discoveryEndpoints, + options, + panicHandler, + ) + return kv, err + +} + +type A struct { + a1 string + a2 int +} + +func main() { + + // An example kvdb using etcd v3 as a key value store + kv, err := getKvdb( + v3.Name, + "root/", + []{"127.0.0.1:2379"}, + nil, + dbg.Panicf, + ) + if err != nil { + fmt.Println("Failed to create a kvdb instance: ", err) + return + } + + // Put a key value pair foo=bar + a := &A{"bar", 1} + _, err = kv.Put("foo", &a, 0) + if err != nil { + fmt.Println("Failed to put a key in kvdb: ", err) + return + } + + // Get a key + value := A{} + _, err = kv.GetVal("foo", &value) + if err != nil { + fmt.Println("Failed to get a key from kvdb: ", err) + return + } +} + +``` + +### Contributing + +We are always looking for contributions from the open source community. Send out a PR and we will review it. + + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. The rules are pretty simple: if you +can certify the below (from +[developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +You can add the sign off when creating the git commit via `git commit -s`. + +### License + +kvdb library is licensed under the Apache License 2.0 diff --git a/vendor/github.com/portworx/kvdb/kvdb.go b/vendor/github.com/portworx/kvdb/kvdb.go new file mode 100644 index 000000000..eb0620941 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/kvdb.go @@ -0,0 +1,452 @@ +package kvdb + +import ( + "errors" + "time" + + "github.com/sirupsen/logrus" +) + +const ( + // KVSet signifies the KV was modified. + KVSet KVAction = 1 << iota + // KVCreate set if the KV pair was created. + KVCreate + // KVGet set when the key is fetched from the KV store + KVGet + // KVDelete set when the key is deleted from the KV store + KVDelete + // KVExpire set when the key expires + KVExpire + // KVUknown operation on KV pair + KVUknown +) + +const ( + // KVCapabilityOrderedUpdates support requires watch to send an watch update + // for every put - instead of coalescing multiple puts in one update. + KVCapabilityOrderedUpdates = 1 << iota +) + +const ( + // KVPrevExists flag to check key already exists + KVPrevExists KVFlags = 1 << iota + // KVCreatedIndex flag compares with passed in index (possibly in KVPair) + KVCreatedIndex + // KVModifiedIndex flag compares with passed in index (possibly in KVPair) + KVModifiedIndex + // KVTTL uses TTL val from KVPair. + KVTTL +) + +const ( + // ReadPermission for read only access + ReadPermission = iota + // WritePermission for write only access + WritePermission + // ReadWritePermission for read-write access + ReadWritePermission +) +const ( + // UsernameKey for an authenticated kvdb endpoint + UsernameKey = "Username" + // PasswordKey for an authenticated kvdb endpoint + PasswordKey = "Password" + // CAFileKey is the CA file path for an authenticated kvdb endpoint + CAFileKey = "CAFile" + // CertFileKey is the certificate file path for an authenticated kvdb endpoint + CertFileKey = "CertFile" + // CertKeyFileKey is the key to the certificate + CertKeyFileKey = "CertKeyFile" + // TrustedCAFileKey is the key for the trusted CA. + TrustedCAFileKey = "TrustedCAFile" + // ClientCertAuthKey is the boolean value indicating client authenticated certificate. + ClientCertAuthKey = "ClientCertAuth" + // RetryCountKey is the integer value indicating the retry count of etcd operations + RetryCountKey = "RetryCount" + // ACLTokenKey is the token value for ACL based KV stores + ACLTokenKey = "ACLToken" + // CAAuthAddress is the address of CA signing authority (required in consul TLS config) + CAAuthAddress = "CAAuthAddress" + // InsecureSkipVerify has a value true or false (required in consul TLS config) + InsecureSkipVerify = "InsecureSkipVerify" + // TransportScheme points to http transport being either http or https. + TransportScheme = "TransportScheme" + // LogPathOption is the name of the option which specified the log path location + LogPathOption = "LogPathOption" +) + +// List of kvdb endpoints supported versions +const ( + // ConsulVersion1 key + ConsulVersion1 = "consulv1" + // EtcdBaseVersion key + EtcdBaseVersion = "etcd" + // EtcdVersion3 key + EtcdVersion3 = "etcdv3" + // MemVersion1 key + MemVersion1 = "memv1" + // BoltVersion1 key + BoltVersion1 = "boltv1" + // ZookeeperVersion1 key + ZookeeperVersion1 = "zookeeperv1" +) + +const ( + // DefaultLockTryDuration is the maximum time spent trying to acquire lock + DefaultLockTryDuration = 300 * time.Second + // DefaultSeparator separate key components + DefaultSeparator = "/" +) + +type WrapperName string + +const ( + Wrapper_None = WrapperName("Wrapper_None") + Wrapper_Log = WrapperName("Wrapper_Log") + Wrapper_NoQuorum = WrapperName("Wrapper_NoQuorum") +) + +type KvdbWrapper interface { + // WrapperName is the name of this wrapper + WrapperName() WrapperName + // WrappedKvdb is the Kvdb wrapped by this wrapper + WrappedKvdb() Kvdb + // Removed is called when wrapper is removed + Removed() + // WrappedKvdb is the Kvdb wrapped by this wrapper + SetWrappedKvdb(kvdb Kvdb) error +} + +var ( + // ErrNotSupported implemenation of a specific function is not supported. + ErrNotSupported = errors.New("implementation not supported") + // ErrWatchStopped is raised when user stops watch. + ErrWatchStopped = errors.New("Watch Stopped") + // ErrNotFound raised if Key is not found + ErrNotFound = errors.New("Key not found") + // ErrExist raised if key already exists + ErrExist = errors.New("Key already exists") + // ErrUnmarshal raised if Get fails to unmarshal value. + ErrUnmarshal = errors.New("Failed to unmarshal value") + // ErrIllegal raised if object is not valid. + ErrIllegal = errors.New("Illegal operation") + // ErrValueMismatch raised if existing KVDB value mismatches with user provided value + ErrValueMismatch = errors.New("Value mismatch") + // ErrEmptyValue raised if the value is empty + ErrEmptyValue = errors.New("Value cannot be empty") + // ErrModified raised during an atomic operation if the index does not match the one in the store + ErrModified = errors.New("Key Index mismatch") + // ErrSetTTLFailed raised if unable to set ttl value for a key create/put/update action + ErrSetTTLFailed = errors.New("Unable to set ttl value") + // ErrTTLNotSupported if kvdb implementation doesn't support TTL + ErrTTLNotSupported = errors.New("TTL value not supported") + // ErrInvalidLock Lock and unlock operations don't match. + ErrInvalidLock = errors.New("Invalid lock/unlock operation") + // ErrNoPassword provided + ErrNoPassword = errors.New("Username provided without any password") + // ErrAuthNotSupported authentication not supported for this kvdb implementation + ErrAuthNotSupported = errors.New("Kvdb authentication not supported") + // ErrNoCertificate no certificate provided for authentication + ErrNoCertificate = errors.New("Certificate File Path not provided") + // ErrUnknownPermission raised if unknown permission type + ErrUnknownPermission = errors.New("Unknown Permission Type") + // ErrMemberDoesNotExist returned when an operation fails for a member + // which does not exist + ErrMemberDoesNotExist = errors.New("Kvdb member does not exist") + // ErrWatchRevisionCompacted requested watch version has been compacted + ErrWatchRevisionCompacted = errors.New("Kvdb watch revision compacted") + // ErrLockRefreshFailed could not refresh lock key so exclusive access to lock may be lost + ErrLockRefreshFailed = errors.New("Failed to refresh lock") + // ErrLockHoldTimeoutTriggered triggers if lock is held beyond configured timeout + ErrLockHoldTimeoutTriggered = errors.New("Lock held beyond configured timeout") + // ErrNoConnection no connection to server + ErrNoConnection = errors.New("No server connection") + // ErrNoQuorum kvdb has lost quorum + ErrNoQuorum = errors.New("KVDB connection failed, either node has " + + "networking issues or KVDB members are down or KVDB cluster is unhealthy. " + + "All operations (get/update/delete) are unavailable.") +) + +// KVAction specifies the action on a KV pair. This is useful to make decisions +// from the results of a Watch. +type KVAction int + +// KVFlags options for operations on KVDB +type KVFlags uint64 + +// PermissionType for user access +type PermissionType int + +// WatchCB is called when a watched key or tree is modified. If the callback +// returns an error, then watch stops and the cb is called one last time +// with ErrWatchStopped. +type WatchCB func(prefix string, opaque interface{}, kvp *KVPair, err error) error + +// FatalErrorCB callback is invoked incase of fatal errors +type FatalErrorCB func(err error, format string, args ...interface{}) + +// DatastoreInit is called to activate a backend KV store. +type DatastoreInit func(domain string, machines []string, options map[string]string, + cb FatalErrorCB) (Kvdb, error) + +// DatastoreVersion is called to get the version of a backend KV store +type DatastoreVersion func(url string, kvdbOptions map[string]string) (string, error) + +// WrapperInit is called to activate a backend KV store. +type WrapperInit func(kv Kvdb, options map[string]string) (Kvdb, error) + +// EnumerateSelect function is a callback function provided to EnumerateWithSelect API +// This fn is executed over all the keys and only those values are returned by Enumerate for which +// this function return true. +type EnumerateSelect func(val interface{}) bool + +// CopySelect function is a callback function provided to EnumerateWithSelect API +// This fn should perform a deep copy of the input interface and return the copy +type CopySelect func(val interface{}) interface{} + +// EnumerateKVPSelect function is a callback function provided to EnumerateKVPWithSelect API +// This fn is executed over all the keys and only those values are returned by Enumerate for which +// this function return true. +type EnumerateKVPSelect func(kvp *KVPair, val interface{}) bool + +// CopyKVPSelect function is a callback function provided to EnumerateKVPWithSelect API +// This fn should perform a deep copy of the input KVPair and return the copy +type CopyKVPSelect func(kvp *KVPair, val interface{}) *KVPair + +// KVPair represents the results of an operation on KVDB. +type KVPair struct { + // Key for this kv pair. + Key string + // Value for this kv pair + Value []byte + // Action the last action on this KVPair. + Action KVAction + // TTL value after which this key will expire from KVDB + TTL int64 + // KVDBIndex A Monotonically index updated at each modification operation. + KVDBIndex uint64 + // CreatedIndex for this kv pair + CreatedIndex uint64 + // ModifiedIndex for this kv pair + ModifiedIndex uint64 + // Lock is a generic interface to represent a lock held on a key. + Lock interface{} +} + +// KVPairs list of KVPairs +type KVPairs []*KVPair + +// Tx Interface to transactionally apply updates to a set of keys. +type Tx interface { + // Put specified key value pair in TX. + Put(key string, value interface{}, ttl uint64) (*KVPair, error) + // Get returns KVPair in this TXs view. If not found, returns value from + // backing KVDB. + Get(key string) (*KVPair, error) + // Get same as get except that value has the unmarshalled value. + GetVal(key string, value interface{}) (*KVPair, error) + // Prepare returns an error it transaction cannot be logged. + Prepare() error + // Commit propagates updates to the KVDB. No operations on this Tx are + // allowed after commit. + Commit() error + // Abort aborts this transaction. No operations on this Tx are allowed + // afer commit. + Abort() error +} + +// Kvdb interface implemented by backing datastores. +type Kvdb interface { + Controller + // String representation of backend datastore. + String() string + // Capbilities - see KVCapabilityXXX + Capabilities() int + // Get returns KVPair that maps to specified key or ErrNotFound. + Get(key string) (*KVPair, error) + // Get returns KVPair that maps to specified key or ErrNotFound. If found + // value contains the unmarshalled result or error is ErrUnmarshal + GetVal(key string, value interface{}) (*KVPair, error) + // GetWithCopy returns a copy of the value as an interface for the specified key + GetWithCopy(key string, copySelect CopySelect) (interface{}, error) + // Put inserts value at key in kvdb. If value is a runtime.Object, it is + // marshalled. If Value is []byte it is set directly. If Value is a string, + // its byte representation is stored. + Put(key string, value interface{}, ttl uint64) (*KVPair, error) + // Create is the same as Put except that ErrExist is returned if the key exists. + Create(key string, value interface{}, ttl uint64) (*KVPair, error) + // Update is the same as Put except that ErrNotFound is returned if the key + // does not exist. + Update(key string, value interface{}, ttl uint64) (*KVPair, error) + // Enumerate returns a list of KVPair for all keys that share the specified prefix. + Enumerate(prefix string) (KVPairs, error) + // EnumerateWithSelect returns a copy of all values under the prefix that satisfy the select + // function in the provided output array of interfaces + EnumerateWithSelect(prefix string, enumerateSelect EnumerateSelect, copySelect CopySelect) ([]interface{}, error) + // EnumerateKVPWithSelect returns a copy of all the KVPairs under the prefix that satisfy the select + // function in the provided output array of key-value pairs + EnumerateKVPWithSelect(prefix string, enumerateSelect EnumerateKVPSelect, copySelect CopyKVPSelect) (KVPairs, error) + // Delete deletes the KVPair specified by the key. ErrNotFound is returned + // if the key is not found. The old KVPair is returned if successful. + Delete(key string) (*KVPair, error) + // DeleteTree same as Delete execpt that all keys sharing the prefix are + // deleted. + DeleteTree(prefix string) error + // Keys returns an array of keys that share specified prefix (ie. "1st level directory"). + // sep parameter defines a key-separator, and if not provided the "/" is assumed. + Keys(prefix, sep string) ([]string, error) + // CompareAndSet updates value at kvp.Key if the previous resident + // satisfies conditions set in flags and optional prevValue. + CompareAndSet(kvp *KVPair, flags KVFlags, prevValue []byte) (*KVPair, error) + // CompareAndDelete deletes value at kvp.Key if the previous resident matches + // satisfies conditions set in flags. + CompareAndDelete(kvp *KVPair, flags KVFlags) (*KVPair, error) + // WatchKey calls watchCB everytime a value at key is updated. waitIndex + // is the oldest ModifiedIndex of a KVPair for which updates are requestd. + WatchKey(key string, waitIndex uint64, opaque interface{}, watchCB WatchCB) error + // WatchTree is the same as WatchKey except that watchCB is triggered + // for updates on all keys that share the prefix. + WatchTree(prefix string, waitIndex uint64, opaque interface{}, watchCB WatchCB) error + // Snapshot returns a kvdb snapshot of the provided list of prefixes and the last updated index. + // If no prefixes are provided, then the whole kvdb tree is snapshotted and could be potentially an expensive operation + // If consistent is true, then snapshot is going to return all the updates happening during the snapshot operation and the last + // updated index from the snapshot + Snapshot(prefixes []string, consistent bool) (Kvdb, uint64, error) + // SnapPut records the key value pair including the index. + SnapPut(kvp *KVPair) (*KVPair, error) + // Lock specfied key and associate a lockerID with it, probably to identify + // who acquired the lock. The KVPair returned should be used to unlock. + LockWithID(key string, lockerID string) (*KVPair, error) + // Lock specfied key. The KVPair returned should be used to unlock. + Lock(key string) (*KVPair, error) + // Lock with specified key and associate a lockerID with it. + // lockTryDuration is the maximum time that can be spent trying to acquire + // lock, else return error. + // lockHoldDuration is the maximum time the lock can be held, after which + // FatalCb is invoked. + // The KVPair returned should be used to unlock if successful. + LockWithTimeout(key string, lockerID string, lockTryDuration time.Duration, + lockHoldDuration time.Duration) (*KVPair, error) + // IsKeyLocked returns a boolean if the lock is held or not. If held, returns the owner. + IsKeyLocked(key string) (bool, string, error) + // Unlock kvp previously acquired through a call to lock. + Unlock(kvp *KVPair) error + // TxNew returns a new Tx coordinator object or ErrNotSupported + TxNew() (Tx, error) + // AddUser adds a new user to kvdb + AddUser(username string, password string) error + // RemoveUser removes a user from kvdb + RemoveUser(username string) error + // GrantUserAccess grants user access to a subtree/prefix based on the permission + GrantUserAccess(username string, permType PermissionType, subtree string) error + // RevokeUsersAccess revokes user's access to a subtree/prefix based on the permission + RevokeUsersAccess(username string, permType PermissionType, subtree string) error + // SetFatalCb sets the function to be called in case of fatal errors + SetFatalCb(f FatalErrorCB) + // SetLockHoldDuration sets maximum time a lock may be held + SetLockHoldDuration(timeout time.Duration) + // GetLockTryDuration gets the maximum time to attempt to get a lock. + GetLockTryDuration() time.Duration + // GetLockHoldDuration gets the currently set lock hold timeout + GetLockHoldDuration() time.Duration + // Serialize serializes all the keys under the domain and returns a byte array + Serialize() ([]byte, error) + // Deserialize deserializes the given byte array into a list of kv pairs + Deserialize([]byte) (KVPairs, error) + // Compact removes the history before the specified index/revision to reduce the space and memory usage + Compact(index uint64) error + KvdbWrapper +} + +// ReplayCb provides info required for replay +type ReplayCb struct { + // Prefix is the watch key/tree prefix + Prefix string + // WaitIndex is the index after which updates must be returned + WaitIndex uint64 + // Opaque is a hint returned by the caller + Opaque interface{} + // WatchCB is the watch callback + WatchCB WatchCB +} + +// UpdatesCollector collects updates from kvdb. +type UpdatesCollector interface { + // Stop collecting updates + Stop() + // ReplayUpdates replays the collected updates. + // Returns the version until the replay's were done + // and any errors it encountered. + ReplayUpdates(updateCb []ReplayCb) (uint64, error) +} + +// NewUpdatesCollector creates new Kvdb collector that collects updates +// starting at startIndex + 1 index. +func NewUpdatesCollector( + db Kvdb, + prefix string, + startIndex uint64, +) (UpdatesCollector, error) { + collector := &updatesCollectorImpl{updates: make([]*kvdbUpdate, 0), + startIndex: startIndex} + logrus.Infof("Starting collector watch on %v at %v", prefix, startIndex) + if err := db.WatchTree(prefix, startIndex, nil, collector.watchCb); err != nil { + return nil, err + } + return collector, nil +} + +// List of kvdb controller ports +const ( + // PeerPort is the port on which peers identify themselves + PeerPort = "2380" + // ClientPort is the port on which clients send requests to kvdb. + ClientPort = "2379" +) + +// MemberInfo represents a member of the kvdb cluster +type MemberInfo struct { + PeerUrls []string + ClientUrls []string + Leader bool + DbSize int64 + IsHealthy bool + ID string +} + +// Controller interface provides APIs to manage Kvdb Cluster and Kvdb Clients. +type Controller interface { + // AddMember adds a new member to an existing kvdb cluster. Add should be + // called on a kvdb node where kvdb is already running. It should be + // followed by a Setup call on the actual node + // Returns: map of nodeID to peerUrls of all members in the initial cluster or error + AddMember(nodeIP, nodePeerPort, nodeName string) (map[string][]string, error) + + // RemoveMember removes a member from an existing kvdb cluster + // Returns: error if it fails to remove a member + RemoveMember(nodeName, nodeIP string) error + + // UpdateMember updates the IP for the given node in an existing kvdb cluster + // Returns: map of nodeID to peerUrls of all members from the existing cluster + UpdateMember(nodeIP, nodePeerPort, nodeName string) (map[string][]string, error) + + // ListMembers enumerates the members of the kvdb cluster + // Returns: the nodeID to memberInfo mappings of all the members + ListMembers() (map[string]*MemberInfo, error) + + // SetEndpoints set the kvdb endpoints for the client + SetEndpoints(endpoints []string) error + + // GetEndpoints returns the kvdb endpoints for the client + GetEndpoints() []string + + // Defragment defrags the underlying database for the given endpoint + // with a timeout specified in seconds + Defragment(endpoint string, timeout int) error +} + +func LogFatalErrorCB(err error, format string, args ...interface{}) { + logrus.Errorf("encountered fatal error: %v", err) + logrus.Panicf(format, args...) +} diff --git a/vendor/github.com/portworx/kvdb/kvdb_controller_not_supported.go b/vendor/github.com/portworx/kvdb/kvdb_controller_not_supported.go new file mode 100644 index 000000000..7b97adcc9 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/kvdb_controller_not_supported.go @@ -0,0 +1,37 @@ +package kvdb + +var ( + // ControllerNotSupported is a null controller implementation. This can be used + // kvdb implementors that do no want to implement the controller interface + ControllerNotSupported = &controllerNotSupported{} +) + +type controllerNotSupported struct{} + +func (c *controllerNotSupported) AddMember(nodeIP, nodePeerPort, nodeName string) (map[string][]string, error) { + return nil, ErrNotSupported +} + +func (c *controllerNotSupported) RemoveMember(nodeID string, nodeIP string) error { + return ErrNotSupported +} + +func (c *controllerNotSupported) UpdateMember(nodeIP, nodePeerPort, nodeName string) (map[string][]string, error) { + return nil, ErrNotSupported +} + +func (c *controllerNotSupported) ListMembers() (map[string]*MemberInfo, error) { + return nil, ErrNotSupported +} + +func (c *controllerNotSupported) SetEndpoints(endpoints []string) error { + return ErrNotSupported +} + +func (c *controllerNotSupported) GetEndpoints() []string { + return []string{} +} + +func (c *controllerNotSupported) Defragment(endpoint string, timeout int) error { + return ErrNotSupported +} diff --git a/vendor/github.com/portworx/kvdb/kvdb_mgr.go b/vendor/github.com/portworx/kvdb/kvdb_mgr.go new file mode 100644 index 000000000..847042d7f --- /dev/null +++ b/vendor/github.com/portworx/kvdb/kvdb_mgr.go @@ -0,0 +1,132 @@ +package kvdb + +import ( + "fmt" + "sync" +) + +var ( + instance Kvdb + datastores = make(map[string]DatastoreInit) + datastoreVersions = make(map[string]DatastoreVersion) + wrappers = make(map[WrapperName]WrapperInit) + lock sync.RWMutex +) + +// Instance returns instance set via SetInstance, nil if none was set. +func Instance() Kvdb { + return instance +} + +// SetInstance sets the singleton instance. +func SetInstance(kvdb Kvdb) error { + instance = kvdb + return nil +} + +// New return a new instance of KVDB as specified by datastore name. +// If domain is set all requests to KVDB are prefixed by domain. +// options is interpreted by backend KVDB. +func New( + name string, + domain string, + machines []string, + options map[string]string, + errorCB FatalErrorCB, +) (Kvdb, error) { + lock.RLock() + defer lock.RUnlock() + if dsInit, exists := datastores[name]; exists { + return dsInit(domain, machines, options, errorCB) + } + return nil, ErrNotSupported +} + +// AddWrapper adds wrapper is it is not already added +func AddWrapper( + wrapper WrapperName, + kvdb Kvdb, + options map[string]string, +) (Kvdb, error) { + lock.Lock() + defer lock.Unlock() + + for w := kvdb; w != nil; w = w.WrappedKvdb() { + if w.WrapperName() == wrapper { + return kvdb, fmt.Errorf("wrapper %v already present in kvdb", + wrapper) + } + } + if initFn, ok := wrappers[wrapper]; !ok { + return kvdb, fmt.Errorf("wrapper %v not found", wrapper) + } else { + // keep log wrapper at the top if it exists + if kvdb.WrapperName() == Wrapper_Log { + newWrapper, err := initFn(kvdb.WrappedKvdb(), options) + if err == nil { + kvdb.SetWrappedKvdb(newWrapper) + return kvdb, nil + } else { + return kvdb, err + } + } + return initFn(kvdb, options) + } +} + +// RemoveWrapper adds wrapper is it is not already added +func RemoveWrapper( + wrapper WrapperName, + kvdb Kvdb, +) (Kvdb, error) { + var prevWrapper Kvdb + for w := kvdb; w != nil; w = w.WrappedKvdb() { + if w.WrapperName() == wrapper { + w.Removed() + if prevWrapper != nil { + prevWrapper.SetWrappedKvdb(w.WrappedKvdb()) + return kvdb, nil + } else { + // removing the top-most wrapper + return w.WrappedKvdb(), nil + } + } + prevWrapper = w + } + return kvdb, nil // did not find the wrapper to remove +} + +// Register adds specified datastore backend to the list of options. +func Register(name string, dsInit DatastoreInit, dsVersion DatastoreVersion) error { + lock.Lock() + defer lock.Unlock() + if _, exists := datastores[name]; exists { + return fmt.Errorf("Datastore provider %q is already registered", name) + } + datastores[name] = dsInit + + if _, exists := datastoreVersions[name]; exists { + return fmt.Errorf("Datastore provider's %q version function already registered", name) + } + datastoreVersions[name] = dsVersion + return nil +} + +// Register wrapper +func RegisterWrapper(name WrapperName, initFn WrapperInit) error { + lock.Lock() + defer lock.Unlock() + wrappers[name] = initFn + return nil +} + +// Version returns the supported version for the provided kvdb endpoint. +func Version(name string, url string, kvdbOptions map[string]string) (string, error) { + lock.RLock() + defer lock.RUnlock() + + if dsVersion, exists := datastoreVersions[name]; exists { + return dsVersion(url, kvdbOptions) + } + return "", ErrNotSupported +} diff --git a/vendor/github.com/portworx/kvdb/updates_collector.go b/vendor/github.com/portworx/kvdb/updates_collector.go new file mode 100644 index 000000000..9bde015d8 --- /dev/null +++ b/vendor/github.com/portworx/kvdb/updates_collector.go @@ -0,0 +1,99 @@ +package kvdb + +import ( + "fmt" + "strings" + "sync" + + "github.com/sirupsen/logrus" +) + +type kvdbUpdate struct { + // prefix is the path on which update was triggered + prefix string + // kvp is the actual key-value pair update + kvp *KVPair + // errors on update + err error +} + +type updatesCollectorImpl struct { + // stopped is true if collection is stopped + stopped bool + // stoppedMutex protects stopped flag + stoppedMutex sync.RWMutex + // start index + startIndex uint64 + // updatesMutex protects updates and start index + updatesMutex sync.Mutex + // updates stores the updates in order + updates []*kvdbUpdate +} + +func (c *updatesCollectorImpl) setStopped() { + c.stoppedMutex.Lock() + c.stopped = true + c.stoppedMutex.Unlock() +} + +func (c *updatesCollectorImpl) isStopped() bool { + c.stoppedMutex.RLock() + defer c.stoppedMutex.RUnlock() + return c.stopped +} + +func (c *updatesCollectorImpl) watchCb( + prefix string, + opaque interface{}, + kvp *KVPair, + err error, +) error { + if c.isStopped() { + return fmt.Errorf("Stopped watch") + } + if err != nil { + c.setStopped() + return err + } + update := &kvdbUpdate{prefix: prefix, kvp: kvp, err: err} + c.updatesMutex.Lock() + c.updates = append(c.updates, update) + c.updatesMutex.Unlock() + return nil +} + +func (c *updatesCollectorImpl) Stop() { + logrus.Info("Stopping updates collector") + c.setStopped() +} + +func (c *updatesCollectorImpl) ReplayUpdates( + cbList []ReplayCb, +) (uint64, error) { + c.updatesMutex.Lock() + updates := make([]*kvdbUpdate, len(c.updates)) + copy(updates, c.updates) + c.updatesMutex.Unlock() + index := c.startIndex + logrus.Infof("collect: replaying %d update(s) for %d callback(s)", + len(updates), len(cbList)) + for _, update := range updates { + if update.kvp == nil { + continue + } + index = update.kvp.ModifiedIndex + for _, cbInfo := range cbList { + if strings.HasPrefix(update.kvp.Key, cbInfo.Prefix) && + cbInfo.WaitIndex < update.kvp.ModifiedIndex { + err := cbInfo.WatchCB(update.prefix, cbInfo.Opaque, update.kvp, + update.err) + if err != nil { + logrus.Infof("collect error: watchCB returned error: %v", + err) + return index, err + } + } // else ignore the update + } + } + return index, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d22fe37c0..ce52877e3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -109,6 +109,9 @@ github.com/codegangsta/inject # github.com/codeskyblue/go-sh v0.0.0-20170112005953-b097669b1569 ## explicit github.com/codeskyblue/go-sh +# github.com/coreos/etcd v3.3.27+incompatible +## explicit +github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes # github.com/coreos/go-oidc v2.2.1+incompatible ## explicit github.com/coreos/go-oidc @@ -232,6 +235,9 @@ github.com/pborman/uuid # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib +# github.com/portworx/kvdb v0.0.0-20230326003017-21a38cf82d4b +## explicit +github.com/portworx/kvdb # github.com/portworx/sched-ops v1.20.4-rc1.0.20211217234328-ead591c0f22d ## explicit; go 1.12 github.com/portworx/sched-ops/k8s/common @@ -269,6 +275,8 @@ github.com/sony/gobreaker # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag +# github.com/stretchr/objx v0.2.0 +## explicit; go 1.12 # github.com/stretchr/testify v1.7.0 ## explicit; go 1.13 github.com/stretchr/testify/assert diff --git a/vsphere/vsphere.go b/vsphere/vsphere.go index e2b731049..063cd2ca2 100644 --- a/vsphere/vsphere.go +++ b/vsphere/vsphere.go @@ -2,8 +2,8 @@ package vsphere import ( "context" + "errors" "fmt" - "github.com/portworx/sched-ops/k8s/core/configmap" "path" "path/filepath" "regexp" @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/go-version" "github.com/libopenstorage/cloudops" "github.com/libopenstorage/cloudops/backoff" + "github.com/libopenstorage/cloudops/store" "github.com/libopenstorage/cloudops/unsupported" "github.com/libopenstorage/cloudops/vsphere/lib/vsphere/vclib" "github.com/libopenstorage/cloudops/vsphere/lib/vsphere/vclib/diskmanagers" @@ -38,10 +39,11 @@ type vsphereOps struct { vm *vclib.VirtualMachine conn *vclib.VSphereConnection cfg *VSphereConfig - dsLock configmap.ConfigMap + dsLock store.Store } var ( + ErrInvalidParam = errors.New("invalid param") exponentialBackoff = wait.Backoff{ Duration: 2 * time.Second, // the base duration Factor: 1.2, // Duration is multiplied by factor each iteration @@ -62,7 +64,10 @@ type VirtualDisk struct { } // NewClient creates a new vsphere cloudops instance -func NewClient(cfg *VSphereConfig) (cloudops.Ops, error) { +func NewClient(cfg *VSphereConfig, storeParams *store.Params) (cloudops.Ops, error) { + if storeParams == nil { + return nil, ErrInvalidParam + } vSphereConn := &vclib.VSphereConnection{ Username: cfg.User, Password: cfg.Password, @@ -84,7 +89,13 @@ func NewClient(cfg *VSphereConfig) (cloudops.Ops, error) { logrus.Debugf(" Datacenter: %s", vmObj.Datacenter.Name()) logrus.Debugf(" VMUUID: %s", cfg.VMUUID) - configMap, err := configmap.New(vSphereDataStoreLock, nil, 0, 420, 5*time.Second, 10*time.Second) + storeInstance, err := store.GetStoreWithParams( + storeParams.Kv, + storeParams.SchedulerType, + storeParams.InternalKvdb, + vSphereDataStoreLock, + 420*time.Second, + 100*time.Second) if err != nil { logrus.Errorf(err.Error()) return nil, err @@ -96,7 +107,7 @@ func NewClient(cfg *VSphereConfig) (cloudops.Ops, error) { cfg: cfg, vm: vmObj, conn: vSphereConn, - dsLock: configMap, + dsLock: storeInstance, }, isExponentialError, exponentialBackoff, @@ -756,9 +767,13 @@ func (ops *vsphereOps) getDatastoreToUseInStoragePod( } spec.DeviceChange = deviceChange - ops.dsLock.LockWithKey(ops.cfg.VMUUID, storagePod.Name()) + // It's best effort locking. If we didn't get a lock no harm done. + storeLock, lockErr := ops.dsLock.LockWithKey(ops.cfg.VMUUID, storagePod.Name()) recommendedDatastore, err := recommendDatastore(ctx, vmObj, storagePod, spec) - ops.dsLock.UnlockWithKey(storagePod.Name()) + if lockErr == nil { + ops.dsLock.Unlock(storeLock) + } + if err != nil { return "", err } diff --git a/vsphere/vsphere_test.go b/vsphere/vsphere_test.go index acf72c97a..61559283e 100644 --- a/vsphere/vsphere_test.go +++ b/vsphere/vsphere_test.go @@ -7,6 +7,7 @@ import ( "github.com/libopenstorage/cloudops" "github.com/libopenstorage/cloudops/test" "github.com/libopenstorage/cloudops/vsphere/lib/vsphere/vclib" + "github.com/libopenstorage/cloudops/store" "github.com/pborman/uuid" "github.com/stretchr/testify/require" "github.com/vmware/govmomi/object" @@ -34,7 +35,8 @@ func initVsphere(t *testing.T) (cloudops.Ops, map[string]interface{}) { datastoreForTest, err = cloudops.GetEnvValueStrict("VSPHERE_TEST_DATASTORE") require.NoError(t, err, "failed to get datastore from env variable VSPHERE_TEST_DATASTORE") - driver, err = NewClient(cfg) + var storeParams store.Params + driver, err = NewClient(cfg, &storeParams) require.NoError(t, err, "failed to instantiate storage ops driver") diskOptions := &vclib.VolumeOptions{