[VOL-2193] Create mocks for Kafka Client and Etcd
This commit consists of:
1) A kafka client mock that implements the kafka client interface
under voltha-lib-go/pkg/kafka/client.go
2) An embedded Etcd server that runs in-process and represents an
Etcd server.
Change-Id: I52a36132568e08c596bb4136918bebcb654a3b99
diff --git a/vendor/go.etcd.io/etcd/pkg/adt/README.md b/vendor/go.etcd.io/etcd/pkg/adt/README.md
new file mode 100644
index 0000000..a2089cd
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/adt/README.md
@@ -0,0 +1,48 @@
+
+## Red-Black Tree
+
+*"Introduction to Algorithms" (Cormen et al, 3rd ed.), Chapter 13*
+
+1. Every node is either red or black.
+2. The root is black.
+3. Every leaf (NIL) is black.
+4. If a node is red, then both its children are black.
+5. For each node, all simple paths from the node to descendant leaves contain the
+same number of black nodes.
+
+For example,
+
+```go
+import (
+ "fmt"
+
+ "go.etcd.io/etcd/pkg/adt"
+)
+
+func main() {
+ ivt := adt.NewIntervalTree()
+ ivt.Insert(NewInt64Interval(510, 511), 0)
+ ivt.Insert(NewInt64Interval(82, 83), 0)
+ ivt.Insert(NewInt64Interval(830, 831), 0)
+ ...
+```
+
+After inserting the values `510`, `82`, `830`, `11`, `383`, `647`, `899`, `261`, `410`, `514`, `815`, `888`, `972`, `238`, `292`, `953`.
+
+![red-black-tree-01-insertion.png](img/red-black-tree-01-insertion.png)
+
+Deleting the node `514` should not trigger any rebalancing:
+
+![red-black-tree-02-delete-514.png](img/red-black-tree-02-delete-514.png)
+
+Deleting the node `11` triggers multiple rotates for rebalancing:
+
+![red-black-tree-03-delete-11.png](img/red-black-tree-03-delete-11.png)
+![red-black-tree-04-delete-11.png](img/red-black-tree-04-delete-11.png)
+![red-black-tree-05-delete-11.png](img/red-black-tree-05-delete-11.png)
+![red-black-tree-06-delete-11.png](img/red-black-tree-06-delete-11.png)
+![red-black-tree-07-delete-11.png](img/red-black-tree-07-delete-11.png)
+![red-black-tree-08-delete-11.png](img/red-black-tree-08-delete-11.png)
+![red-black-tree-09-delete-11.png](img/red-black-tree-09-delete-11.png)
+
+Try yourself at https://www.cs.usfca.edu/~galles/visualization/RedBlack.html.
diff --git a/vendor/go.etcd.io/etcd/pkg/adt/doc.go b/vendor/go.etcd.io/etcd/pkg/adt/doc.go
new file mode 100644
index 0000000..1a95591
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/adt/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 adt implements useful abstract data types.
+package adt
diff --git a/vendor/go.etcd.io/etcd/pkg/adt/interval_tree.go b/vendor/go.etcd.io/etcd/pkg/adt/interval_tree.go
new file mode 100644
index 0000000..2e5b2dd
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/adt/interval_tree.go
@@ -0,0 +1,951 @@
+// 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 adt
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "strings"
+)
+
+// Comparable is an interface for trichotomic comparisons.
+type Comparable interface {
+ // Compare gives the result of a 3-way comparison
+ // a.Compare(b) = 1 => a > b
+ // a.Compare(b) = 0 => a == b
+ // a.Compare(b) = -1 => a < b
+ Compare(c Comparable) int
+}
+
+type rbcolor int
+
+const (
+ black rbcolor = iota
+ red
+)
+
+func (c rbcolor) String() string {
+ switch c {
+ case black:
+ return "black"
+ case red:
+ return "black"
+ default:
+ panic(fmt.Errorf("unknown color %d", c))
+ }
+}
+
+// Interval implements a Comparable interval [begin, end)
+// TODO: support different sorts of intervals: (a,b), [a,b], (a, b]
+type Interval struct {
+ Begin Comparable
+ End Comparable
+}
+
+// Compare on an interval gives == if the interval overlaps.
+func (ivl *Interval) Compare(c Comparable) int {
+ ivl2 := c.(*Interval)
+ ivbCmpBegin := ivl.Begin.Compare(ivl2.Begin)
+ ivbCmpEnd := ivl.Begin.Compare(ivl2.End)
+ iveCmpBegin := ivl.End.Compare(ivl2.Begin)
+
+ // ivl is left of ivl2
+ if ivbCmpBegin < 0 && iveCmpBegin <= 0 {
+ return -1
+ }
+
+ // iv is right of iv2
+ if ivbCmpEnd >= 0 {
+ return 1
+ }
+
+ return 0
+}
+
+type intervalNode struct {
+ // iv is the interval-value pair entry.
+ iv IntervalValue
+ // max endpoint of all descendent nodes.
+ max Comparable
+ // left and right are sorted by low endpoint of key interval
+ left, right *intervalNode
+ // parent is the direct ancestor of the node
+ parent *intervalNode
+ c rbcolor
+}
+
+func (x *intervalNode) color(sentinel *intervalNode) rbcolor {
+ if x == sentinel {
+ return black
+ }
+ return x.c
+}
+
+func (x *intervalNode) height(sentinel *intervalNode) int {
+ if x == sentinel {
+ return 0
+ }
+ ld := x.left.height(sentinel)
+ rd := x.right.height(sentinel)
+ if ld < rd {
+ return rd + 1
+ }
+ return ld + 1
+}
+
+func (x *intervalNode) min(sentinel *intervalNode) *intervalNode {
+ for x.left != sentinel {
+ x = x.left
+ }
+ return x
+}
+
+// successor is the next in-order node in the tree
+func (x *intervalNode) successor(sentinel *intervalNode) *intervalNode {
+ if x.right != sentinel {
+ return x.right.min(sentinel)
+ }
+ y := x.parent
+ for y != sentinel && x == y.right {
+ x = y
+ y = y.parent
+ }
+ return y
+}
+
+// updateMax updates the maximum values for a node and its ancestors
+func (x *intervalNode) updateMax(sentinel *intervalNode) {
+ for x != sentinel {
+ oldmax := x.max
+ max := x.iv.Ivl.End
+ if x.left != sentinel && x.left.max.Compare(max) > 0 {
+ max = x.left.max
+ }
+ if x.right != sentinel && x.right.max.Compare(max) > 0 {
+ max = x.right.max
+ }
+ if oldmax.Compare(max) == 0 {
+ break
+ }
+ x.max = max
+ x = x.parent
+ }
+}
+
+type nodeVisitor func(n *intervalNode) bool
+
+// visit will call a node visitor on each node that overlaps the given interval
+func (x *intervalNode) visit(iv *Interval, sentinel *intervalNode, nv nodeVisitor) bool {
+ if x == sentinel {
+ return true
+ }
+ v := iv.Compare(&x.iv.Ivl)
+ switch {
+ case v < 0:
+ if !x.left.visit(iv, sentinel, nv) {
+ return false
+ }
+ case v > 0:
+ maxiv := Interval{x.iv.Ivl.Begin, x.max}
+ if maxiv.Compare(iv) == 0 {
+ if !x.left.visit(iv, sentinel, nv) || !x.right.visit(iv, sentinel, nv) {
+ return false
+ }
+ }
+ default:
+ if !x.left.visit(iv, sentinel, nv) || !nv(x) || !x.right.visit(iv, sentinel, nv) {
+ return false
+ }
+ }
+ return true
+}
+
+// IntervalValue represents a range tree node that contains a range and a value.
+type IntervalValue struct {
+ Ivl Interval
+ Val interface{}
+}
+
+// IntervalTree represents a (mostly) textbook implementation of the
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.) chapter 13 red-black tree
+// and chapter 14.3 interval tree with search supporting "stabbing queries".
+type IntervalTree interface {
+ // Insert adds a node with the given interval into the tree.
+ Insert(ivl Interval, val interface{})
+ // Delete removes the node with the given interval from the tree, returning
+ // true if a node is in fact removed.
+ Delete(ivl Interval) bool
+ // Len gives the number of elements in the tree.
+ Len() int
+ // Height is the number of levels in the tree; one node has height 1.
+ Height() int
+ // MaxHeight is the expected maximum tree height given the number of nodes.
+ MaxHeight() int
+ // Visit calls a visitor function on every tree node intersecting the given interval.
+ // It will visit each interval [x, y) in ascending order sorted on x.
+ Visit(ivl Interval, ivv IntervalVisitor)
+ // Find gets the IntervalValue for the node matching the given interval
+ Find(ivl Interval) *IntervalValue
+ // Intersects returns true if there is some tree node intersecting the given interval.
+ Intersects(iv Interval) bool
+ // Contains returns true if the interval tree's keys cover the entire given interval.
+ Contains(ivl Interval) bool
+ // Stab returns a slice with all elements in the tree intersecting the interval.
+ Stab(iv Interval) []*IntervalValue
+ // Union merges a given interval tree into the receiver.
+ Union(inIvt IntervalTree, ivl Interval)
+}
+
+// NewIntervalTree returns a new interval tree.
+func NewIntervalTree() IntervalTree {
+ sentinel := &intervalNode{
+ iv: IntervalValue{},
+ max: nil,
+ left: nil,
+ right: nil,
+ parent: nil,
+ c: black,
+ }
+ return &intervalTree{
+ root: sentinel,
+ count: 0,
+ sentinel: sentinel,
+ }
+}
+
+type intervalTree struct {
+ root *intervalNode
+ count int
+
+ // red-black NIL node
+ // use 'sentinel' as a dummy object to simplify boundary conditions
+ // use the sentinel to treat a nil child of a node x as an ordinary node whose parent is x
+ // use one shared sentinel to represent all nil leaves and the root's parent
+ sentinel *intervalNode
+}
+
+// TODO: make this consistent with textbook implementation
+//
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p324
+//
+// 0. RB-DELETE(T, z)
+// 1.
+// 2. y = z
+// 3. y-original-color = y.color
+// 4.
+// 5. if z.left == T.nil
+// 6. x = z.right
+// 7. RB-TRANSPLANT(T, z, z.right)
+// 8. else if z.right == T.nil
+// 9. x = z.left
+// 10. RB-TRANSPLANT(T, z, z.left)
+// 11. else
+// 12. y = TREE-MINIMUM(z.right)
+// 13. y-original-color = y.color
+// 14. x = y.right
+// 15. if y.p == z
+// 16. x.p = y
+// 17. else
+// 18. RB-TRANSPLANT(T, y, y.right)
+// 19. y.right = z.right
+// 20. y.right.p = y
+// 21. RB-TRANSPLANT(T, z, y)
+// 22. y.left = z.left
+// 23. y.left.p = y
+// 24. y.color = z.color
+// 25.
+// 26. if y-original-color == BLACK
+// 27. RB-DELETE-FIXUP(T, x)
+
+// Delete removes the node with the given interval from the tree, returning
+// true if a node is in fact removed.
+func (ivt *intervalTree) Delete(ivl Interval) bool {
+ z := ivt.find(ivl)
+ if z == ivt.sentinel {
+ return false
+ }
+
+ y := z
+ if z.left != ivt.sentinel && z.right != ivt.sentinel {
+ y = z.successor(ivt.sentinel)
+ }
+
+ x := ivt.sentinel
+ if y.left != ivt.sentinel {
+ x = y.left
+ } else if y.right != ivt.sentinel {
+ x = y.right
+ }
+
+ x.parent = y.parent
+
+ if y.parent == ivt.sentinel {
+ ivt.root = x
+ } else {
+ if y == y.parent.left {
+ y.parent.left = x
+ } else {
+ y.parent.right = x
+ }
+ y.parent.updateMax(ivt.sentinel)
+ }
+ if y != z {
+ z.iv = y.iv
+ z.updateMax(ivt.sentinel)
+ }
+
+ if y.color(ivt.sentinel) == black {
+ ivt.deleteFixup(x)
+ }
+
+ ivt.count--
+ return true
+}
+
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p326
+//
+// 0. RB-DELETE-FIXUP(T, z)
+// 1.
+// 2. while x ≠ T.root and x.color == BLACK
+// 3. if x == x.p.left
+// 4. w = x.p.right
+// 5. if w.color == RED
+// 6. w.color = BLACK
+// 7. x.p.color = RED
+// 8. LEFT-ROTATE(T, x, p)
+// 9. if w.left.color == BLACK and w.right.color == BLACK
+// 10. w.color = RED
+// 11. x = x.p
+// 12. else if w.right.color == BLACK
+// 13. w.left.color = BLACK
+// 14. w.color = RED
+// 15. RIGHT-ROTATE(T, w)
+// 16. w = w.p.right
+// 17. w.color = x.p.color
+// 18. x.p.color = BLACK
+// 19. LEFT-ROTATE(T, w.p)
+// 20. x = T.root
+// 21. else
+// 22. w = x.p.left
+// 23. if w.color == RED
+// 24. w.color = BLACK
+// 25. x.p.color = RED
+// 26. RIGHT-ROTATE(T, x, p)
+// 27. if w.right.color == BLACK and w.left.color == BLACK
+// 28. w.color = RED
+// 29. x = x.p
+// 30. else if w.left.color == BLACK
+// 31. w.right.color = BLACK
+// 32. w.color = RED
+// 33. LEFT-ROTATE(T, w)
+// 34. w = w.p.left
+// 35. w.color = x.p.color
+// 36. x.p.color = BLACK
+// 37. RIGHT-ROTATE(T, w.p)
+// 38. x = T.root
+// 39.
+// 40. x.color = BLACK
+//
+func (ivt *intervalTree) deleteFixup(x *intervalNode) {
+ for x != ivt.root && x.color(ivt.sentinel) == black {
+ if x == x.parent.left { // line 3-20
+ w := x.parent.right
+ if w.color(ivt.sentinel) == red {
+ w.c = black
+ x.parent.c = red
+ ivt.rotateLeft(x.parent)
+ w = x.parent.right
+ }
+ if w == nil {
+ break
+ }
+ if w.left.color(ivt.sentinel) == black && w.right.color(ivt.sentinel) == black {
+ w.c = red
+ x = x.parent
+ } else {
+ if w.right.color(ivt.sentinel) == black {
+ w.left.c = black
+ w.c = red
+ ivt.rotateRight(w)
+ w = x.parent.right
+ }
+ w.c = x.parent.color(ivt.sentinel)
+ x.parent.c = black
+ w.right.c = black
+ ivt.rotateLeft(x.parent)
+ x = ivt.root
+ }
+ } else { // line 22-38
+ // same as above but with left and right exchanged
+ w := x.parent.left
+ if w.color(ivt.sentinel) == red {
+ w.c = black
+ x.parent.c = red
+ ivt.rotateRight(x.parent)
+ w = x.parent.left
+ }
+ if w == nil {
+ break
+ }
+ if w.left.color(ivt.sentinel) == black && w.right.color(ivt.sentinel) == black {
+ w.c = red
+ x = x.parent
+ } else {
+ if w.left.color(ivt.sentinel) == black {
+ w.right.c = black
+ w.c = red
+ ivt.rotateLeft(w)
+ w = x.parent.left
+ }
+ w.c = x.parent.color(ivt.sentinel)
+ x.parent.c = black
+ w.left.c = black
+ ivt.rotateRight(x.parent)
+ x = ivt.root
+ }
+ }
+ }
+
+ if x != nil {
+ x.c = black
+ }
+}
+
+func (ivt *intervalTree) createIntervalNode(ivl Interval, val interface{}) *intervalNode {
+ return &intervalNode{
+ iv: IntervalValue{ivl, val},
+ max: ivl.End,
+ c: red,
+ left: ivt.sentinel,
+ right: ivt.sentinel,
+ parent: ivt.sentinel,
+ }
+}
+
+// TODO: make this consistent with textbook implementation
+//
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p315
+//
+// 0. RB-INSERT(T, z)
+// 1.
+// 2. y = T.nil
+// 3. x = T.root
+// 4.
+// 5. while x ≠ T.nil
+// 6. y = x
+// 7. if z.key < x.key
+// 8. x = x.left
+// 9. else
+// 10. x = x.right
+// 11.
+// 12. z.p = y
+// 13.
+// 14. if y == T.nil
+// 15. T.root = z
+// 16. else if z.key < y.key
+// 17. y.left = z
+// 18. else
+// 19. y.right = z
+// 20.
+// 21. z.left = T.nil
+// 22. z.right = T.nil
+// 23. z.color = RED
+// 24.
+// 25. RB-INSERT-FIXUP(T, z)
+
+// Insert adds a node with the given interval into the tree.
+func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
+ y := ivt.sentinel
+ z := ivt.createIntervalNode(ivl, val)
+ x := ivt.root
+ for x != ivt.sentinel {
+ y = x
+ if z.iv.Ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 {
+ x = x.left
+ } else {
+ x = x.right
+ }
+ }
+
+ z.parent = y
+ if y == ivt.sentinel {
+ ivt.root = z
+ } else {
+ if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 {
+ y.left = z
+ } else {
+ y.right = z
+ }
+ y.updateMax(ivt.sentinel)
+ }
+ z.c = red
+
+ ivt.insertFixup(z)
+ ivt.count++
+}
+
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p316
+//
+// 0. RB-INSERT-FIXUP(T, z)
+// 1.
+// 2. while z.p.color == RED
+// 3. if z.p == z.p.p.left
+// 4. y = z.p.p.right
+// 5. if y.color == RED
+// 6. z.p.color = BLACK
+// 7. y.color = BLACK
+// 8. z.p.p.color = RED
+// 9. z = z.p.p
+// 10. else if z == z.p.right
+// 11. z = z.p
+// 12. LEFT-ROTATE(T, z)
+// 13. z.p.color = BLACK
+// 14. z.p.p.color = RED
+// 15. RIGHT-ROTATE(T, z.p.p)
+// 16. else
+// 17. y = z.p.p.left
+// 18. if y.color == RED
+// 19. z.p.color = BLACK
+// 20. y.color = BLACK
+// 21. z.p.p.color = RED
+// 22. z = z.p.p
+// 23. else if z == z.p.right
+// 24. z = z.p
+// 25. RIGHT-ROTATE(T, z)
+// 26. z.p.color = BLACK
+// 27. z.p.p.color = RED
+// 28. LEFT-ROTATE(T, z.p.p)
+// 29.
+// 30. T.root.color = BLACK
+//
+func (ivt *intervalTree) insertFixup(z *intervalNode) {
+ for z.parent.color(ivt.sentinel) == red {
+ if z.parent == z.parent.parent.left { // line 3-15
+
+ y := z.parent.parent.right
+ if y.color(ivt.sentinel) == red {
+ y.c = black
+ z.parent.c = black
+ z.parent.parent.c = red
+ z = z.parent.parent
+ } else {
+ if z == z.parent.right {
+ z = z.parent
+ ivt.rotateLeft(z)
+ }
+ z.parent.c = black
+ z.parent.parent.c = red
+ ivt.rotateRight(z.parent.parent)
+ }
+ } else { // line 16-28
+ // same as then with left/right exchanged
+ y := z.parent.parent.left
+ if y.color(ivt.sentinel) == red {
+ y.c = black
+ z.parent.c = black
+ z.parent.parent.c = red
+ z = z.parent.parent
+ } else {
+ if z == z.parent.left {
+ z = z.parent
+ ivt.rotateRight(z)
+ }
+ z.parent.c = black
+ z.parent.parent.c = red
+ ivt.rotateLeft(z.parent.parent)
+ }
+ }
+ }
+
+ // line 30
+ ivt.root.c = black
+}
+
+// rotateLeft moves x so it is left of its right child
+//
+// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.2, p313
+//
+// 0. LEFT-ROTATE(T, x)
+// 1.
+// 2. y = x.right
+// 3. x.right = y.left
+// 4.
+// 5. if y.left ≠ T.nil
+// 6. y.left.p = x
+// 7.
+// 8. y.p = x.p
+// 9.
+// 10. if x.p == T.nil
+// 11. T.root = y
+// 12. else if x == x.p.left
+// 13. x.p.left = y
+// 14. else
+// 15. x.p.right = y
+// 16.
+// 17. y.left = x
+// 18. x.p = y
+//
+func (ivt *intervalTree) rotateLeft(x *intervalNode) {
+ // rotateLeft x must have right child
+ if x.right == ivt.sentinel {
+ return
+ }
+
+ // line 2-3
+ y := x.right
+ x.right = y.left
+
+ // line 5-6
+ if y.left != ivt.sentinel {
+ y.left.parent = x
+ }
+ x.updateMax(ivt.sentinel)
+
+ // line 10-15, 18
+ ivt.replaceParent(x, y)
+
+ // line 17
+ y.left = x
+ y.updateMax(ivt.sentinel)
+}
+
+// rotateRight moves x so it is right of its left child
+//
+// 0. RIGHT-ROTATE(T, x)
+// 1.
+// 2. y = x.left
+// 3. x.left = y.right
+// 4.
+// 5. if y.right ≠ T.nil
+// 6. y.right.p = x
+// 7.
+// 8. y.p = x.p
+// 9.
+// 10. if x.p == T.nil
+// 11. T.root = y
+// 12. else if x == x.p.right
+// 13. x.p.right = y
+// 14. else
+// 15. x.p.left = y
+// 16.
+// 17. y.right = x
+// 18. x.p = y
+//
+func (ivt *intervalTree) rotateRight(x *intervalNode) {
+ // rotateRight x must have left child
+ if x.left == ivt.sentinel {
+ return
+ }
+
+ // line 2-3
+ y := x.left
+ x.left = y.right
+
+ // line 5-6
+ if y.right != ivt.sentinel {
+ y.right.parent = x
+ }
+ x.updateMax(ivt.sentinel)
+
+ // line 10-15, 18
+ ivt.replaceParent(x, y)
+
+ // line 17
+ y.right = x
+ y.updateMax(ivt.sentinel)
+}
+
+// replaceParent replaces x's parent with y
+func (ivt *intervalTree) replaceParent(x *intervalNode, y *intervalNode) {
+ y.parent = x.parent
+ if x.parent == ivt.sentinel {
+ ivt.root = y
+ } else {
+ if x == x.parent.left {
+ x.parent.left = y
+ } else {
+ x.parent.right = y
+ }
+ x.parent.updateMax(ivt.sentinel)
+ }
+ x.parent = y
+}
+
+// Len gives the number of elements in the tree
+func (ivt *intervalTree) Len() int { return ivt.count }
+
+// Height is the number of levels in the tree; one node has height 1.
+func (ivt *intervalTree) Height() int { return ivt.root.height(ivt.sentinel) }
+
+// MaxHeight is the expected maximum tree height given the number of nodes
+func (ivt *intervalTree) MaxHeight() int {
+ return int((2 * math.Log2(float64(ivt.Len()+1))) + 0.5)
+}
+
+// IntervalVisitor is used on tree searches; return false to stop searching.
+type IntervalVisitor func(n *IntervalValue) bool
+
+// Visit calls a visitor function on every tree node intersecting the given interval.
+// It will visit each interval [x, y) in ascending order sorted on x.
+func (ivt *intervalTree) Visit(ivl Interval, ivv IntervalVisitor) {
+ ivt.root.visit(&ivl, ivt.sentinel, func(n *intervalNode) bool { return ivv(&n.iv) })
+}
+
+// find the exact node for a given interval
+func (ivt *intervalTree) find(ivl Interval) *intervalNode {
+ ret := ivt.sentinel
+ f := func(n *intervalNode) bool {
+ if n.iv.Ivl != ivl {
+ return true
+ }
+ ret = n
+ return false
+ }
+ ivt.root.visit(&ivl, ivt.sentinel, f)
+ return ret
+}
+
+// Find gets the IntervalValue for the node matching the given interval
+func (ivt *intervalTree) Find(ivl Interval) (ret *IntervalValue) {
+ n := ivt.find(ivl)
+ if n == ivt.sentinel {
+ return nil
+ }
+ return &n.iv
+}
+
+// Intersects returns true if there is some tree node intersecting the given interval.
+func (ivt *intervalTree) Intersects(iv Interval) bool {
+ x := ivt.root
+ for x != ivt.sentinel && iv.Compare(&x.iv.Ivl) != 0 {
+ if x.left != ivt.sentinel && x.left.max.Compare(iv.Begin) > 0 {
+ x = x.left
+ } else {
+ x = x.right
+ }
+ }
+ return x != ivt.sentinel
+}
+
+// Contains returns true if the interval tree's keys cover the entire given interval.
+func (ivt *intervalTree) Contains(ivl Interval) bool {
+ var maxEnd, minBegin Comparable
+
+ isContiguous := true
+ ivt.Visit(ivl, func(n *IntervalValue) bool {
+ if minBegin == nil {
+ minBegin = n.Ivl.Begin
+ maxEnd = n.Ivl.End
+ return true
+ }
+ if maxEnd.Compare(n.Ivl.Begin) < 0 {
+ isContiguous = false
+ return false
+ }
+ if n.Ivl.End.Compare(maxEnd) > 0 {
+ maxEnd = n.Ivl.End
+ }
+ return true
+ })
+
+ return isContiguous && minBegin != nil && maxEnd.Compare(ivl.End) >= 0 && minBegin.Compare(ivl.Begin) <= 0
+}
+
+// Stab returns a slice with all elements in the tree intersecting the interval.
+func (ivt *intervalTree) Stab(iv Interval) (ivs []*IntervalValue) {
+ if ivt.count == 0 {
+ return nil
+ }
+ f := func(n *IntervalValue) bool { ivs = append(ivs, n); return true }
+ ivt.Visit(iv, f)
+ return ivs
+}
+
+// Union merges a given interval tree into the receiver.
+func (ivt *intervalTree) Union(inIvt IntervalTree, ivl Interval) {
+ f := func(n *IntervalValue) bool {
+ ivt.Insert(n.Ivl, n.Val)
+ return true
+ }
+ inIvt.Visit(ivl, f)
+}
+
+type visitedInterval struct {
+ root Interval
+ left Interval
+ right Interval
+ color rbcolor
+ depth int
+}
+
+func (vi visitedInterval) String() string {
+ bd := new(strings.Builder)
+ bd.WriteString(fmt.Sprintf("root [%v,%v,%v], left [%v,%v], right [%v,%v], depth %d",
+ vi.root.Begin, vi.root.End, vi.color,
+ vi.left.Begin, vi.left.End,
+ vi.right.Begin, vi.right.End,
+ vi.depth,
+ ))
+ return bd.String()
+}
+
+// visitLevel traverses tree in level order.
+// used for testing
+func (ivt *intervalTree) visitLevel() []visitedInterval {
+ if ivt.root == ivt.sentinel {
+ return nil
+ }
+
+ rs := make([]visitedInterval, 0, ivt.Len())
+
+ type pair struct {
+ node *intervalNode
+ depth int
+ }
+ queue := []pair{{ivt.root, 0}}
+ for len(queue) > 0 {
+ f := queue[0]
+ queue = queue[1:]
+
+ vi := visitedInterval{
+ root: f.node.iv.Ivl,
+ color: f.node.color(ivt.sentinel),
+ depth: f.depth,
+ }
+ if f.node.left != ivt.sentinel {
+ vi.left = f.node.left.iv.Ivl
+ queue = append(queue, pair{f.node.left, f.depth + 1})
+ }
+ if f.node.right != ivt.sentinel {
+ vi.right = f.node.right.iv.Ivl
+ queue = append(queue, pair{f.node.right, f.depth + 1})
+ }
+
+ rs = append(rs, vi)
+ }
+
+ return rs
+}
+
+type StringComparable string
+
+func (s StringComparable) Compare(c Comparable) int {
+ sc := c.(StringComparable)
+ if s < sc {
+ return -1
+ }
+ if s > sc {
+ return 1
+ }
+ return 0
+}
+
+func NewStringInterval(begin, end string) Interval {
+ return Interval{StringComparable(begin), StringComparable(end)}
+}
+
+func NewStringPoint(s string) Interval {
+ return Interval{StringComparable(s), StringComparable(s + "\x00")}
+}
+
+// StringAffineComparable treats "" as > all other strings
+type StringAffineComparable string
+
+func (s StringAffineComparable) Compare(c Comparable) int {
+ sc := c.(StringAffineComparable)
+
+ if len(s) == 0 {
+ if len(sc) == 0 {
+ return 0
+ }
+ return 1
+ }
+ if len(sc) == 0 {
+ return -1
+ }
+
+ if s < sc {
+ return -1
+ }
+ if s > sc {
+ return 1
+ }
+ return 0
+}
+
+func NewStringAffineInterval(begin, end string) Interval {
+ return Interval{StringAffineComparable(begin), StringAffineComparable(end)}
+}
+
+func NewStringAffinePoint(s string) Interval {
+ return NewStringAffineInterval(s, s+"\x00")
+}
+
+func NewInt64Interval(a int64, b int64) Interval {
+ return Interval{Int64Comparable(a), Int64Comparable(b)}
+}
+
+func newInt64EmptyInterval() Interval {
+ return Interval{Begin: nil, End: nil}
+}
+
+func NewInt64Point(a int64) Interval {
+ return Interval{Int64Comparable(a), Int64Comparable(a + 1)}
+}
+
+type Int64Comparable int64
+
+func (v Int64Comparable) Compare(c Comparable) int {
+ vc := c.(Int64Comparable)
+ cmp := v - vc
+ if cmp < 0 {
+ return -1
+ }
+ if cmp > 0 {
+ return 1
+ }
+ return 0
+}
+
+// BytesAffineComparable treats empty byte arrays as > all other byte arrays
+type BytesAffineComparable []byte
+
+func (b BytesAffineComparable) Compare(c Comparable) int {
+ bc := c.(BytesAffineComparable)
+
+ if len(b) == 0 {
+ if len(bc) == 0 {
+ return 0
+ }
+ return 1
+ }
+ if len(bc) == 0 {
+ return -1
+ }
+
+ return bytes.Compare(b, bc)
+}
+
+func NewBytesAffineInterval(begin, end []byte) Interval {
+ return Interval{BytesAffineComparable(begin), BytesAffineComparable(end)}
+}
+
+func NewBytesAffinePoint(b []byte) Interval {
+ be := make([]byte, len(b)+1)
+ copy(be, b)
+ be[len(b)] = 0
+ return NewBytesAffineInterval(b, be)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/contention/contention.go b/vendor/go.etcd.io/etcd/pkg/contention/contention.go
new file mode 100644
index 0000000..26ce9a2
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/contention/contention.go
@@ -0,0 +1,69 @@
+// 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 contention
+
+import (
+ "sync"
+ "time"
+)
+
+// TimeoutDetector detects routine starvations by
+// observing the actual time duration to finish an action
+// or between two events that should happen in a fixed
+// interval. If the observed duration is longer than
+// the expectation, the detector will report the result.
+type TimeoutDetector struct {
+ mu sync.Mutex // protects all
+ maxDuration time.Duration
+ // map from event to time
+ // time is the last seen time of the event.
+ records map[uint64]time.Time
+}
+
+// NewTimeoutDetector creates the TimeoutDetector.
+func NewTimeoutDetector(maxDuration time.Duration) *TimeoutDetector {
+ return &TimeoutDetector{
+ maxDuration: maxDuration,
+ records: make(map[uint64]time.Time),
+ }
+}
+
+// Reset resets the NewTimeoutDetector.
+func (td *TimeoutDetector) Reset() {
+ td.mu.Lock()
+ defer td.mu.Unlock()
+
+ td.records = make(map[uint64]time.Time)
+}
+
+// Observe observes an event for given id. It returns false and exceeded duration
+// if the interval is longer than the expectation.
+func (td *TimeoutDetector) Observe(which uint64) (bool, time.Duration) {
+ td.mu.Lock()
+ defer td.mu.Unlock()
+
+ ok := true
+ now := time.Now()
+ exceed := time.Duration(0)
+
+ if pt, found := td.records[which]; found {
+ exceed = now.Sub(pt) - td.maxDuration
+ if exceed > 0 {
+ ok = false
+ }
+ }
+ td.records[which] = now
+ return ok, exceed
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/contention/doc.go b/vendor/go.etcd.io/etcd/pkg/contention/doc.go
new file mode 100644
index 0000000..daf4522
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/contention/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 contention provides facilities for detecting system contention.
+package contention
diff --git a/vendor/go.etcd.io/etcd/pkg/cpuutil/doc.go b/vendor/go.etcd.io/etcd/pkg/cpuutil/doc.go
new file mode 100644
index 0000000..0323b2d
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/cpuutil/doc.go
@@ -0,0 +1,16 @@
+// Copyright 2017 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 cpuutil provides facilities for detecting cpu-specific features.
+package cpuutil
diff --git a/vendor/go.etcd.io/etcd/pkg/cpuutil/endian.go b/vendor/go.etcd.io/etcd/pkg/cpuutil/endian.go
new file mode 100644
index 0000000..06c06cd
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/cpuutil/endian.go
@@ -0,0 +1,36 @@
+// Copyright 2017 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 cpuutil
+
+import (
+ "encoding/binary"
+ "unsafe"
+)
+
+const intWidth int = int(unsafe.Sizeof(0))
+
+var byteOrder binary.ByteOrder
+
+// ByteOrder returns the byte order for the CPU's native endianness.
+func ByteOrder() binary.ByteOrder { return byteOrder }
+
+func init() {
+ i := int(0x1)
+ if v := (*[intWidth]byte)(unsafe.Pointer(&i)); v[0] == 0 {
+ byteOrder = binary.BigEndian
+ } else {
+ byteOrder = binary.LittleEndian
+ }
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/crc/crc.go b/vendor/go.etcd.io/etcd/pkg/crc/crc.go
new file mode 100644
index 0000000..4b998a4
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/crc/crc.go
@@ -0,0 +1,43 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crc provides utility function for cyclic redundancy check
+// algorithms.
+package crc
+
+import (
+ "hash"
+ "hash/crc32"
+)
+
+// The size of a CRC-32 checksum in bytes.
+const Size = 4
+
+type digest struct {
+ crc uint32
+ tab *crc32.Table
+}
+
+// New creates a new hash.Hash32 computing the CRC-32 checksum
+// using the polynomial represented by the Table.
+// Modified by xiangli to take a prevcrc.
+func New(prev uint32, tab *crc32.Table) hash.Hash32 { return &digest{prev, tab} }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) BlockSize() int { return 1 }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func (d *digest) Write(p []byte) (n int, err error) {
+ d.crc = crc32.Update(d.crc, d.tab, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return d.crc }
+
+func (d *digest) Sum(in []byte) []byte {
+ s := d.Sum32()
+ return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/debugutil/doc.go b/vendor/go.etcd.io/etcd/pkg/debugutil/doc.go
new file mode 100644
index 0000000..74499eb
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/debugutil/doc.go
@@ -0,0 +1,16 @@
+// Copyright 2017 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 debugutil includes utility functions for debugging.
+package debugutil
diff --git a/vendor/go.etcd.io/etcd/pkg/debugutil/pprof.go b/vendor/go.etcd.io/etcd/pkg/debugutil/pprof.go
new file mode 100644
index 0000000..8d5544a
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/debugutil/pprof.go
@@ -0,0 +1,47 @@
+// Copyright 2017 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 debugutil
+
+import (
+ "net/http"
+ "net/http/pprof"
+ "runtime"
+)
+
+const HTTPPrefixPProf = "/debug/pprof"
+
+// PProfHandlers returns a map of pprof handlers keyed by the HTTP path.
+func PProfHandlers() map[string]http.Handler {
+ // set only when there's no existing setting
+ if runtime.SetMutexProfileFraction(-1) == 0 {
+ // 1 out of 5 mutex events are reported, on average
+ runtime.SetMutexProfileFraction(5)
+ }
+
+ m := make(map[string]http.Handler)
+
+ m[HTTPPrefixPProf+"/"] = http.HandlerFunc(pprof.Index)
+ m[HTTPPrefixPProf+"/profile"] = http.HandlerFunc(pprof.Profile)
+ m[HTTPPrefixPProf+"/symbol"] = http.HandlerFunc(pprof.Symbol)
+ m[HTTPPrefixPProf+"/cmdline"] = http.HandlerFunc(pprof.Cmdline)
+ m[HTTPPrefixPProf+"/trace "] = http.HandlerFunc(pprof.Trace)
+ m[HTTPPrefixPProf+"/heap"] = pprof.Handler("heap")
+ m[HTTPPrefixPProf+"/goroutine"] = pprof.Handler("goroutine")
+ m[HTTPPrefixPProf+"/threadcreate"] = pprof.Handler("threadcreate")
+ m[HTTPPrefixPProf+"/block"] = pprof.Handler("block")
+ m[HTTPPrefixPProf+"/mutex"] = pprof.Handler("mutex")
+
+ return m
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/dir_unix.go b/vendor/go.etcd.io/etcd/pkg/fileutil/dir_unix.go
new file mode 100644
index 0000000..58a77df
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/dir_unix.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.
+
+// +build !windows
+
+package fileutil
+
+import "os"
+
+// OpenDir opens a directory for syncing.
+func OpenDir(path string) (*os.File, error) { return os.Open(path) }
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/dir_windows.go b/vendor/go.etcd.io/etcd/pkg/fileutil/dir_windows.go
new file mode 100644
index 0000000..c123395
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/dir_windows.go
@@ -0,0 +1,46 @@
+// 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.
+
+// +build windows
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+// OpenDir opens a directory in windows with write access for syncing.
+func OpenDir(path string) (*os.File, error) {
+ fd, err := openDir(path)
+ if err != nil {
+ return nil, err
+ }
+ return os.NewFile(uintptr(fd), path), nil
+}
+
+func openDir(path string) (fd syscall.Handle, err error) {
+ if len(path) == 0 {
+ return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
+ }
+ pathp, err := syscall.UTF16PtrFromString(path)
+ if err != nil {
+ return syscall.InvalidHandle, err
+ }
+ access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE)
+ sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
+ createmode := uint32(syscall.OPEN_EXISTING)
+ fl := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
+ return syscall.CreateFile(pathp, access, sharemode, nil, createmode, fl, 0)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/doc.go b/vendor/go.etcd.io/etcd/pkg/fileutil/doc.go
new file mode 100644
index 0000000..69dde5a
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/doc.go
@@ -0,0 +1,16 @@
+// 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 fileutil implements utility functions related to files and paths.
+package fileutil
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/fileutil.go b/vendor/go.etcd.io/etcd/pkg/fileutil/fileutil.go
new file mode 100644
index 0000000..5d9fb53
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/fileutil.go
@@ -0,0 +1,104 @@
+// 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 fileutil
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/coreos/pkg/capnslog"
+)
+
+const (
+ // PrivateFileMode grants owner to read/write a file.
+ PrivateFileMode = 0600
+ // PrivateDirMode grants owner to make/remove files inside the directory.
+ PrivateDirMode = 0700
+)
+
+var plog = capnslog.NewPackageLogger("go.etcd.io/etcd", "pkg/fileutil")
+
+// IsDirWriteable checks if dir is writable by writing and removing a file
+// to dir. It returns nil if dir is writable.
+func IsDirWriteable(dir string) error {
+ f := filepath.Join(dir, ".touch")
+ if err := ioutil.WriteFile(f, []byte(""), PrivateFileMode); err != nil {
+ return err
+ }
+ return os.Remove(f)
+}
+
+// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
+// does not exists. TouchDirAll also ensures the given directory is writable.
+func TouchDirAll(dir string) error {
+ // If path is already a directory, MkdirAll does nothing
+ // and returns nil.
+ err := os.MkdirAll(dir, PrivateDirMode)
+ if err != nil {
+ // if mkdirAll("a/text") and "text" is not
+ // a directory, this will return syscall.ENOTDIR
+ return err
+ }
+ return IsDirWriteable(dir)
+}
+
+// CreateDirAll is similar to TouchDirAll but returns error
+// if the deepest directory was not empty.
+func CreateDirAll(dir string) error {
+ err := TouchDirAll(dir)
+ if err == nil {
+ var ns []string
+ ns, err = ReadDir(dir)
+ if err != nil {
+ return err
+ }
+ if len(ns) != 0 {
+ err = fmt.Errorf("expected %q to be empty, got %q", dir, ns)
+ }
+ }
+ return err
+}
+
+// Exist returns true if a file or directory exists.
+func Exist(name string) bool {
+ _, err := os.Stat(name)
+ return err == nil
+}
+
+// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
+// shorten the length of the file.
+func ZeroToEnd(f *os.File) error {
+ // TODO: support FALLOC_FL_ZERO_RANGE
+ off, err := f.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return err
+ }
+ lenf, lerr := f.Seek(0, io.SeekEnd)
+ if lerr != nil {
+ return lerr
+ }
+ if err = f.Truncate(off); err != nil {
+ return err
+ }
+ // make sure blocks remain allocated
+ if err = Preallocate(f, lenf, true); err != nil {
+ return err
+ }
+ _, err = f.Seek(off, io.SeekStart)
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock.go
new file mode 100644
index 0000000..338627f
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock.go
@@ -0,0 +1,26 @@
+// 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 fileutil
+
+import (
+ "errors"
+ "os"
+)
+
+var (
+ ErrLocked = errors.New("fileutil: file already locked")
+)
+
+type LockedFile struct{ *os.File }
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_flock.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_flock.go
new file mode 100644
index 0000000..542550b
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_flock.go
@@ -0,0 +1,49 @@
+// 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.
+
+// +build !windows,!plan9,!solaris
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+func flockTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
+ f.Close()
+ if err == syscall.EWOULDBLOCK {
+ err = ErrLocked
+ }
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
+
+func flockLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
+ f.Close()
+ return nil, err
+ }
+ return &LockedFile{f}, err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_linux.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_linux.go
new file mode 100644
index 0000000..b0abc98
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_linux.go
@@ -0,0 +1,97 @@
+// 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.
+
+// +build linux
+
+package fileutil
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "syscall"
+)
+
+// This used to call syscall.Flock() but that call fails with EBADF on NFS.
+// An alternative is lockf() which works on NFS but that call lets a process lock
+// the same file twice. Instead, use Linux's non-standard open file descriptor
+// locks which will block if the process already holds the file lock.
+//
+// constants from /usr/include/bits/fcntl-linux.h
+const (
+ F_OFD_GETLK = 37
+ F_OFD_SETLK = 37
+ F_OFD_SETLKW = 38
+)
+
+var (
+ wrlck = syscall.Flock_t{
+ Type: syscall.F_WRLCK,
+ Whence: int16(io.SeekStart),
+ Start: 0,
+ Len: 0,
+ }
+
+ linuxTryLockFile = flockTryLockFile
+ linuxLockFile = flockLockFile
+)
+
+func init() {
+ // use open file descriptor locks if the system supports it
+ getlk := syscall.Flock_t{Type: syscall.F_RDLCK}
+ if err := syscall.FcntlFlock(0, F_OFD_GETLK, &getlk); err == nil {
+ linuxTryLockFile = ofdTryLockFile
+ linuxLockFile = ofdLockFile
+ }
+}
+
+func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ return linuxTryLockFile(path, flag, perm)
+}
+
+func ofdTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, fmt.Errorf("ofdTryLockFile failed to open %q (%v)", path, err)
+ }
+
+ flock := wrlck
+ if err = syscall.FcntlFlock(f.Fd(), F_OFD_SETLK, &flock); err != nil {
+ f.Close()
+ if err == syscall.EWOULDBLOCK {
+ err = ErrLocked
+ }
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
+
+func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ return linuxLockFile(path, flag, perm)
+}
+
+func ofdLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, fmt.Errorf("ofdLockFile failed to open %q (%v)", path, err)
+ }
+
+ flock := wrlck
+ err = syscall.FcntlFlock(f.Fd(), F_OFD_SETLKW, &flock)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_plan9.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_plan9.go
new file mode 100644
index 0000000..fee6a7c
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_plan9.go
@@ -0,0 +1,45 @@
+// 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 fileutil
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ if err := os.Chmod(path, syscall.DMEXCL|PrivateFileMode); err != nil {
+ return nil, err
+ }
+ f, err := os.Open(path, flag, perm)
+ if err != nil {
+ return nil, ErrLocked
+ }
+ return &LockedFile{f}, nil
+}
+
+func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ if err := os.Chmod(path, syscall.DMEXCL|PrivateFileMode); err != nil {
+ return nil, err
+ }
+ for {
+ f, err := os.OpenFile(path, flag, perm)
+ if err == nil {
+ return &LockedFile{f}, nil
+ }
+ time.Sleep(10 * time.Millisecond)
+ }
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_solaris.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_solaris.go
new file mode 100644
index 0000000..352ca55
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_solaris.go
@@ -0,0 +1,62 @@
+// 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.
+
+// +build solaris
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ var lock syscall.Flock_t
+ lock.Start = 0
+ lock.Len = 0
+ lock.Pid = 0
+ lock.Type = syscall.F_WRLCK
+ lock.Whence = 0
+ lock.Pid = 0
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &lock); err != nil {
+ f.Close()
+ if err == syscall.EAGAIN {
+ err = ErrLocked
+ }
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
+
+func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ var lock syscall.Flock_t
+ lock.Start = 0
+ lock.Len = 0
+ lock.Pid = 0
+ lock.Type = syscall.F_WRLCK
+ lock.Whence = 0
+ f, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err = syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, &lock); err != nil {
+ f.Close()
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_unix.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_unix.go
new file mode 100644
index 0000000..ed01164
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_unix.go
@@ -0,0 +1,29 @@
+// 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.
+
+// +build !windows,!plan9,!solaris,!linux
+
+package fileutil
+
+import (
+ "os"
+)
+
+func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ return flockTryLockFile(path, flag, perm)
+}
+
+func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ return flockLockFile(path, flag, perm)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/lock_windows.go b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_windows.go
new file mode 100644
index 0000000..b181723
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/lock_windows.go
@@ -0,0 +1,125 @@
+// 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.
+
+// +build windows
+
+package fileutil
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procLockFileEx = modkernel32.NewProc("LockFileEx")
+
+ errLocked = errors.New("The process cannot access the file because another process has locked a portion of the file.")
+)
+
+const (
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+ LOCKFILE_EXCLUSIVE_LOCK = 2
+ LOCKFILE_FAIL_IMMEDIATELY = 1
+
+ // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
+ errLockViolation syscall.Errno = 0x21
+)
+
+func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := open(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err := lockFile(syscall.Handle(f.Fd()), LOCKFILE_FAIL_IMMEDIATELY); err != nil {
+ f.Close()
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
+
+func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
+ f, err := open(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ if err := lockFile(syscall.Handle(f.Fd()), 0); err != nil {
+ f.Close()
+ return nil, err
+ }
+ return &LockedFile{f}, nil
+}
+
+func open(path string, flag int, perm os.FileMode) (*os.File, error) {
+ if path == "" {
+ return nil, fmt.Errorf("cannot open empty filename")
+ }
+ var access uint32
+ switch flag {
+ case syscall.O_RDONLY:
+ access = syscall.GENERIC_READ
+ case syscall.O_WRONLY:
+ access = syscall.GENERIC_WRITE
+ case syscall.O_RDWR:
+ access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
+ case syscall.O_WRONLY | syscall.O_CREAT:
+ access = syscall.GENERIC_ALL
+ default:
+ panic(fmt.Errorf("flag %v is not supported", flag))
+ }
+ fd, err := syscall.CreateFile(&(syscall.StringToUTF16(path)[0]),
+ access,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ nil,
+ syscall.OPEN_ALWAYS,
+ syscall.FILE_ATTRIBUTE_NORMAL,
+ 0)
+ if err != nil {
+ return nil, err
+ }
+ return os.NewFile(uintptr(fd), path), nil
+}
+
+func lockFile(fd syscall.Handle, flags uint32) error {
+ var flag uint32 = LOCKFILE_EXCLUSIVE_LOCK
+ flag |= flags
+ if fd == syscall.InvalidHandle {
+ return nil
+ }
+ err := lockFileEx(fd, flag, 1, 0, &syscall.Overlapped{})
+ if err == nil {
+ return nil
+ } else if err.Error() == errLocked.Error() {
+ return ErrLocked
+ } else if err != errLockViolation {
+ return err
+ }
+ return nil
+}
+
+func lockFileEx(h syscall.Handle, flags, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
+ var reserved uint32 = 0
+ r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate.go b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate.go
new file mode 100644
index 0000000..c747b7c
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate.go
@@ -0,0 +1,54 @@
+// 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 fileutil
+
+import (
+ "io"
+ "os"
+)
+
+// Preallocate tries to allocate the space for given
+// file. This operation is only supported on linux by a
+// few filesystems (btrfs, ext4, etc.).
+// If the operation is unsupported, no error will be returned.
+// Otherwise, the error encountered will be returned.
+func Preallocate(f *os.File, sizeInBytes int64, extendFile bool) error {
+ if sizeInBytes == 0 {
+ // fallocate will return EINVAL if length is 0; skip
+ return nil
+ }
+ if extendFile {
+ return preallocExtend(f, sizeInBytes)
+ }
+ return preallocFixed(f, sizeInBytes)
+}
+
+func preallocExtendTrunc(f *os.File, sizeInBytes int64) error {
+ curOff, err := f.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return err
+ }
+ size, err := f.Seek(sizeInBytes, io.SeekEnd)
+ if err != nil {
+ return err
+ }
+ if _, err = f.Seek(curOff, io.SeekStart); err != nil {
+ return err
+ }
+ if sizeInBytes > size {
+ return nil
+ }
+ return f.Truncate(sizeInBytes)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_darwin.go b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_darwin.go
new file mode 100644
index 0000000..5a6dccf
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_darwin.go
@@ -0,0 +1,65 @@
+// 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.
+
+// +build darwin
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func preallocExtend(f *os.File, sizeInBytes int64) error {
+ if err := preallocFixed(f, sizeInBytes); err != nil {
+ return err
+ }
+ return preallocExtendTrunc(f, sizeInBytes)
+}
+
+func preallocFixed(f *os.File, sizeInBytes int64) error {
+ // allocate all requested space or no space at all
+ // TODO: allocate contiguous space on disk with F_ALLOCATECONTIG flag
+ fstore := &syscall.Fstore_t{
+ Flags: syscall.F_ALLOCATEALL,
+ Posmode: syscall.F_PEOFPOSMODE,
+ Length: sizeInBytes}
+ p := unsafe.Pointer(fstore)
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(p))
+ if errno == 0 || errno == syscall.ENOTSUP {
+ return nil
+ }
+
+ // wrong argument to fallocate syscall
+ if errno == syscall.EINVAL {
+ // filesystem "st_blocks" are allocated in the units of
+ // "Allocation Block Size" (run "diskutil info /" command)
+ var stat syscall.Stat_t
+ syscall.Fstat(int(f.Fd()), &stat)
+
+ // syscall.Statfs_t.Bsize is "optimal transfer block size"
+ // and contains matching 4096 value when latest OS X kernel
+ // supports 4,096 KB filesystem block size
+ var statfs syscall.Statfs_t
+ syscall.Fstatfs(int(f.Fd()), &statfs)
+ blockSize := int64(statfs.Bsize)
+
+ if stat.Blocks*blockSize >= sizeInBytes {
+ // enough blocks are already allocated
+ return nil
+ }
+ }
+ return errno
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unix.go b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unix.go
new file mode 100644
index 0000000..50bd84f
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unix.go
@@ -0,0 +1,49 @@
+// 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.
+
+// +build linux
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+func preallocExtend(f *os.File, sizeInBytes int64) error {
+ // use mode = 0 to change size
+ err := syscall.Fallocate(int(f.Fd()), 0, 0, sizeInBytes)
+ if err != nil {
+ errno, ok := err.(syscall.Errno)
+ // not supported; fallback
+ // fallocate EINTRs frequently in some environments; fallback
+ if ok && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
+ return preallocExtendTrunc(f, sizeInBytes)
+ }
+ }
+ return err
+}
+
+func preallocFixed(f *os.File, sizeInBytes int64) error {
+ // use mode = 1 to keep size; see FALLOC_FL_KEEP_SIZE
+ err := syscall.Fallocate(int(f.Fd()), 1, 0, sizeInBytes)
+ if err != nil {
+ errno, ok := err.(syscall.Errno)
+ // treat not supported as nil error
+ if ok && errno == syscall.ENOTSUP {
+ return nil
+ }
+ }
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unsupported.go b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unsupported.go
new file mode 100644
index 0000000..162fbc5
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/preallocate_unsupported.go
@@ -0,0 +1,25 @@
+// 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.
+
+// +build !linux,!darwin
+
+package fileutil
+
+import "os"
+
+func preallocExtend(f *os.File, sizeInBytes int64) error {
+ return preallocExtendTrunc(f, sizeInBytes)
+}
+
+func preallocFixed(f *os.File, sizeInBytes int64) error { return nil }
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/purge.go b/vendor/go.etcd.io/etcd/pkg/fileutil/purge.go
new file mode 100644
index 0000000..fda96c3
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/purge.go
@@ -0,0 +1,88 @@
+// 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 fileutil
+
+import (
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+
+ "go.uber.org/zap"
+)
+
+func PurgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
+ return purgeFile(lg, dirname, suffix, max, interval, stop, nil)
+}
+
+// purgeFile is the internal implementation for PurgeFile which can post purged files to purgec if non-nil.
+func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}, purgec chan<- string) <-chan error {
+ errC := make(chan error, 1)
+ go func() {
+ for {
+ fnames, err := ReadDir(dirname)
+ if err != nil {
+ errC <- err
+ return
+ }
+ newfnames := make([]string, 0)
+ for _, fname := range fnames {
+ if strings.HasSuffix(fname, suffix) {
+ newfnames = append(newfnames, fname)
+ }
+ }
+ sort.Strings(newfnames)
+ fnames = newfnames
+ for len(newfnames) > int(max) {
+ f := filepath.Join(dirname, newfnames[0])
+ l, err := TryLockFile(f, os.O_WRONLY, PrivateFileMode)
+ if err != nil {
+ break
+ }
+ if err = os.Remove(f); err != nil {
+ errC <- err
+ return
+ }
+ if err = l.Close(); err != nil {
+ if lg != nil {
+ lg.Warn("failed to unlock/close", zap.String("path", l.Name()), zap.Error(err))
+ } else {
+ plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err)
+ }
+ errC <- err
+ return
+ }
+ if lg != nil {
+ lg.Info("purged", zap.String("path", f))
+ } else {
+ plog.Infof("purged file %s successfully", f)
+ }
+ newfnames = newfnames[1:]
+ }
+ if purgec != nil {
+ for i := 0; i < len(fnames)-len(newfnames); i++ {
+ purgec <- fnames[i]
+ }
+ }
+ select {
+ case <-time.After(interval):
+ case <-stop:
+ return
+ }
+ }
+ }()
+ return errC
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/read_dir.go b/vendor/go.etcd.io/etcd/pkg/fileutil/read_dir.go
new file mode 100644
index 0000000..2eeaa89
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/read_dir.go
@@ -0,0 +1,70 @@
+// 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 fileutil
+
+import (
+ "os"
+ "path/filepath"
+ "sort"
+)
+
+// ReadDirOp represents an read-directory operation.
+type ReadDirOp struct {
+ ext string
+}
+
+// ReadDirOption configures archiver operations.
+type ReadDirOption func(*ReadDirOp)
+
+// WithExt filters file names by their extensions.
+// (e.g. WithExt(".wal") to list only WAL files)
+func WithExt(ext string) ReadDirOption {
+ return func(op *ReadDirOp) { op.ext = ext }
+}
+
+func (op *ReadDirOp) applyOpts(opts []ReadDirOption) {
+ for _, opt := range opts {
+ opt(op)
+ }
+}
+
+// ReadDir returns the filenames in the given directory in sorted order.
+func ReadDir(d string, opts ...ReadDirOption) ([]string, error) {
+ op := &ReadDirOp{}
+ op.applyOpts(opts)
+
+ dir, err := os.Open(d)
+ if err != nil {
+ return nil, err
+ }
+ defer dir.Close()
+
+ names, err := dir.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ sort.Strings(names)
+
+ if op.ext != "" {
+ tss := make([]string, 0)
+ for _, v := range names {
+ if filepath.Ext(v) == op.ext {
+ tss = append(tss, v)
+ }
+ }
+ names = tss
+ }
+ return names, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/sync.go b/vendor/go.etcd.io/etcd/pkg/fileutil/sync.go
new file mode 100644
index 0000000..54dd41f
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/sync.go
@@ -0,0 +1,29 @@
+// 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.
+
+// +build !linux,!darwin
+
+package fileutil
+
+import "os"
+
+// Fsync is a wrapper around file.Sync(). Special handling is needed on darwin platform.
+func Fsync(f *os.File) error {
+ return f.Sync()
+}
+
+// Fdatasync is a wrapper around file.Sync(). Special handling is needed on linux platform.
+func Fdatasync(f *os.File) error {
+ return f.Sync()
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/sync_darwin.go b/vendor/go.etcd.io/etcd/pkg/fileutil/sync_darwin.go
new file mode 100644
index 0000000..c2f39bf
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/sync_darwin.go
@@ -0,0 +1,40 @@
+// 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.
+
+// +build darwin
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+// Fsync on HFS/OSX flushes the data on to the physical drive but the drive
+// may not write it to the persistent media for quite sometime and it may be
+// written in out-of-order sequence. Using F_FULLFSYNC ensures that the
+// physical drive's buffer will also get flushed to the media.
+func Fsync(f *os.File) error {
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_FULLFSYNC), uintptr(0))
+ if errno == 0 {
+ return nil
+ }
+ return errno
+}
+
+// Fdatasync on darwin platform invokes fcntl(F_FULLFSYNC) for actual persistence
+// on physical drive media.
+func Fdatasync(f *os.File) error {
+ return Fsync(f)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/fileutil/sync_linux.go b/vendor/go.etcd.io/etcd/pkg/fileutil/sync_linux.go
new file mode 100644
index 0000000..1bbced9
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/fileutil/sync_linux.go
@@ -0,0 +1,34 @@
+// 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.
+
+// +build linux
+
+package fileutil
+
+import (
+ "os"
+ "syscall"
+)
+
+// Fsync is a wrapper around file.Sync(). Special handling is needed on darwin platform.
+func Fsync(f *os.File) error {
+ return f.Sync()
+}
+
+// Fdatasync is similar to fsync(), but does not flush modified metadata
+// unless that metadata is needed in order to allow a subsequent data retrieval
+// to be correctly handled.
+func Fdatasync(f *os.File) error {
+ return syscall.Fdatasync(int(f.Fd()))
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/flag.go b/vendor/go.etcd.io/etcd/pkg/flags/flag.go
new file mode 100644
index 0000000..215902c
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/flag.go
@@ -0,0 +1,121 @@
+// 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 flags implements command-line flag parsing.
+package flags
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/coreos/pkg/capnslog"
+ "github.com/spf13/pflag"
+)
+
+var plog = capnslog.NewPackageLogger("go.etcd.io/etcd", "pkg/flags")
+
+// SetFlagsFromEnv parses all registered flags in the given flagset,
+// and if they are not already set it attempts to set their values from
+// environment variables. Environment variables take the name of the flag but
+// are UPPERCASE, have the given prefix and any dashes are replaced by
+// underscores - for example: some-flag => ETCD_SOME_FLAG
+func SetFlagsFromEnv(prefix string, fs *flag.FlagSet) error {
+ var err error
+ alreadySet := make(map[string]bool)
+ fs.Visit(func(f *flag.Flag) {
+ alreadySet[FlagToEnv(prefix, f.Name)] = true
+ })
+ usedEnvKey := make(map[string]bool)
+ fs.VisitAll(func(f *flag.Flag) {
+ if serr := setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, true); serr != nil {
+ err = serr
+ }
+ })
+ verifyEnv(prefix, usedEnvKey, alreadySet)
+ return err
+}
+
+// SetPflagsFromEnv is similar to SetFlagsFromEnv. However, the accepted flagset type is pflag.FlagSet
+// and it does not do any logging.
+func SetPflagsFromEnv(prefix string, fs *pflag.FlagSet) error {
+ var err error
+ alreadySet := make(map[string]bool)
+ usedEnvKey := make(map[string]bool)
+ fs.VisitAll(func(f *pflag.Flag) {
+ if f.Changed {
+ alreadySet[FlagToEnv(prefix, f.Name)] = true
+ }
+ if serr := setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, false); serr != nil {
+ err = serr
+ }
+ })
+ verifyEnv(prefix, usedEnvKey, alreadySet)
+ return err
+}
+
+// FlagToEnv converts flag string to upper-case environment variable key string.
+func FlagToEnv(prefix, name string) string {
+ return prefix + "_" + strings.ToUpper(strings.Replace(name, "-", "_", -1))
+}
+
+func verifyEnv(prefix string, usedEnvKey, alreadySet map[string]bool) {
+ for _, env := range os.Environ() {
+ kv := strings.SplitN(env, "=", 2)
+ if len(kv) != 2 {
+ plog.Warningf("found invalid env %s", env)
+ }
+ if usedEnvKey[kv[0]] {
+ continue
+ }
+ if alreadySet[kv[0]] {
+ plog.Fatalf("conflicting environment variable %q is shadowed by corresponding command-line flag (either unset environment variable or disable flag)", kv[0])
+ }
+ if strings.HasPrefix(env, prefix+"_") {
+ plog.Warningf("unrecognized environment variable %s", env)
+ }
+ }
+}
+
+type flagSetter interface {
+ Set(fk string, fv string) error
+}
+
+func setFlagFromEnv(fs flagSetter, prefix, fname string, usedEnvKey, alreadySet map[string]bool, log bool) error {
+ key := FlagToEnv(prefix, fname)
+ if !alreadySet[key] {
+ val := os.Getenv(key)
+ if val != "" {
+ usedEnvKey[key] = true
+ if serr := fs.Set(fname, val); serr != nil {
+ return fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
+ }
+ if log {
+ plog.Infof("recognized and used environment variable %s=%s", key, val)
+ }
+ }
+ }
+ return nil
+}
+
+func IsSet(fs *flag.FlagSet, name string) bool {
+ set := false
+ fs.Visit(func(f *flag.Flag) {
+ if f.Name == name {
+ set = true
+ }
+ })
+ return set
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/ignored.go b/vendor/go.etcd.io/etcd/pkg/flags/ignored.go
new file mode 100644
index 0000000..9953049
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/ignored.go
@@ -0,0 +1,36 @@
+// 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 flags
+
+// IgnoredFlag encapsulates a flag that may have been previously valid but is
+// now ignored. If an IgnoredFlag is set, a warning is printed and
+// operation continues.
+type IgnoredFlag struct {
+ Name string
+}
+
+// IsBoolFlag is defined to allow the flag to be defined without an argument
+func (f *IgnoredFlag) IsBoolFlag() bool {
+ return true
+}
+
+func (f *IgnoredFlag) Set(s string) error {
+ plog.Warningf(`flag "-%s" is no longer supported - ignoring.`, f.Name)
+ return nil
+}
+
+func (f *IgnoredFlag) String() string {
+ return ""
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/selective_string.go b/vendor/go.etcd.io/etcd/pkg/flags/selective_string.go
new file mode 100644
index 0000000..4b90fbf
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/selective_string.go
@@ -0,0 +1,114 @@
+// 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 flags
+
+import (
+ "errors"
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// SelectiveStringValue implements the flag.Value interface.
+type SelectiveStringValue struct {
+ v string
+ valids map[string]struct{}
+}
+
+// Set verifies the argument to be a valid member of the allowed values
+// before setting the underlying flag value.
+func (ss *SelectiveStringValue) Set(s string) error {
+ if _, ok := ss.valids[s]; ok {
+ ss.v = s
+ return nil
+ }
+ return errors.New("invalid value")
+}
+
+// String returns the set value (if any) of the SelectiveStringValue
+func (ss *SelectiveStringValue) String() string {
+ return ss.v
+}
+
+// Valids returns the list of valid strings.
+func (ss *SelectiveStringValue) Valids() []string {
+ s := make([]string, 0, len(ss.valids))
+ for k := range ss.valids {
+ s = append(s, k)
+ }
+ sort.Strings(s)
+ return s
+}
+
+// NewSelectiveStringValue creates a new string flag
+// for which any one of the given strings is a valid value,
+// and any other value is an error.
+//
+// valids[0] will be default value. Caller must be sure
+// len(valids) != 0 or it will panic.
+func NewSelectiveStringValue(valids ...string) *SelectiveStringValue {
+ vm := make(map[string]struct{})
+ for _, v := range valids {
+ vm[v] = struct{}{}
+ }
+ return &SelectiveStringValue{valids: vm, v: valids[0]}
+}
+
+// SelectiveStringsValue implements the flag.Value interface.
+type SelectiveStringsValue struct {
+ vs []string
+ valids map[string]struct{}
+}
+
+// Set verifies the argument to be a valid member of the allowed values
+// before setting the underlying flag value.
+func (ss *SelectiveStringsValue) Set(s string) error {
+ vs := strings.Split(s, ",")
+ for i := range vs {
+ if _, ok := ss.valids[vs[i]]; ok {
+ ss.vs = append(ss.vs, vs[i])
+ } else {
+ return fmt.Errorf("invalid value %q", vs[i])
+ }
+ }
+ sort.Strings(ss.vs)
+ return nil
+}
+
+// String returns the set value (if any) of the SelectiveStringsValue.
+func (ss *SelectiveStringsValue) String() string {
+ return strings.Join(ss.vs, ",")
+}
+
+// Valids returns the list of valid strings.
+func (ss *SelectiveStringsValue) Valids() []string {
+ s := make([]string, 0, len(ss.valids))
+ for k := range ss.valids {
+ s = append(s, k)
+ }
+ sort.Strings(s)
+ return s
+}
+
+// NewSelectiveStringsValue creates a new string slice flag
+// for which any one of the given strings is a valid value,
+// and any other value is an error.
+func NewSelectiveStringsValue(valids ...string) *SelectiveStringsValue {
+ vm := make(map[string]struct{})
+ for _, v := range valids {
+ vm[v] = struct{}{}
+ }
+ return &SelectiveStringsValue{valids: vm, vs: []string{}}
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/strings.go b/vendor/go.etcd.io/etcd/pkg/flags/strings.go
new file mode 100644
index 0000000..3e47fb3
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/strings.go
@@ -0,0 +1,52 @@
+// 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 flags
+
+import (
+ "flag"
+ "sort"
+ "strings"
+)
+
+// StringsValue wraps "sort.StringSlice".
+type StringsValue sort.StringSlice
+
+// Set parses a command line set of strings, separated by comma.
+// Implements "flag.Value" interface.
+func (ss *StringsValue) Set(s string) error {
+ *ss = strings.Split(s, ",")
+ return nil
+}
+
+// String implements "flag.Value" interface.
+func (ss *StringsValue) String() string { return strings.Join(*ss, ",") }
+
+// NewStringsValue implements string slice as "flag.Value" interface.
+// Given value is to be separated by comma.
+func NewStringsValue(s string) (ss *StringsValue) {
+ if s == "" {
+ return &StringsValue{}
+ }
+ ss = new(StringsValue)
+ if err := ss.Set(s); err != nil {
+ plog.Panicf("new StringsValue should never fail: %v", err)
+ }
+ return ss
+}
+
+// StringsFromFlag returns a string slice from the flag.
+func StringsFromFlag(fs *flag.FlagSet, flagName string) []string {
+ return []string(*fs.Lookup(flagName).Value.(*StringsValue))
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/unique_strings.go b/vendor/go.etcd.io/etcd/pkg/flags/unique_strings.go
new file mode 100644
index 0000000..e220ee0
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/unique_strings.go
@@ -0,0 +1,76 @@
+// 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 flags
+
+import (
+ "flag"
+ "sort"
+ "strings"
+)
+
+// UniqueStringsValue wraps a list of unique strings.
+// The values are set in order.
+type UniqueStringsValue struct {
+ Values map[string]struct{}
+}
+
+// Set parses a command line set of strings, separated by comma.
+// Implements "flag.Value" interface.
+// The values are set in order.
+func (us *UniqueStringsValue) Set(s string) error {
+ us.Values = make(map[string]struct{})
+ for _, v := range strings.Split(s, ",") {
+ us.Values[v] = struct{}{}
+ }
+ return nil
+}
+
+// String implements "flag.Value" interface.
+func (us *UniqueStringsValue) String() string {
+ return strings.Join(us.stringSlice(), ",")
+}
+
+func (us *UniqueStringsValue) stringSlice() []string {
+ ss := make([]string, 0, len(us.Values))
+ for v := range us.Values {
+ ss = append(ss, v)
+ }
+ sort.Strings(ss)
+ return ss
+}
+
+// NewUniqueStringsValue implements string slice as "flag.Value" interface.
+// Given value is to be separated by comma.
+// The values are set in order.
+func NewUniqueStringsValue(s string) (us *UniqueStringsValue) {
+ us = &UniqueStringsValue{Values: make(map[string]struct{})}
+ if s == "" {
+ return us
+ }
+ if err := us.Set(s); err != nil {
+ plog.Panicf("new UniqueStringsValue should never fail: %v", err)
+ }
+ return us
+}
+
+// UniqueStringsFromFlag returns a string slice from the flag.
+func UniqueStringsFromFlag(fs *flag.FlagSet, flagName string) []string {
+ return (*fs.Lookup(flagName).Value.(*UniqueStringsValue)).stringSlice()
+}
+
+// UniqueStringsMapFromFlag returns a map of strings from the flag.
+func UniqueStringsMapFromFlag(fs *flag.FlagSet, flagName string) map[string]struct{} {
+ return (*fs.Lookup(flagName).Value.(*UniqueStringsValue)).Values
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/unique_urls.go b/vendor/go.etcd.io/etcd/pkg/flags/unique_urls.go
new file mode 100644
index 0000000..9b4178c
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/unique_urls.go
@@ -0,0 +1,92 @@
+// 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 flags
+
+import (
+ "flag"
+ "net/url"
+ "sort"
+ "strings"
+
+ "go.etcd.io/etcd/pkg/types"
+)
+
+// UniqueURLs contains unique URLs
+// with non-URL exceptions.
+type UniqueURLs struct {
+ Values map[string]struct{}
+ uss []url.URL
+ Allowed map[string]struct{}
+}
+
+// Set parses a command line set of URLs formatted like:
+// http://127.0.0.1:2380,http://10.1.1.2:80
+// Implements "flag.Value" interface.
+func (us *UniqueURLs) Set(s string) error {
+ if _, ok := us.Values[s]; ok {
+ return nil
+ }
+ if _, ok := us.Allowed[s]; ok {
+ us.Values[s] = struct{}{}
+ return nil
+ }
+ ss, err := types.NewURLs(strings.Split(s, ","))
+ if err != nil {
+ return err
+ }
+ us.Values = make(map[string]struct{})
+ us.uss = make([]url.URL, 0)
+ for _, v := range ss {
+ us.Values[v.String()] = struct{}{}
+ us.uss = append(us.uss, v)
+ }
+ return nil
+}
+
+// String implements "flag.Value" interface.
+func (us *UniqueURLs) String() string {
+ all := make([]string, 0, len(us.Values))
+ for u := range us.Values {
+ all = append(all, u)
+ }
+ sort.Strings(all)
+ return strings.Join(all, ",")
+}
+
+// NewUniqueURLsWithExceptions implements "url.URL" slice as flag.Value interface.
+// Given value is to be separated by comma.
+func NewUniqueURLsWithExceptions(s string, exceptions ...string) *UniqueURLs {
+ us := &UniqueURLs{Values: make(map[string]struct{}), Allowed: make(map[string]struct{})}
+ for _, v := range exceptions {
+ us.Allowed[v] = struct{}{}
+ }
+ if s == "" {
+ return us
+ }
+ if err := us.Set(s); err != nil {
+ plog.Panicf("new UniqueURLs should never fail: %v", err)
+ }
+ return us
+}
+
+// UniqueURLsFromFlag returns a slice from urls got from the flag.
+func UniqueURLsFromFlag(fs *flag.FlagSet, urlsFlagName string) []url.URL {
+ return (*fs.Lookup(urlsFlagName).Value.(*UniqueURLs)).uss
+}
+
+// UniqueURLsMapFromFlag returns a map from url strings got from the flag.
+func UniqueURLsMapFromFlag(fs *flag.FlagSet, urlsFlagName string) map[string]struct{} {
+ return (*fs.Lookup(urlsFlagName).Value.(*UniqueURLs)).Values
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/flags/urls.go b/vendor/go.etcd.io/etcd/pkg/flags/urls.go
new file mode 100644
index 0000000..ca90970
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/flags/urls.go
@@ -0,0 +1,65 @@
+// 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 flags
+
+import (
+ "flag"
+ "net/url"
+ "strings"
+
+ "go.etcd.io/etcd/pkg/types"
+)
+
+// URLsValue wraps "types.URLs".
+type URLsValue types.URLs
+
+// Set parses a command line set of URLs formatted like:
+// http://127.0.0.1:2380,http://10.1.1.2:80
+// Implements "flag.Value" interface.
+func (us *URLsValue) Set(s string) error {
+ ss, err := types.NewURLs(strings.Split(s, ","))
+ if err != nil {
+ return err
+ }
+ *us = URLsValue(ss)
+ return nil
+}
+
+// String implements "flag.Value" interface.
+func (us *URLsValue) String() string {
+ all := make([]string, len(*us))
+ for i, u := range *us {
+ all[i] = u.String()
+ }
+ return strings.Join(all, ",")
+}
+
+// NewURLsValue implements "url.URL" slice as flag.Value interface.
+// Given value is to be separated by comma.
+func NewURLsValue(s string) *URLsValue {
+ if s == "" {
+ return &URLsValue{}
+ }
+ v := &URLsValue{}
+ if err := v.Set(s); err != nil {
+ plog.Panicf("new URLsValue should never fail: %v", err)
+ }
+ return v
+}
+
+// URLsFromFlag returns a slices from url got from the flag.
+func URLsFromFlag(fs *flag.FlagSet, urlsFlagName string) []url.URL {
+ return []url.URL(*fs.Lookup(urlsFlagName).Value.(*URLsValue))
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/httputil/httputil.go b/vendor/go.etcd.io/etcd/pkg/httputil/httputil.go
new file mode 100644
index 0000000..3bf58a3
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/httputil/httputil.go
@@ -0,0 +1,50 @@
+// 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.
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httputil provides HTTP utility functions.
+package httputil
+
+import (
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+)
+
+// GracefulClose drains http.Response.Body until it hits EOF
+// and closes it. This prevents TCP/TLS connections from closing,
+// therefore available for reuse.
+// Borrowed from golang/net/context/ctxhttp/cancelreq.go.
+func GracefulClose(resp *http.Response) {
+ io.Copy(ioutil.Discard, resp.Body)
+ resp.Body.Close()
+}
+
+// GetHostname returns the hostname from request Host field.
+// It returns empty string, if Host field contains invalid
+// value (e.g. "localhost:::" with too many colons).
+func GetHostname(req *http.Request) string {
+ if req == nil {
+ return ""
+ }
+ h, _, err := net.SplitHostPort(req.Host)
+ if err != nil {
+ return req.Host
+ }
+ return h
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/idutil/id.go b/vendor/go.etcd.io/etcd/pkg/idutil/id.go
new file mode 100644
index 0000000..63a02cd
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/idutil/id.go
@@ -0,0 +1,75 @@
+// 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 idutil implements utility functions for generating unique,
+// randomized ids.
+package idutil
+
+import (
+ "math"
+ "sync/atomic"
+ "time"
+)
+
+const (
+ tsLen = 5 * 8
+ cntLen = 8
+ suffixLen = tsLen + cntLen
+)
+
+// Generator generates unique identifiers based on counters, timestamps, and
+// a node member ID.
+//
+// The initial id is in this format:
+// High order 2 bytes are from memberID, next 5 bytes are from timestamp,
+// and low order one byte is a counter.
+// | prefix | suffix |
+// | 2 bytes | 5 bytes | 1 byte |
+// | memberID | timestamp | cnt |
+//
+// The timestamp 5 bytes is different when the machine is restart
+// after 1 ms and before 35 years.
+//
+// It increases suffix to generate the next id.
+// The count field may overflow to timestamp field, which is intentional.
+// It helps to extend the event window to 2^56. This doesn't break that
+// id generated after restart is unique because etcd throughput is <<
+// 256req/ms(250k reqs/second).
+type Generator struct {
+ // high order 2 bytes
+ prefix uint64
+ // low order 6 bytes
+ suffix uint64
+}
+
+func NewGenerator(memberID uint16, now time.Time) *Generator {
+ prefix := uint64(memberID) << suffixLen
+ unixMilli := uint64(now.UnixNano()) / uint64(time.Millisecond/time.Nanosecond)
+ suffix := lowbit(unixMilli, tsLen) << cntLen
+ return &Generator{
+ prefix: prefix,
+ suffix: suffix,
+ }
+}
+
+// Next generates a id that is unique.
+func (g *Generator) Next() uint64 {
+ suffix := atomic.AddUint64(&g.suffix, 1)
+ id := g.prefix | lowbit(suffix, suffixLen)
+ return id
+}
+
+func lowbit(x uint64, n uint) uint64 {
+ return x & (math.MaxUint64 >> (64 - n))
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/ioutil/pagewriter.go b/vendor/go.etcd.io/etcd/pkg/ioutil/pagewriter.go
new file mode 100644
index 0000000..72de159
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/ioutil/pagewriter.go
@@ -0,0 +1,106 @@
+// 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 ioutil
+
+import (
+ "io"
+)
+
+var defaultBufferBytes = 128 * 1024
+
+// PageWriter implements the io.Writer interface so that writes will
+// either be in page chunks or from flushing.
+type PageWriter struct {
+ w io.Writer
+ // pageOffset tracks the page offset of the base of the buffer
+ pageOffset int
+ // pageBytes is the number of bytes per page
+ pageBytes int
+ // bufferedBytes counts the number of bytes pending for write in the buffer
+ bufferedBytes int
+ // buf holds the write buffer
+ buf []byte
+ // bufWatermarkBytes is the number of bytes the buffer can hold before it needs
+ // to be flushed. It is less than len(buf) so there is space for slack writes
+ // to bring the writer to page alignment.
+ bufWatermarkBytes int
+}
+
+// NewPageWriter creates a new PageWriter. pageBytes is the number of bytes
+// to write per page. pageOffset is the starting offset of io.Writer.
+func NewPageWriter(w io.Writer, pageBytes, pageOffset int) *PageWriter {
+ return &PageWriter{
+ w: w,
+ pageOffset: pageOffset,
+ pageBytes: pageBytes,
+ buf: make([]byte, defaultBufferBytes+pageBytes),
+ bufWatermarkBytes: defaultBufferBytes,
+ }
+}
+
+func (pw *PageWriter) Write(p []byte) (n int, err error) {
+ if len(p)+pw.bufferedBytes <= pw.bufWatermarkBytes {
+ // no overflow
+ copy(pw.buf[pw.bufferedBytes:], p)
+ pw.bufferedBytes += len(p)
+ return len(p), nil
+ }
+ // complete the slack page in the buffer if unaligned
+ slack := pw.pageBytes - ((pw.pageOffset + pw.bufferedBytes) % pw.pageBytes)
+ if slack != pw.pageBytes {
+ partial := slack > len(p)
+ if partial {
+ // not enough data to complete the slack page
+ slack = len(p)
+ }
+ // special case: writing to slack page in buffer
+ copy(pw.buf[pw.bufferedBytes:], p[:slack])
+ pw.bufferedBytes += slack
+ n = slack
+ p = p[slack:]
+ if partial {
+ // avoid forcing an unaligned flush
+ return n, nil
+ }
+ }
+ // buffer contents are now page-aligned; clear out
+ if err = pw.Flush(); err != nil {
+ return n, err
+ }
+ // directly write all complete pages without copying
+ if len(p) > pw.pageBytes {
+ pages := len(p) / pw.pageBytes
+ c, werr := pw.w.Write(p[:pages*pw.pageBytes])
+ n += c
+ if werr != nil {
+ return n, werr
+ }
+ p = p[pages*pw.pageBytes:]
+ }
+ // write remaining tail to buffer
+ c, werr := pw.Write(p)
+ n += c
+ return n, werr
+}
+
+func (pw *PageWriter) Flush() error {
+ if pw.bufferedBytes == 0 {
+ return nil
+ }
+ _, err := pw.w.Write(pw.buf[:pw.bufferedBytes])
+ pw.pageOffset = (pw.pageOffset + pw.bufferedBytes) % pw.pageBytes
+ pw.bufferedBytes = 0
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/ioutil/readcloser.go b/vendor/go.etcd.io/etcd/pkg/ioutil/readcloser.go
new file mode 100644
index 0000000..d3efcfe
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/ioutil/readcloser.go
@@ -0,0 +1,66 @@
+// 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 ioutil
+
+import (
+ "fmt"
+ "io"
+)
+
+// ReaderAndCloser implements io.ReadCloser interface by combining
+// reader and closer together.
+type ReaderAndCloser struct {
+ io.Reader
+ io.Closer
+}
+
+var (
+ ErrShortRead = fmt.Errorf("ioutil: short read")
+ ErrExpectEOF = fmt.Errorf("ioutil: expect EOF")
+)
+
+// NewExactReadCloser returns a ReadCloser that returns errors if the underlying
+// reader does not read back exactly the requested number of bytes.
+func NewExactReadCloser(rc io.ReadCloser, totalBytes int64) io.ReadCloser {
+ return &exactReadCloser{rc: rc, totalBytes: totalBytes}
+}
+
+type exactReadCloser struct {
+ rc io.ReadCloser
+ br int64
+ totalBytes int64
+}
+
+func (e *exactReadCloser) Read(p []byte) (int, error) {
+ n, err := e.rc.Read(p)
+ e.br += int64(n)
+ if e.br > e.totalBytes {
+ return 0, ErrExpectEOF
+ }
+ if e.br < e.totalBytes && n == 0 {
+ return 0, ErrShortRead
+ }
+ return n, err
+}
+
+func (e *exactReadCloser) Close() error {
+ if err := e.rc.Close(); err != nil {
+ return err
+ }
+ if e.br < e.totalBytes {
+ return ErrShortRead
+ }
+ return nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/ioutil/reader.go b/vendor/go.etcd.io/etcd/pkg/ioutil/reader.go
new file mode 100644
index 0000000..0703ed4
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/ioutil/reader.go
@@ -0,0 +1,40 @@
+// 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 ioutil implements I/O utility functions.
+package ioutil
+
+import "io"
+
+// NewLimitedBufferReader returns a reader that reads from the given reader
+// but limits the amount of data returned to at most n bytes.
+func NewLimitedBufferReader(r io.Reader, n int) io.Reader {
+ return &limitedBufferReader{
+ r: r,
+ n: n,
+ }
+}
+
+type limitedBufferReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *limitedBufferReader) Read(p []byte) (n int, err error) {
+ np := p
+ if len(np) > r.n {
+ np = np[:r.n]
+ }
+ return r.r.Read(np)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/ioutil/util.go b/vendor/go.etcd.io/etcd/pkg/ioutil/util.go
new file mode 100644
index 0000000..6a6746e
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/ioutil/util.go
@@ -0,0 +1,43 @@
+// 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 ioutil
+
+import (
+ "io"
+ "os"
+
+ "go.etcd.io/etcd/pkg/fileutil"
+)
+
+// WriteAndSyncFile behaves just like ioutil.WriteFile in the standard library,
+// but calls Sync before closing the file. WriteAndSyncFile guarantees the data
+// is synced if there is no error returned.
+func WriteAndSyncFile(filename string, data []byte, perm os.FileMode) error {
+ f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ if err == nil {
+ err = fileutil.Fsync(f)
+ }
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/doc.go b/vendor/go.etcd.io/etcd/pkg/netutil/doc.go
new file mode 100644
index 0000000..5d92d03
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/doc.go
@@ -0,0 +1,16 @@
+// 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 netutil implements network-related utility functions.
+package netutil
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/isolate_linux.go b/vendor/go.etcd.io/etcd/pkg/netutil/isolate_linux.go
new file mode 100644
index 0000000..418580a
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/isolate_linux.go
@@ -0,0 +1,82 @@
+// 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 netutil
+
+import (
+ "fmt"
+ "os/exec"
+)
+
+// DropPort drops all tcp packets that are received from the given port and sent to the given port.
+func DropPort(port int) error {
+ cmdStr := fmt.Sprintf("sudo iptables -A OUTPUT -p tcp --destination-port %d -j DROP", port)
+ if _, err := exec.Command("/bin/sh", "-c", cmdStr).Output(); err != nil {
+ return err
+ }
+ cmdStr = fmt.Sprintf("sudo iptables -A INPUT -p tcp --destination-port %d -j DROP", port)
+ _, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
+ return err
+}
+
+// RecoverPort stops dropping tcp packets at given port.
+func RecoverPort(port int) error {
+ cmdStr := fmt.Sprintf("sudo iptables -D OUTPUT -p tcp --destination-port %d -j DROP", port)
+ if _, err := exec.Command("/bin/sh", "-c", cmdStr).Output(); err != nil {
+ return err
+ }
+ cmdStr = fmt.Sprintf("sudo iptables -D INPUT -p tcp --destination-port %d -j DROP", port)
+ _, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
+ return err
+}
+
+// SetLatency adds latency in millisecond scale with random variations.
+func SetLatency(ms, rv int) error {
+ ifces, err := GetDefaultInterfaces()
+ if err != nil {
+ return err
+ }
+
+ if rv > ms {
+ rv = 1
+ }
+ for ifce := range ifces {
+ cmdStr := fmt.Sprintf("sudo tc qdisc add dev %s root netem delay %dms %dms distribution normal", ifce, ms, rv)
+ _, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
+ if err != nil {
+ // the rule has already been added. Overwrite it.
+ cmdStr = fmt.Sprintf("sudo tc qdisc change dev %s root netem delay %dms %dms distribution normal", ifce, ms, rv)
+ _, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// RemoveLatency resets latency configurations.
+func RemoveLatency() error {
+ ifces, err := GetDefaultInterfaces()
+ if err != nil {
+ return err
+ }
+ for ifce := range ifces {
+ _, err = exec.Command("/bin/sh", "-c", fmt.Sprintf("sudo tc qdisc del dev %s root netem", ifce)).Output()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/isolate_stub.go b/vendor/go.etcd.io/etcd/pkg/netutil/isolate_stub.go
new file mode 100644
index 0000000..7f4c3e6
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/isolate_stub.go
@@ -0,0 +1,25 @@
+// 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.
+
+// +build !linux
+
+package netutil
+
+func DropPort(port int) error { return nil }
+
+func RecoverPort(port int) error { return nil }
+
+func SetLatency(ms, rv int) error { return nil }
+
+func RemoveLatency() error { return nil }
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/netutil.go b/vendor/go.etcd.io/etcd/pkg/netutil/netutil.go
new file mode 100644
index 0000000..faef646
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/netutil.go
@@ -0,0 +1,213 @@
+// 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 netutil
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "net/url"
+ "reflect"
+ "sort"
+ "time"
+
+ "go.etcd.io/etcd/pkg/types"
+
+ "go.uber.org/zap"
+)
+
+// indirection for testing
+var resolveTCPAddr = resolveTCPAddrDefault
+
+const retryInterval = time.Second
+
+// taken from go's ResolveTCP code but uses configurable ctx
+func resolveTCPAddrDefault(ctx context.Context, addr string) (*net.TCPAddr, error) {
+ host, port, serr := net.SplitHostPort(addr)
+ if serr != nil {
+ return nil, serr
+ }
+ portnum, perr := net.DefaultResolver.LookupPort(ctx, "tcp", port)
+ if perr != nil {
+ return nil, perr
+ }
+
+ var ips []net.IPAddr
+ if ip := net.ParseIP(host); ip != nil {
+ ips = []net.IPAddr{{IP: ip}}
+ } else {
+ // Try as a DNS name.
+ ipss, err := net.DefaultResolver.LookupIPAddr(ctx, host)
+ if err != nil {
+ return nil, err
+ }
+ ips = ipss
+ }
+ // randomize?
+ ip := ips[0]
+ return &net.TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}, nil
+}
+
+// resolveTCPAddrs is a convenience wrapper for net.ResolveTCPAddr.
+// resolveTCPAddrs return a new set of url.URLs, in which all DNS hostnames
+// are resolved.
+func resolveTCPAddrs(ctx context.Context, lg *zap.Logger, urls [][]url.URL) ([][]url.URL, error) {
+ newurls := make([][]url.URL, 0)
+ for _, us := range urls {
+ nus := make([]url.URL, len(us))
+ for i, u := range us {
+ nu, err := url.Parse(u.String())
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse %q (%v)", u.String(), err)
+ }
+ nus[i] = *nu
+ }
+ for i, u := range nus {
+ h, err := resolveURL(ctx, lg, u)
+ if err != nil {
+ return nil, fmt.Errorf("failed to resolve %q (%v)", u.String(), err)
+ }
+ if h != "" {
+ nus[i].Host = h
+ }
+ }
+ newurls = append(newurls, nus)
+ }
+ return newurls, nil
+}
+
+func resolveURL(ctx context.Context, lg *zap.Logger, u url.URL) (string, error) {
+ if u.Scheme == "unix" || u.Scheme == "unixs" {
+ // unix sockets don't resolve over TCP
+ return "", nil
+ }
+ host, _, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ lg.Warn(
+ "failed to parse URL Host while resolving URL",
+ zap.String("url", u.String()),
+ zap.String("host", u.Host),
+ zap.Error(err),
+ )
+ return "", err
+ }
+ if host == "localhost" || net.ParseIP(host) != nil {
+ return "", nil
+ }
+ for ctx.Err() == nil {
+ tcpAddr, err := resolveTCPAddr(ctx, u.Host)
+ if err == nil {
+ lg.Info(
+ "resolved URL Host",
+ zap.String("url", u.String()),
+ zap.String("host", u.Host),
+ zap.String("resolved-addr", tcpAddr.String()),
+ )
+ return tcpAddr.String(), nil
+ }
+
+ lg.Warn(
+ "failed to resolve URL Host",
+ zap.String("url", u.String()),
+ zap.String("host", u.Host),
+ zap.Duration("retry-interval", retryInterval),
+ zap.Error(err),
+ )
+
+ select {
+ case <-ctx.Done():
+ lg.Warn(
+ "failed to resolve URL Host; returning",
+ zap.String("url", u.String()),
+ zap.String("host", u.Host),
+ zap.Duration("retry-interval", retryInterval),
+ zap.Error(err),
+ )
+ return "", err
+ case <-time.After(retryInterval):
+ }
+ }
+ return "", ctx.Err()
+}
+
+// urlsEqual checks equality of url.URLS between two arrays.
+// This check pass even if an URL is in hostname and opposite is in IP address.
+func urlsEqual(ctx context.Context, lg *zap.Logger, a []url.URL, b []url.URL) (bool, error) {
+ if len(a) != len(b) {
+ return false, fmt.Errorf("len(%q) != len(%q)", urlsToStrings(a), urlsToStrings(b))
+ }
+ urls, err := resolveTCPAddrs(ctx, lg, [][]url.URL{a, b})
+ if err != nil {
+ return false, err
+ }
+ preva, prevb := a, b
+ a, b = urls[0], urls[1]
+ sort.Sort(types.URLs(a))
+ sort.Sort(types.URLs(b))
+ for i := range a {
+ if !reflect.DeepEqual(a[i], b[i]) {
+ return false, fmt.Errorf("%q(resolved from %q) != %q(resolved from %q)",
+ a[i].String(), preva[i].String(),
+ b[i].String(), prevb[i].String(),
+ )
+ }
+ }
+ return true, nil
+}
+
+// URLStringsEqual returns "true" if given URLs are valid
+// and resolved to same IP addresses. Otherwise, return "false"
+// and error, if any.
+func URLStringsEqual(ctx context.Context, lg *zap.Logger, a []string, b []string) (bool, error) {
+ if len(a) != len(b) {
+ return false, fmt.Errorf("len(%q) != len(%q)", a, b)
+ }
+ urlsA := make([]url.URL, 0)
+ for _, str := range a {
+ u, err := url.Parse(str)
+ if err != nil {
+ return false, fmt.Errorf("failed to parse %q", str)
+ }
+ urlsA = append(urlsA, *u)
+ }
+ urlsB := make([]url.URL, 0)
+ for _, str := range b {
+ u, err := url.Parse(str)
+ if err != nil {
+ return false, fmt.Errorf("failed to parse %q", str)
+ }
+ urlsB = append(urlsB, *u)
+ }
+ if lg == nil {
+ lg, _ = zap.NewProduction()
+ if lg == nil {
+ lg = zap.NewExample()
+ }
+ }
+ return urlsEqual(ctx, lg, urlsA, urlsB)
+}
+
+func urlsToStrings(us []url.URL) []string {
+ rs := make([]string, len(us))
+ for i := range us {
+ rs[i] = us[i].String()
+ }
+ return rs
+}
+
+func IsNetworkTimeoutError(err error) bool {
+ nerr, ok := err.(net.Error)
+ return ok && nerr.Timeout()
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/routes.go b/vendor/go.etcd.io/etcd/pkg/netutil/routes.go
new file mode 100644
index 0000000..3eb6a19
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/routes.go
@@ -0,0 +1,33 @@
+// 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.
+
+// +build !linux
+
+package netutil
+
+import (
+ "fmt"
+ "runtime"
+)
+
+// GetDefaultHost fetches the a resolvable name that corresponds
+// to the machine's default routable interface
+func GetDefaultHost() (string, error) {
+ return "", fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
+}
+
+// GetDefaultInterfaces fetches the device name of default routable interface.
+func GetDefaultInterfaces() (map[string]uint8, error) {
+ return nil, fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/netutil/routes_linux.go b/vendor/go.etcd.io/etcd/pkg/netutil/routes_linux.go
new file mode 100644
index 0000000..5118d3d
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/netutil/routes_linux.go
@@ -0,0 +1,250 @@
+// 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.
+
+// +build linux
+
+package netutil
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "net"
+ "sort"
+ "syscall"
+
+ "go.etcd.io/etcd/pkg/cpuutil"
+)
+
+var errNoDefaultRoute = fmt.Errorf("could not find default route")
+var errNoDefaultHost = fmt.Errorf("could not find default host")
+var errNoDefaultInterface = fmt.Errorf("could not find default interface")
+
+// GetDefaultHost obtains the first IP address of machine from the routing table and returns the IP address as string.
+// An IPv4 address is preferred to an IPv6 address for backward compatibility.
+func GetDefaultHost() (string, error) {
+ rmsgs, rerr := getDefaultRoutes()
+ if rerr != nil {
+ return "", rerr
+ }
+
+ // prioritize IPv4
+ if rmsg, ok := rmsgs[syscall.AF_INET]; ok {
+ if host, err := chooseHost(syscall.AF_INET, rmsg); host != "" || err != nil {
+ return host, err
+ }
+ delete(rmsgs, syscall.AF_INET)
+ }
+
+ // sort so choice is deterministic
+ var families []int
+ for family := range rmsgs {
+ families = append(families, int(family))
+ }
+ sort.Ints(families)
+
+ for _, f := range families {
+ family := uint8(f)
+ if host, err := chooseHost(family, rmsgs[family]); host != "" || err != nil {
+ return host, err
+ }
+ }
+
+ return "", errNoDefaultHost
+}
+
+func chooseHost(family uint8, rmsg *syscall.NetlinkMessage) (string, error) {
+ host, oif, err := parsePREFSRC(rmsg)
+ if host != "" || err != nil {
+ return host, err
+ }
+
+ // prefsrc not detected, fall back to getting address from iface
+ ifmsg, ierr := getIfaceAddr(oif, family)
+ if ierr != nil {
+ return "", ierr
+ }
+
+ attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
+ if aerr != nil {
+ return "", aerr
+ }
+
+ for _, attr := range attrs {
+ // search for RTA_DST because ipv6 doesn't have RTA_SRC
+ if attr.Attr.Type == syscall.RTA_DST {
+ return net.IP(attr.Value).String(), nil
+ }
+ }
+
+ return "", nil
+}
+
+func getDefaultRoutes() (map[uint8]*syscall.NetlinkMessage, error) {
+ dat, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, msgErr := syscall.ParseNetlinkMessage(dat)
+ if msgErr != nil {
+ return nil, msgErr
+ }
+
+ routes := make(map[uint8]*syscall.NetlinkMessage)
+ rtmsg := syscall.RtMsg{}
+ for _, m := range msgs {
+ if m.Header.Type != syscall.RTM_NEWROUTE {
+ continue
+ }
+ buf := bytes.NewBuffer(m.Data[:syscall.SizeofRtMsg])
+ if rerr := binary.Read(buf, cpuutil.ByteOrder(), &rtmsg); rerr != nil {
+ continue
+ }
+ if rtmsg.Dst_len == 0 && rtmsg.Table == syscall.RT_TABLE_MAIN {
+ // zero-length Dst_len implies default route
+ msg := m
+ routes[rtmsg.Family] = &msg
+ }
+ }
+
+ if len(routes) > 0 {
+ return routes, nil
+ }
+
+ return nil, errNoDefaultRoute
+}
+
+// Used to get an address of interface.
+func getIfaceAddr(idx uint32, family uint8) (*syscall.NetlinkMessage, error) {
+ dat, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, int(family))
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, msgErr := syscall.ParseNetlinkMessage(dat)
+ if msgErr != nil {
+ return nil, msgErr
+ }
+
+ ifaddrmsg := syscall.IfAddrmsg{}
+ for _, m := range msgs {
+ if m.Header.Type != syscall.RTM_NEWADDR {
+ continue
+ }
+ buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfAddrmsg])
+ if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifaddrmsg); rerr != nil {
+ continue
+ }
+ if ifaddrmsg.Index == idx {
+ return &m, nil
+ }
+ }
+
+ return nil, fmt.Errorf("could not find address for interface index %v", idx)
+
+}
+
+// Used to get a name of interface.
+func getIfaceLink(idx uint32) (*syscall.NetlinkMessage, error) {
+ dat, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, msgErr := syscall.ParseNetlinkMessage(dat)
+ if msgErr != nil {
+ return nil, msgErr
+ }
+
+ ifinfomsg := syscall.IfInfomsg{}
+ for _, m := range msgs {
+ if m.Header.Type != syscall.RTM_NEWLINK {
+ continue
+ }
+ buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfInfomsg])
+ if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifinfomsg); rerr != nil {
+ continue
+ }
+ if ifinfomsg.Index == int32(idx) {
+ return &m, nil
+ }
+ }
+
+ return nil, fmt.Errorf("could not find link for interface index %v", idx)
+}
+
+// GetDefaultInterfaces gets names of interfaces and returns a map[interface]families.
+func GetDefaultInterfaces() (map[string]uint8, error) {
+ interfaces := make(map[string]uint8)
+ rmsgs, rerr := getDefaultRoutes()
+ if rerr != nil {
+ return interfaces, rerr
+ }
+
+ for family, rmsg := range rmsgs {
+ _, oif, err := parsePREFSRC(rmsg)
+ if err != nil {
+ return interfaces, err
+ }
+
+ ifmsg, ierr := getIfaceLink(oif)
+ if ierr != nil {
+ return interfaces, ierr
+ }
+
+ attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
+ if aerr != nil {
+ return interfaces, aerr
+ }
+
+ for _, attr := range attrs {
+ if attr.Attr.Type == syscall.IFLA_IFNAME {
+ // key is an interface name
+ // possible values: 2 - AF_INET, 10 - AF_INET6, 12 - dualstack
+ interfaces[string(attr.Value[:len(attr.Value)-1])] += family
+ }
+ }
+ }
+ if len(interfaces) > 0 {
+ return interfaces, nil
+ }
+ return interfaces, errNoDefaultInterface
+}
+
+// parsePREFSRC returns preferred source address and output interface index (RTA_OIF).
+func parsePREFSRC(m *syscall.NetlinkMessage) (host string, oif uint32, err error) {
+ var attrs []syscall.NetlinkRouteAttr
+ attrs, err = syscall.ParseNetlinkRouteAttr(m)
+ if err != nil {
+ return "", 0, err
+ }
+
+ for _, attr := range attrs {
+ if attr.Attr.Type == syscall.RTA_PREFSRC {
+ host = net.IP(attr.Value).String()
+ }
+ if attr.Attr.Type == syscall.RTA_OIF {
+ oif = cpuutil.ByteOrder().Uint32(attr.Value)
+ }
+ if host != "" && oif != uint32(0) {
+ break
+ }
+ }
+
+ if oif == 0 {
+ err = errNoDefaultRoute
+ }
+ return host, oif, err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/pathutil/path.go b/vendor/go.etcd.io/etcd/pkg/pathutil/path.go
new file mode 100644
index 0000000..f26254b
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/pathutil/path.go
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pathutil implements utility functions for handling slash-separated
+// paths.
+package pathutil
+
+import "path"
+
+// CanonicalURLPath returns the canonical url path for p, which follows the rules:
+// 1. the path always starts with "/"
+// 2. replace multiple slashes with a single slash
+// 3. replace each '.' '..' path name element with equivalent one
+// 4. keep the trailing slash
+// The function is borrowed from stdlib http.cleanPath in server.go.
+func CanonicalURLPath(p string) string {
+ if p == "" {
+ return "/"
+ }
+ if p[0] != '/' {
+ p = "/" + p
+ }
+ np := path.Clean(p)
+ // path.Clean removes trailing slash except for root,
+ // put the trailing slash back if necessary.
+ if p[len(p)-1] == '/' && np != "/" {
+ np += "/"
+ }
+ return np
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/pbutil/pbutil.go b/vendor/go.etcd.io/etcd/pkg/pbutil/pbutil.go
new file mode 100644
index 0000000..53167ff
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/pbutil/pbutil.go
@@ -0,0 +1,60 @@
+// 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 pbutil defines interfaces for handling Protocol Buffer objects.
+package pbutil
+
+import "github.com/coreos/pkg/capnslog"
+
+var (
+ plog = capnslog.NewPackageLogger("go.etcd.io/etcd", "pkg/pbutil")
+)
+
+type Marshaler interface {
+ Marshal() (data []byte, err error)
+}
+
+type Unmarshaler interface {
+ Unmarshal(data []byte) error
+}
+
+func MustMarshal(m Marshaler) []byte {
+ d, err := m.Marshal()
+ if err != nil {
+ plog.Panicf("marshal should never fail (%v)", err)
+ }
+ return d
+}
+
+func MustUnmarshal(um Unmarshaler, data []byte) {
+ if err := um.Unmarshal(data); err != nil {
+ plog.Panicf("unmarshal should never fail (%v)", err)
+ }
+}
+
+func MaybeUnmarshal(um Unmarshaler, data []byte) bool {
+ if err := um.Unmarshal(data); err != nil {
+ return false
+ }
+ return true
+}
+
+func GetBool(v *bool) (vv bool, set bool) {
+ if v == nil {
+ return false, false
+ }
+ return *v, true
+}
+
+func Boolp(b bool) *bool { return &b }
diff --git a/vendor/go.etcd.io/etcd/pkg/runtime/fds_linux.go b/vendor/go.etcd.io/etcd/pkg/runtime/fds_linux.go
new file mode 100644
index 0000000..8e9359d
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/runtime/fds_linux.go
@@ -0,0 +1,37 @@
+// 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 runtime implements utility functions for runtime systems.
+package runtime
+
+import (
+ "io/ioutil"
+ "syscall"
+)
+
+func FDLimit() (uint64, error) {
+ var rlimit syscall.Rlimit
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
+ return 0, err
+ }
+ return rlimit.Cur, nil
+}
+
+func FDUsage() (uint64, error) {
+ fds, err := ioutil.ReadDir("/proc/self/fd")
+ if err != nil {
+ return 0, err
+ }
+ return uint64(len(fds)), nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/runtime/fds_other.go b/vendor/go.etcd.io/etcd/pkg/runtime/fds_other.go
new file mode 100644
index 0000000..0cbdb88
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/runtime/fds_other.go
@@ -0,0 +1,30 @@
+// 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.
+
+// +build !linux
+
+package runtime
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func FDLimit() (uint64, error) {
+ return 0, fmt.Errorf("cannot get FDLimit on %s", runtime.GOOS)
+}
+
+func FDUsage() (uint64, error) {
+ return 0, fmt.Errorf("cannot get FDUsage on %s", runtime.GOOS)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/schedule/doc.go b/vendor/go.etcd.io/etcd/pkg/schedule/doc.go
new file mode 100644
index 0000000..cca2c75
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/schedule/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 schedule provides mechanisms and policies for scheduling units of work.
+package schedule
diff --git a/vendor/go.etcd.io/etcd/pkg/schedule/schedule.go b/vendor/go.etcd.io/etcd/pkg/schedule/schedule.go
new file mode 100644
index 0000000..234d019
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/schedule/schedule.go
@@ -0,0 +1,165 @@
+// 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 schedule
+
+import (
+ "context"
+ "sync"
+)
+
+type Job func(context.Context)
+
+// Scheduler can schedule jobs.
+type Scheduler interface {
+ // Schedule asks the scheduler to schedule a job defined by the given func.
+ // Schedule to a stopped scheduler might panic.
+ Schedule(j Job)
+
+ // Pending returns number of pending jobs
+ Pending() int
+
+ // Scheduled returns the number of scheduled jobs (excluding pending jobs)
+ Scheduled() int
+
+ // Finished returns the number of finished jobs
+ Finished() int
+
+ // WaitFinish waits until at least n job are finished and all pending jobs are finished.
+ WaitFinish(n int)
+
+ // Stop stops the scheduler.
+ Stop()
+}
+
+type fifo struct {
+ mu sync.Mutex
+
+ resume chan struct{}
+ scheduled int
+ finished int
+ pendings []Job
+
+ ctx context.Context
+ cancel context.CancelFunc
+
+ finishCond *sync.Cond
+ donec chan struct{}
+}
+
+// NewFIFOScheduler returns a Scheduler that schedules jobs in FIFO
+// order sequentially
+func NewFIFOScheduler() Scheduler {
+ f := &fifo{
+ resume: make(chan struct{}, 1),
+ donec: make(chan struct{}, 1),
+ }
+ f.finishCond = sync.NewCond(&f.mu)
+ f.ctx, f.cancel = context.WithCancel(context.Background())
+ go f.run()
+ return f
+}
+
+// Schedule schedules a job that will be ran in FIFO order sequentially.
+func (f *fifo) Schedule(j Job) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ if f.cancel == nil {
+ panic("schedule: schedule to stopped scheduler")
+ }
+
+ if len(f.pendings) == 0 {
+ select {
+ case f.resume <- struct{}{}:
+ default:
+ }
+ }
+ f.pendings = append(f.pendings, j)
+}
+
+func (f *fifo) Pending() int {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return len(f.pendings)
+}
+
+func (f *fifo) Scheduled() int {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return f.scheduled
+}
+
+func (f *fifo) Finished() int {
+ f.finishCond.L.Lock()
+ defer f.finishCond.L.Unlock()
+ return f.finished
+}
+
+func (f *fifo) WaitFinish(n int) {
+ f.finishCond.L.Lock()
+ for f.finished < n || len(f.pendings) != 0 {
+ f.finishCond.Wait()
+ }
+ f.finishCond.L.Unlock()
+}
+
+// Stop stops the scheduler and cancels all pending jobs.
+func (f *fifo) Stop() {
+ f.mu.Lock()
+ f.cancel()
+ f.cancel = nil
+ f.mu.Unlock()
+ <-f.donec
+}
+
+func (f *fifo) run() {
+ // TODO: recover from job panic?
+ defer func() {
+ close(f.donec)
+ close(f.resume)
+ }()
+
+ for {
+ var todo Job
+ f.mu.Lock()
+ if len(f.pendings) != 0 {
+ f.scheduled++
+ todo = f.pendings[0]
+ }
+ f.mu.Unlock()
+ if todo == nil {
+ select {
+ case <-f.resume:
+ case <-f.ctx.Done():
+ f.mu.Lock()
+ pendings := f.pendings
+ f.pendings = nil
+ f.mu.Unlock()
+ // clean up pending jobs
+ for _, todo := range pendings {
+ todo(f.ctx)
+ }
+ return
+ }
+ } else {
+ todo(f.ctx)
+ f.finishCond.L.Lock()
+ f.finished++
+ f.pendings = f.pendings[1:]
+ f.finishCond.Broadcast()
+ f.finishCond.L.Unlock()
+ }
+ }
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/srv/srv.go b/vendor/go.etcd.io/etcd/pkg/srv/srv.go
new file mode 100644
index 0000000..c356002
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/srv/srv.go
@@ -0,0 +1,142 @@
+// 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 srv looks up DNS SRV records.
+package srv
+
+import (
+ "fmt"
+ "net"
+ "net/url"
+ "strings"
+
+ "go.etcd.io/etcd/pkg/types"
+)
+
+var (
+ // indirection for testing
+ lookupSRV = net.LookupSRV // net.DefaultResolver.LookupSRV when ctxs don't conflict
+ resolveTCPAddr = net.ResolveTCPAddr
+)
+
+// GetCluster gets the cluster information via DNS discovery.
+// Also sees each entry as a separate instance.
+func GetCluster(serviceScheme, service, name, dns string, apurls types.URLs) ([]string, error) {
+ tempName := int(0)
+ tcp2ap := make(map[string]url.URL)
+
+ // First, resolve the apurls
+ for _, url := range apurls {
+ tcpAddr, err := resolveTCPAddr("tcp", url.Host)
+ if err != nil {
+ return nil, err
+ }
+ tcp2ap[tcpAddr.String()] = url
+ }
+
+ stringParts := []string{}
+ updateNodeMap := func(service, scheme string) error {
+ _, addrs, err := lookupSRV(service, "tcp", dns)
+ if err != nil {
+ return err
+ }
+ for _, srv := range addrs {
+ port := fmt.Sprintf("%d", srv.Port)
+ host := net.JoinHostPort(srv.Target, port)
+ tcpAddr, terr := resolveTCPAddr("tcp", host)
+ if terr != nil {
+ err = terr
+ continue
+ }
+ n := ""
+ url, ok := tcp2ap[tcpAddr.String()]
+ if ok {
+ n = name
+ }
+ if n == "" {
+ n = fmt.Sprintf("%d", tempName)
+ tempName++
+ }
+ // SRV records have a trailing dot but URL shouldn't.
+ shortHost := strings.TrimSuffix(srv.Target, ".")
+ urlHost := net.JoinHostPort(shortHost, port)
+ if ok && url.Scheme != scheme {
+ err = fmt.Errorf("bootstrap at %s from DNS for %s has scheme mismatch with expected peer %s", scheme+"://"+urlHost, service, url.String())
+ } else {
+ stringParts = append(stringParts, fmt.Sprintf("%s=%s://%s", n, scheme, urlHost))
+ }
+ }
+ if len(stringParts) == 0 {
+ return err
+ }
+ return nil
+ }
+
+ err := updateNodeMap(service, serviceScheme)
+ if err != nil {
+ return nil, fmt.Errorf("error querying DNS SRV records for _%s %s", service, err)
+ }
+ return stringParts, nil
+}
+
+type SRVClients struct {
+ Endpoints []string
+ SRVs []*net.SRV
+}
+
+// GetClient looks up the client endpoints for a service and domain.
+func GetClient(service, domain string, serviceName string) (*SRVClients, error) {
+ var urls []*url.URL
+ var srvs []*net.SRV
+
+ updateURLs := func(service, scheme string) error {
+ _, addrs, err := lookupSRV(service, "tcp", domain)
+ if err != nil {
+ return err
+ }
+ for _, srv := range addrs {
+ urls = append(urls, &url.URL{
+ Scheme: scheme,
+ Host: net.JoinHostPort(srv.Target, fmt.Sprintf("%d", srv.Port)),
+ })
+ }
+ srvs = append(srvs, addrs...)
+ return nil
+ }
+
+ errHTTPS := updateURLs(GetSRVService(service, serviceName, "https"), "https")
+ errHTTP := updateURLs(GetSRVService(service, serviceName, "http"), "http")
+
+ if errHTTPS != nil && errHTTP != nil {
+ return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP)
+ }
+
+ endpoints := make([]string, len(urls))
+ for i := range urls {
+ endpoints[i] = urls[i].String()
+ }
+ return &SRVClients{Endpoints: endpoints, SRVs: srvs}, nil
+}
+
+// GetSRVService generates a SRV service including an optional suffix.
+func GetSRVService(service, serviceName string, scheme string) (SRVService string) {
+ if scheme == "https" {
+ service = fmt.Sprintf("%s-ssl", service)
+ }
+
+ if serviceName != "" {
+ return fmt.Sprintf("%s-%s", service, serviceName)
+ }
+ return service
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/tlsutil/cipher_suites.go b/vendor/go.etcd.io/etcd/pkg/tlsutil/cipher_suites.go
new file mode 100644
index 0000000..b5916bb
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/tlsutil/cipher_suites.go
@@ -0,0 +1,51 @@
+// 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 tlsutil
+
+import "crypto/tls"
+
+// cipher suites implemented by Go
+// https://github.com/golang/go/blob/dev.boringcrypto.go1.10/src/crypto/tls/cipher_suites.go
+var cipherSuites = map[string]uint16{
+ "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+ "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+ "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
+ "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+}
+
+// GetCipherSuite returns the corresponding cipher suite,
+// and boolean value if it is supported.
+func GetCipherSuite(s string) (uint16, bool) {
+ v, ok := cipherSuites[s]
+ return v, ok
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/tlsutil/doc.go b/vendor/go.etcd.io/etcd/pkg/tlsutil/doc.go
new file mode 100644
index 0000000..3b6aa67
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/tlsutil/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 tlsutil provides utility functions for handling TLS.
+package tlsutil
diff --git a/vendor/go.etcd.io/etcd/pkg/tlsutil/tlsutil.go b/vendor/go.etcd.io/etcd/pkg/tlsutil/tlsutil.go
new file mode 100644
index 0000000..3a5aef0
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/tlsutil/tlsutil.go
@@ -0,0 +1,73 @@
+// 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 tlsutil
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/pem"
+ "io/ioutil"
+)
+
+// NewCertPool creates x509 certPool with provided CA files.
+func NewCertPool(CAFiles []string) (*x509.CertPool, error) {
+ certPool := x509.NewCertPool()
+
+ for _, CAFile := range CAFiles {
+ pemByte, err := ioutil.ReadFile(CAFile)
+ if err != nil {
+ return nil, err
+ }
+
+ for {
+ var block *pem.Block
+ block, pemByte = pem.Decode(pemByte)
+ if block == nil {
+ break
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ certPool.AddCert(cert)
+ }
+ }
+
+ return certPool, nil
+}
+
+// NewCert generates TLS cert by using the given cert,key and parse function.
+func NewCert(certfile, keyfile string, parseFunc func([]byte, []byte) (tls.Certificate, error)) (*tls.Certificate, error) {
+ cert, err := ioutil.ReadFile(certfile)
+ if err != nil {
+ return nil, err
+ }
+
+ key, err := ioutil.ReadFile(keyfile)
+ if err != nil {
+ return nil, err
+ }
+
+ if parseFunc == nil {
+ parseFunc = tls.X509KeyPair
+ }
+
+ tlsCert, err := parseFunc(cert, key)
+ if err != nil {
+ return nil, err
+ }
+ return &tlsCert, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/doc.go b/vendor/go.etcd.io/etcd/pkg/transport/doc.go
new file mode 100644
index 0000000..37658ce
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/doc.go
@@ -0,0 +1,17 @@
+// 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 transport implements various HTTP transport utilities based on Go
+// net package.
+package transport
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/keepalive_listener.go b/vendor/go.etcd.io/etcd/pkg/transport/keepalive_listener.go
new file mode 100644
index 0000000..4ff8e7f
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/keepalive_listener.go
@@ -0,0 +1,94 @@
+// 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 transport
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net"
+ "time"
+)
+
+type keepAliveConn interface {
+ SetKeepAlive(bool) error
+ SetKeepAlivePeriod(d time.Duration) error
+}
+
+// NewKeepAliveListener returns a listener that listens on the given address.
+// Be careful when wrap around KeepAliveListener with another Listener if TLSInfo is not nil.
+// Some pkgs (like go/http) might expect Listener to return TLSConn type to start TLS handshake.
+// http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
+func NewKeepAliveListener(l net.Listener, scheme string, tlscfg *tls.Config) (net.Listener, error) {
+ if scheme == "https" {
+ if tlscfg == nil {
+ return nil, fmt.Errorf("cannot listen on TLS for given listener: KeyFile and CertFile are not presented")
+ }
+ return newTLSKeepaliveListener(l, tlscfg), nil
+ }
+
+ return &keepaliveListener{
+ Listener: l,
+ }, nil
+}
+
+type keepaliveListener struct{ net.Listener }
+
+func (kln *keepaliveListener) Accept() (net.Conn, error) {
+ c, err := kln.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ kac := c.(keepAliveConn)
+ // detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
+ // default on linux: 30 + 8 * 30
+ // default on osx: 30 + 8 * 75
+ kac.SetKeepAlive(true)
+ kac.SetKeepAlivePeriod(30 * time.Second)
+ return c, nil
+}
+
+// A tlsKeepaliveListener implements a network listener (net.Listener) for TLS connections.
+type tlsKeepaliveListener struct {
+ net.Listener
+ config *tls.Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
+func (l *tlsKeepaliveListener) Accept() (c net.Conn, err error) {
+ c, err = l.Listener.Accept()
+ if err != nil {
+ return
+ }
+ kac := c.(keepAliveConn)
+ // detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
+ // default on linux: 30 + 8 * 30
+ // default on osx: 30 + 8 * 75
+ kac.SetKeepAlive(true)
+ kac.SetKeepAlivePeriod(30 * time.Second)
+ c = tls.Server(c, l.config)
+ return c, nil
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func newTLSKeepaliveListener(inner net.Listener, config *tls.Config) net.Listener {
+ l := &tlsKeepaliveListener{}
+ l.Listener = inner
+ l.config = config
+ return l
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/limit_listen.go b/vendor/go.etcd.io/etcd/pkg/transport/limit_listen.go
new file mode 100644
index 0000000..930c542
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/limit_listen.go
@@ -0,0 +1,80 @@
+// Copyright 2013 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 transport provides network utility functions, complementing the more
+// common ones in the net package.
+package transport
+
+import (
+ "errors"
+ "net"
+ "sync"
+ "time"
+)
+
+var (
+ ErrNotTCP = errors.New("only tcp connections have keepalive")
+)
+
+// LimitListener returns a Listener that accepts at most n simultaneous
+// connections from the provided Listener.
+func LimitListener(l net.Listener, n int) net.Listener {
+ return &limitListener{l, make(chan struct{}, n)}
+}
+
+type limitListener struct {
+ net.Listener
+ sem chan struct{}
+}
+
+func (l *limitListener) acquire() { l.sem <- struct{}{} }
+func (l *limitListener) release() { <-l.sem }
+
+func (l *limitListener) Accept() (net.Conn, error) {
+ l.acquire()
+ c, err := l.Listener.Accept()
+ if err != nil {
+ l.release()
+ return nil, err
+ }
+ return &limitListenerConn{Conn: c, release: l.release}, nil
+}
+
+type limitListenerConn struct {
+ net.Conn
+ releaseOnce sync.Once
+ release func()
+}
+
+func (l *limitListenerConn) Close() error {
+ err := l.Conn.Close()
+ l.releaseOnce.Do(l.release)
+ return err
+}
+
+func (l *limitListenerConn) SetKeepAlive(doKeepAlive bool) error {
+ tcpc, ok := l.Conn.(*net.TCPConn)
+ if !ok {
+ return ErrNotTCP
+ }
+ return tcpc.SetKeepAlive(doKeepAlive)
+}
+
+func (l *limitListenerConn) SetKeepAlivePeriod(d time.Duration) error {
+ tcpc, ok := l.Conn.(*net.TCPConn)
+ if !ok {
+ return ErrNotTCP
+ }
+ return tcpc.SetKeepAlivePeriod(d)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/listener.go b/vendor/go.etcd.io/etcd/pkg/transport/listener.go
new file mode 100644
index 0000000..fa12911
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/listener.go
@@ -0,0 +1,451 @@
+// 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 transport
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "go.etcd.io/etcd/pkg/tlsutil"
+
+ "go.uber.org/zap"
+)
+
+// NewListener creates a new listner.
+func NewListener(addr, scheme string, tlsinfo *TLSInfo) (l net.Listener, err error) {
+ if l, err = newListener(addr, scheme); err != nil {
+ return nil, err
+ }
+ return wrapTLS(scheme, tlsinfo, l)
+}
+
+func newListener(addr string, scheme string) (net.Listener, error) {
+ if scheme == "unix" || scheme == "unixs" {
+ // unix sockets via unix://laddr
+ return NewUnixListener(addr)
+ }
+ return net.Listen("tcp", addr)
+}
+
+func wrapTLS(scheme string, tlsinfo *TLSInfo, l net.Listener) (net.Listener, error) {
+ if scheme != "https" && scheme != "unixs" {
+ return l, nil
+ }
+ if tlsinfo != nil && tlsinfo.SkipClientSANVerify {
+ return NewTLSListener(l, tlsinfo)
+ }
+ return newTLSListener(l, tlsinfo, checkSAN)
+}
+
+type TLSInfo struct {
+ CertFile string
+ KeyFile string
+ TrustedCAFile string
+ ClientCertAuth bool
+ CRLFile string
+ InsecureSkipVerify bool
+ SkipClientSANVerify bool
+
+ // ServerName ensures the cert matches the given host in case of discovery / virtual hosting
+ ServerName string
+
+ // HandshakeFailure is optionally called when a connection fails to handshake. The
+ // connection will be closed immediately afterwards.
+ HandshakeFailure func(*tls.Conn, error)
+
+ // CipherSuites is a list of supported cipher suites.
+ // If empty, Go auto-populates it by default.
+ // Note that cipher suites are prioritized in the given order.
+ CipherSuites []uint16
+
+ selfCert bool
+
+ // parseFunc exists to simplify testing. Typically, parseFunc
+ // should be left nil. In that case, tls.X509KeyPair will be used.
+ parseFunc func([]byte, []byte) (tls.Certificate, error)
+
+ // AllowedCN is a CN which must be provided by a client.
+ AllowedCN string
+
+ // AllowedHostname is an IP address or hostname that must match the TLS
+ // certificate provided by a client.
+ AllowedHostname string
+
+ // Logger logs TLS errors.
+ // If nil, all logs are discarded.
+ Logger *zap.Logger
+
+ // EmptyCN indicates that the cert must have empty CN.
+ // If true, ClientConfig() will return an error for a cert with non empty CN.
+ EmptyCN bool
+}
+
+func (info TLSInfo) String() string {
+ return fmt.Sprintf("cert = %s, key = %s, trusted-ca = %s, client-cert-auth = %v, crl-file = %s", info.CertFile, info.KeyFile, info.TrustedCAFile, info.ClientCertAuth, info.CRLFile)
+}
+
+func (info TLSInfo) Empty() bool {
+ return info.CertFile == "" && info.KeyFile == ""
+}
+
+func SelfCert(lg *zap.Logger, dirpath string, hosts []string, additionalUsages ...x509.ExtKeyUsage) (info TLSInfo, err error) {
+ if err = os.MkdirAll(dirpath, 0700); err != nil {
+ return
+ }
+ info.Logger = lg
+
+ certPath := filepath.Join(dirpath, "cert.pem")
+ keyPath := filepath.Join(dirpath, "key.pem")
+ _, errcert := os.Stat(certPath)
+ _, errkey := os.Stat(keyPath)
+ if errcert == nil && errkey == nil {
+ info.CertFile = certPath
+ info.KeyFile = keyPath
+ info.selfCert = true
+ return
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "cannot generate random number",
+ zap.Error(err),
+ )
+ }
+ return
+ }
+
+ tmpl := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{Organization: []string{"etcd"}},
+ NotBefore: time.Now(),
+ NotAfter: time.Now().Add(365 * (24 * time.Hour)),
+
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: append([]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, additionalUsages...),
+ BasicConstraintsValid: true,
+ }
+
+ for _, host := range hosts {
+ h, _, _ := net.SplitHostPort(host)
+ if ip := net.ParseIP(h); ip != nil {
+ tmpl.IPAddresses = append(tmpl.IPAddresses, ip)
+ } else {
+ tmpl.DNSNames = append(tmpl.DNSNames, h)
+ }
+ }
+
+ priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "cannot generate ECDSA key",
+ zap.Error(err),
+ )
+ }
+ return
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, &priv.PublicKey, priv)
+ if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "cannot generate x509 certificate",
+ zap.Error(err),
+ )
+ }
+ return
+ }
+
+ certOut, err := os.Create(certPath)
+ if err != nil {
+ info.Logger.Warn(
+ "cannot cert file",
+ zap.String("path", certPath),
+ zap.Error(err),
+ )
+ return
+ }
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+ certOut.Close()
+ if info.Logger != nil {
+ info.Logger.Info("created cert file", zap.String("path", certPath))
+ }
+
+ b, err := x509.MarshalECPrivateKey(priv)
+ if err != nil {
+ return
+ }
+ keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "cannot key file",
+ zap.String("path", keyPath),
+ zap.Error(err),
+ )
+ }
+ return
+ }
+ pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
+ keyOut.Close()
+ if info.Logger != nil {
+ info.Logger.Info("created key file", zap.String("path", keyPath))
+ }
+ return SelfCert(lg, dirpath, hosts)
+}
+
+// baseConfig is called on initial TLS handshake start.
+//
+// Previously,
+// 1. Server has non-empty (*tls.Config).Certificates on client hello
+// 2. Server calls (*tls.Config).GetCertificate iff:
+// - Server's (*tls.Config).Certificates is not empty, or
+// - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
+//
+// When (*tls.Config).Certificates is always populated on initial handshake,
+// client is expected to provide a valid matching SNI to pass the TLS
+// verification, thus trigger server (*tls.Config).GetCertificate to reload
+// TLS assets. However, a cert whose SAN field does not include domain names
+// but only IP addresses, has empty (*tls.ClientHelloInfo).ServerName, thus
+// it was never able to trigger TLS reload on initial handshake; first
+// ceritifcate object was being used, never being updated.
+//
+// Now, (*tls.Config).Certificates is created empty on initial TLS client
+// handshake, in order to trigger (*tls.Config).GetCertificate and populate
+// rest of the certificates on every new TLS connection, even when client
+// SNI is empty (e.g. cert only includes IPs).
+func (info TLSInfo) baseConfig() (*tls.Config, error) {
+ if info.KeyFile == "" || info.CertFile == "" {
+ return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
+ }
+ if info.Logger == nil {
+ info.Logger = zap.NewNop()
+ }
+
+ _, err := tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
+ if err != nil {
+ return nil, err
+ }
+
+ cfg := &tls.Config{
+ MinVersion: tls.VersionTLS12,
+ ServerName: info.ServerName,
+ }
+
+ if len(info.CipherSuites) > 0 {
+ cfg.CipherSuites = info.CipherSuites
+ }
+
+ // Client certificates may be verified by either an exact match on the CN,
+ // or a more general check of the CN and SANs.
+ var verifyCertificate func(*x509.Certificate) bool
+ if info.AllowedCN != "" {
+ if info.AllowedHostname != "" {
+ return nil, fmt.Errorf("AllowedCN and AllowedHostname are mutually exclusive (cn=%q, hostname=%q)", info.AllowedCN, info.AllowedHostname)
+ }
+ verifyCertificate = func(cert *x509.Certificate) bool {
+ return info.AllowedCN == cert.Subject.CommonName
+ }
+ }
+ if info.AllowedHostname != "" {
+ verifyCertificate = func(cert *x509.Certificate) bool {
+ return cert.VerifyHostname(info.AllowedHostname) == nil
+ }
+ }
+ if verifyCertificate != nil {
+ cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
+ for _, chains := range verifiedChains {
+ if len(chains) != 0 {
+ if verifyCertificate(chains[0]) {
+ return nil
+ }
+ }
+ }
+ return errors.New("client certificate authentication failed")
+ }
+ }
+
+ // this only reloads certs when there's a client request
+ // TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
+ cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
+ cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
+ if os.IsNotExist(err) {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "failed to find peer cert files",
+ zap.String("cert-file", info.CertFile),
+ zap.String("key-file", info.KeyFile),
+ zap.Error(err),
+ )
+ }
+ } else if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "failed to create peer certificate",
+ zap.String("cert-file", info.CertFile),
+ zap.String("key-file", info.KeyFile),
+ zap.Error(err),
+ )
+ }
+ }
+ return cert, err
+ }
+ cfg.GetClientCertificate = func(unused *tls.CertificateRequestInfo) (cert *tls.Certificate, err error) {
+ cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
+ if os.IsNotExist(err) {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "failed to find client cert files",
+ zap.String("cert-file", info.CertFile),
+ zap.String("key-file", info.KeyFile),
+ zap.Error(err),
+ )
+ }
+ } else if err != nil {
+ if info.Logger != nil {
+ info.Logger.Warn(
+ "failed to create client certificate",
+ zap.String("cert-file", info.CertFile),
+ zap.String("key-file", info.KeyFile),
+ zap.Error(err),
+ )
+ }
+ }
+ return cert, err
+ }
+ return cfg, nil
+}
+
+// cafiles returns a list of CA file paths.
+func (info TLSInfo) cafiles() []string {
+ cs := make([]string, 0)
+ if info.TrustedCAFile != "" {
+ cs = append(cs, info.TrustedCAFile)
+ }
+ return cs
+}
+
+// ServerConfig generates a tls.Config object for use by an HTTP server.
+func (info TLSInfo) ServerConfig() (*tls.Config, error) {
+ cfg, err := info.baseConfig()
+ if err != nil {
+ return nil, err
+ }
+
+ cfg.ClientAuth = tls.NoClientCert
+ if info.TrustedCAFile != "" || info.ClientCertAuth {
+ cfg.ClientAuth = tls.RequireAndVerifyClientCert
+ }
+
+ cs := info.cafiles()
+ if len(cs) > 0 {
+ cp, err := tlsutil.NewCertPool(cs)
+ if err != nil {
+ return nil, err
+ }
+ cfg.ClientCAs = cp
+ }
+
+ // "h2" NextProtos is necessary for enabling HTTP2 for go's HTTP server
+ cfg.NextProtos = []string{"h2"}
+
+ // go1.13 enables TLS 1.3 by default
+ // and in TLS 1.3, cipher suites are not configurable
+ // setting Max TLS version to TLS 1.2 for go 1.13
+ cfg.MaxVersion = tls.VersionTLS12
+
+ return cfg, nil
+}
+
+// ClientConfig generates a tls.Config object for use by an HTTP client.
+func (info TLSInfo) ClientConfig() (*tls.Config, error) {
+ var cfg *tls.Config
+ var err error
+
+ if !info.Empty() {
+ cfg, err = info.baseConfig()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ cfg = &tls.Config{ServerName: info.ServerName}
+ }
+ cfg.InsecureSkipVerify = info.InsecureSkipVerify
+
+ cs := info.cafiles()
+ if len(cs) > 0 {
+ cfg.RootCAs, err = tlsutil.NewCertPool(cs)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if info.selfCert {
+ cfg.InsecureSkipVerify = true
+ }
+
+ if info.EmptyCN {
+ hasNonEmptyCN := false
+ cn := ""
+ tlsutil.NewCert(info.CertFile, info.KeyFile, func(certPEMBlock []byte, keyPEMBlock []byte) (tls.Certificate, error) {
+ var block *pem.Block
+ block, _ = pem.Decode(certPEMBlock)
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ return tls.Certificate{}, err
+ }
+ if len(cert.Subject.CommonName) != 0 {
+ hasNonEmptyCN = true
+ cn = cert.Subject.CommonName
+ }
+ return tls.X509KeyPair(certPEMBlock, keyPEMBlock)
+ })
+ if hasNonEmptyCN {
+ return nil, fmt.Errorf("cert has non empty Common Name (%s)", cn)
+ }
+ }
+
+ // go1.13 enables TLS 1.3 by default
+ // and in TLS 1.3, cipher suites are not configurable
+ // setting Max TLS version to TLS 1.2 for go 1.13
+ cfg.MaxVersion = tls.VersionTLS12
+
+ return cfg, nil
+}
+
+// IsClosedConnError returns true if the error is from closing listener, cmux.
+// copied from golang.org/x/net/http2/http2.go
+func IsClosedConnError(err error) bool {
+ // 'use of closed network connection' (Go <=1.8)
+ // 'use of closed file or network connection' (Go >1.8, internal/poll.ErrClosing)
+ // 'mux: listener closed' (cmux.ErrListenerClosed)
+ return err != nil && strings.Contains(err.Error(), "closed")
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/listener_tls.go b/vendor/go.etcd.io/etcd/pkg/transport/listener_tls.go
new file mode 100644
index 0000000..6f16009
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/listener_tls.go
@@ -0,0 +1,272 @@
+// Copyright 2017 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 transport
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "strings"
+ "sync"
+)
+
+// tlsListener overrides a TLS listener so it will reject client
+// certificates with insufficient SAN credentials or CRL revoked
+// certificates.
+type tlsListener struct {
+ net.Listener
+ connc chan net.Conn
+ donec chan struct{}
+ err error
+ handshakeFailure func(*tls.Conn, error)
+ check tlsCheckFunc
+}
+
+type tlsCheckFunc func(context.Context, *tls.Conn) error
+
+// NewTLSListener handshakes TLS connections and performs optional CRL checking.
+func NewTLSListener(l net.Listener, tlsinfo *TLSInfo) (net.Listener, error) {
+ check := func(context.Context, *tls.Conn) error { return nil }
+ return newTLSListener(l, tlsinfo, check)
+}
+
+func newTLSListener(l net.Listener, tlsinfo *TLSInfo, check tlsCheckFunc) (net.Listener, error) {
+ if tlsinfo == nil || tlsinfo.Empty() {
+ l.Close()
+ return nil, fmt.Errorf("cannot listen on TLS for %s: KeyFile and CertFile are not presented", l.Addr().String())
+ }
+ tlscfg, err := tlsinfo.ServerConfig()
+ if err != nil {
+ return nil, err
+ }
+
+ hf := tlsinfo.HandshakeFailure
+ if hf == nil {
+ hf = func(*tls.Conn, error) {}
+ }
+
+ if len(tlsinfo.CRLFile) > 0 {
+ prevCheck := check
+ check = func(ctx context.Context, tlsConn *tls.Conn) error {
+ if err := prevCheck(ctx, tlsConn); err != nil {
+ return err
+ }
+ st := tlsConn.ConnectionState()
+ if certs := st.PeerCertificates; len(certs) > 0 {
+ return checkCRL(tlsinfo.CRLFile, certs)
+ }
+ return nil
+ }
+ }
+
+ tlsl := &tlsListener{
+ Listener: tls.NewListener(l, tlscfg),
+ connc: make(chan net.Conn),
+ donec: make(chan struct{}),
+ handshakeFailure: hf,
+ check: check,
+ }
+ go tlsl.acceptLoop()
+ return tlsl, nil
+}
+
+func (l *tlsListener) Accept() (net.Conn, error) {
+ select {
+ case conn := <-l.connc:
+ return conn, nil
+ case <-l.donec:
+ return nil, l.err
+ }
+}
+
+func checkSAN(ctx context.Context, tlsConn *tls.Conn) error {
+ st := tlsConn.ConnectionState()
+ if certs := st.PeerCertificates; len(certs) > 0 {
+ addr := tlsConn.RemoteAddr().String()
+ return checkCertSAN(ctx, certs[0], addr)
+ }
+ return nil
+}
+
+// acceptLoop launches each TLS handshake in a separate goroutine
+// to prevent a hanging TLS connection from blocking other connections.
+func (l *tlsListener) acceptLoop() {
+ var wg sync.WaitGroup
+ var pendingMu sync.Mutex
+
+ pending := make(map[net.Conn]struct{})
+ ctx, cancel := context.WithCancel(context.Background())
+ defer func() {
+ cancel()
+ pendingMu.Lock()
+ for c := range pending {
+ c.Close()
+ }
+ pendingMu.Unlock()
+ wg.Wait()
+ close(l.donec)
+ }()
+
+ for {
+ conn, err := l.Listener.Accept()
+ if err != nil {
+ l.err = err
+ return
+ }
+
+ pendingMu.Lock()
+ pending[conn] = struct{}{}
+ pendingMu.Unlock()
+
+ wg.Add(1)
+ go func() {
+ defer func() {
+ if conn != nil {
+ conn.Close()
+ }
+ wg.Done()
+ }()
+
+ tlsConn := conn.(*tls.Conn)
+ herr := tlsConn.Handshake()
+ pendingMu.Lock()
+ delete(pending, conn)
+ pendingMu.Unlock()
+
+ if herr != nil {
+ l.handshakeFailure(tlsConn, herr)
+ return
+ }
+ if err := l.check(ctx, tlsConn); err != nil {
+ l.handshakeFailure(tlsConn, err)
+ return
+ }
+
+ select {
+ case l.connc <- tlsConn:
+ conn = nil
+ case <-ctx.Done():
+ }
+ }()
+ }
+}
+
+func checkCRL(crlPath string, cert []*x509.Certificate) error {
+ // TODO: cache
+ crlBytes, err := ioutil.ReadFile(crlPath)
+ if err != nil {
+ return err
+ }
+ certList, err := x509.ParseCRL(crlBytes)
+ if err != nil {
+ return err
+ }
+ revokedSerials := make(map[string]struct{})
+ for _, rc := range certList.TBSCertList.RevokedCertificates {
+ revokedSerials[string(rc.SerialNumber.Bytes())] = struct{}{}
+ }
+ for _, c := range cert {
+ serial := string(c.SerialNumber.Bytes())
+ if _, ok := revokedSerials[serial]; ok {
+ return fmt.Errorf("transport: certificate serial %x revoked", serial)
+ }
+ }
+ return nil
+}
+
+func checkCertSAN(ctx context.Context, cert *x509.Certificate, remoteAddr string) error {
+ if len(cert.IPAddresses) == 0 && len(cert.DNSNames) == 0 {
+ return nil
+ }
+ h, _, herr := net.SplitHostPort(remoteAddr)
+ if herr != nil {
+ return herr
+ }
+ if len(cert.IPAddresses) > 0 {
+ cerr := cert.VerifyHostname(h)
+ if cerr == nil {
+ return nil
+ }
+ if len(cert.DNSNames) == 0 {
+ return cerr
+ }
+ }
+ if len(cert.DNSNames) > 0 {
+ ok, err := isHostInDNS(ctx, h, cert.DNSNames)
+ if ok {
+ return nil
+ }
+ errStr := ""
+ if err != nil {
+ errStr = " (" + err.Error() + ")"
+ }
+ return fmt.Errorf("tls: %q does not match any of DNSNames %q"+errStr, h, cert.DNSNames)
+ }
+ return nil
+}
+
+func isHostInDNS(ctx context.Context, host string, dnsNames []string) (ok bool, err error) {
+ // reverse lookup
+ wildcards, names := []string{}, []string{}
+ for _, dns := range dnsNames {
+ if strings.HasPrefix(dns, "*.") {
+ wildcards = append(wildcards, dns[1:])
+ } else {
+ names = append(names, dns)
+ }
+ }
+ lnames, lerr := net.DefaultResolver.LookupAddr(ctx, host)
+ for _, name := range lnames {
+ // strip trailing '.' from PTR record
+ if name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+ for _, wc := range wildcards {
+ if strings.HasSuffix(name, wc) {
+ return true, nil
+ }
+ }
+ for _, n := range names {
+ if n == name {
+ return true, nil
+ }
+ }
+ }
+ err = lerr
+
+ // forward lookup
+ for _, dns := range names {
+ addrs, lerr := net.DefaultResolver.LookupHost(ctx, dns)
+ if lerr != nil {
+ err = lerr
+ continue
+ }
+ for _, addr := range addrs {
+ if addr == host {
+ return true, nil
+ }
+ }
+ }
+ return false, err
+}
+
+func (l *tlsListener) Close() error {
+ err := l.Listener.Close()
+ <-l.donec
+ return err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/timeout_conn.go b/vendor/go.etcd.io/etcd/pkg/transport/timeout_conn.go
new file mode 100644
index 0000000..7e8c020
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/timeout_conn.go
@@ -0,0 +1,44 @@
+// 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 transport
+
+import (
+ "net"
+ "time"
+)
+
+type timeoutConn struct {
+ net.Conn
+ wtimeoutd time.Duration
+ rdtimeoutd time.Duration
+}
+
+func (c timeoutConn) Write(b []byte) (n int, err error) {
+ if c.wtimeoutd > 0 {
+ if err := c.SetWriteDeadline(time.Now().Add(c.wtimeoutd)); err != nil {
+ return 0, err
+ }
+ }
+ return c.Conn.Write(b)
+}
+
+func (c timeoutConn) Read(b []byte) (n int, err error) {
+ if c.rdtimeoutd > 0 {
+ if err := c.SetReadDeadline(time.Now().Add(c.rdtimeoutd)); err != nil {
+ return 0, err
+ }
+ }
+ return c.Conn.Read(b)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/timeout_dialer.go b/vendor/go.etcd.io/etcd/pkg/transport/timeout_dialer.go
new file mode 100644
index 0000000..6ae39ec
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/timeout_dialer.go
@@ -0,0 +1,36 @@
+// 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 transport
+
+import (
+ "net"
+ "time"
+)
+
+type rwTimeoutDialer struct {
+ wtimeoutd time.Duration
+ rdtimeoutd time.Duration
+ net.Dialer
+}
+
+func (d *rwTimeoutDialer) Dial(network, address string) (net.Conn, error) {
+ conn, err := d.Dialer.Dial(network, address)
+ tconn := &timeoutConn{
+ rdtimeoutd: d.rdtimeoutd,
+ wtimeoutd: d.wtimeoutd,
+ Conn: conn,
+ }
+ return tconn, err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/timeout_listener.go b/vendor/go.etcd.io/etcd/pkg/transport/timeout_listener.go
new file mode 100644
index 0000000..273e99f
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/timeout_listener.go
@@ -0,0 +1,57 @@
+// 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 transport
+
+import (
+ "net"
+ "time"
+)
+
+// NewTimeoutListener returns a listener that listens on the given address.
+// If read/write on the accepted connection blocks longer than its time limit,
+// it will return timeout error.
+func NewTimeoutListener(addr string, scheme string, tlsinfo *TLSInfo, rdtimeoutd, wtimeoutd time.Duration) (net.Listener, error) {
+ ln, err := newListener(addr, scheme)
+ if err != nil {
+ return nil, err
+ }
+ ln = &rwTimeoutListener{
+ Listener: ln,
+ rdtimeoutd: rdtimeoutd,
+ wtimeoutd: wtimeoutd,
+ }
+ if ln, err = wrapTLS(scheme, tlsinfo, ln); err != nil {
+ return nil, err
+ }
+ return ln, nil
+}
+
+type rwTimeoutListener struct {
+ net.Listener
+ wtimeoutd time.Duration
+ rdtimeoutd time.Duration
+}
+
+func (rwln *rwTimeoutListener) Accept() (net.Conn, error) {
+ c, err := rwln.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ return timeoutConn{
+ Conn: c,
+ wtimeoutd: rwln.wtimeoutd,
+ rdtimeoutd: rwln.rdtimeoutd,
+ }, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/timeout_transport.go b/vendor/go.etcd.io/etcd/pkg/transport/timeout_transport.go
new file mode 100644
index 0000000..ea16b4c
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/timeout_transport.go
@@ -0,0 +1,51 @@
+// 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 transport
+
+import (
+ "net"
+ "net/http"
+ "time"
+)
+
+// NewTimeoutTransport returns a transport created using the given TLS info.
+// If read/write on the created connection blocks longer than its time limit,
+// it will return timeout error.
+// If read/write timeout is set, transport will not be able to reuse connection.
+func NewTimeoutTransport(info TLSInfo, dialtimeoutd, rdtimeoutd, wtimeoutd time.Duration) (*http.Transport, error) {
+ tr, err := NewTransport(info, dialtimeoutd)
+ if err != nil {
+ return nil, err
+ }
+
+ if rdtimeoutd != 0 || wtimeoutd != 0 {
+ // the timed out connection will timeout soon after it is idle.
+ // it should not be put back to http transport as an idle connection for future usage.
+ tr.MaxIdleConnsPerHost = -1
+ } else {
+ // allow more idle connections between peers to avoid unnecessary port allocation.
+ tr.MaxIdleConnsPerHost = 1024
+ }
+
+ tr.Dial = (&rwTimeoutDialer{
+ Dialer: net.Dialer{
+ Timeout: dialtimeoutd,
+ KeepAlive: 30 * time.Second,
+ },
+ rdtimeoutd: rdtimeoutd,
+ wtimeoutd: wtimeoutd,
+ }).Dial
+ return tr, nil
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/tls.go b/vendor/go.etcd.io/etcd/pkg/transport/tls.go
new file mode 100644
index 0000000..62fe0d3
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/tls.go
@@ -0,0 +1,49 @@
+// 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 transport
+
+import (
+ "fmt"
+ "strings"
+ "time"
+)
+
+// ValidateSecureEndpoints scans the given endpoints against tls info, returning only those
+// endpoints that could be validated as secure.
+func ValidateSecureEndpoints(tlsInfo TLSInfo, eps []string) ([]string, error) {
+ t, err := NewTransport(tlsInfo, 5*time.Second)
+ if err != nil {
+ return nil, err
+ }
+ var errs []string
+ var endpoints []string
+ for _, ep := range eps {
+ if !strings.HasPrefix(ep, "https://") {
+ errs = append(errs, fmt.Sprintf("%q is insecure", ep))
+ continue
+ }
+ conn, cerr := t.Dial("tcp", ep[len("https://"):])
+ if cerr != nil {
+ errs = append(errs, fmt.Sprintf("%q failed to dial (%v)", ep, cerr))
+ continue
+ }
+ conn.Close()
+ endpoints = append(endpoints, ep)
+ }
+ if len(errs) != 0 {
+ err = fmt.Errorf("%s", strings.Join(errs, ","))
+ }
+ return endpoints, err
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/transport.go b/vendor/go.etcd.io/etcd/pkg/transport/transport.go
new file mode 100644
index 0000000..4a7fe69
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/transport.go
@@ -0,0 +1,71 @@
+// 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 transport
+
+import (
+ "net"
+ "net/http"
+ "strings"
+ "time"
+)
+
+type unixTransport struct{ *http.Transport }
+
+func NewTransport(info TLSInfo, dialtimeoutd time.Duration) (*http.Transport, error) {
+ cfg, err := info.ClientConfig()
+ if err != nil {
+ return nil, err
+ }
+
+ t := &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ Dial: (&net.Dialer{
+ Timeout: dialtimeoutd,
+ // value taken from http.DefaultTransport
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ // value taken from http.DefaultTransport
+ TLSHandshakeTimeout: 10 * time.Second,
+ TLSClientConfig: cfg,
+ }
+
+ dialer := (&net.Dialer{
+ Timeout: dialtimeoutd,
+ KeepAlive: 30 * time.Second,
+ })
+ dial := func(net, addr string) (net.Conn, error) {
+ return dialer.Dial("unix", addr)
+ }
+
+ tu := &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ Dial: dial,
+ TLSHandshakeTimeout: 10 * time.Second,
+ TLSClientConfig: cfg,
+ }
+ ut := &unixTransport{tu}
+
+ t.RegisterProtocol("unix", ut)
+ t.RegisterProtocol("unixs", ut)
+
+ return t, nil
+}
+
+func (urt *unixTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+ url := *req.URL
+ req.URL = &url
+ req.URL.Scheme = strings.Replace(req.URL.Scheme, "unix", "http", 1)
+ return urt.Transport.RoundTrip(req)
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/transport/unix_listener.go b/vendor/go.etcd.io/etcd/pkg/transport/unix_listener.go
new file mode 100644
index 0000000..123e203
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/transport/unix_listener.go
@@ -0,0 +1,40 @@
+// 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 transport
+
+import (
+ "net"
+ "os"
+)
+
+type unixListener struct{ net.Listener }
+
+func NewUnixListener(addr string) (net.Listener, error) {
+ if err := os.Remove(addr); err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+ l, err := net.Listen("unix", addr)
+ if err != nil {
+ return nil, err
+ }
+ return &unixListener{l}, nil
+}
+
+func (ul *unixListener) Close() error {
+ if err := os.Remove(ul.Addr().String()); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return ul.Listener.Close()
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/wait/wait.go b/vendor/go.etcd.io/etcd/pkg/wait/wait.go
new file mode 100644
index 0000000..9b1df41
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/wait/wait.go
@@ -0,0 +1,91 @@
+// 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 wait provides utility functions for polling, listening using Go
+// channel.
+package wait
+
+import (
+ "log"
+ "sync"
+)
+
+// Wait is an interface that provides the ability to wait and trigger events that
+// are associated with IDs.
+type Wait interface {
+ // Register waits returns a chan that waits on the given ID.
+ // The chan will be triggered when Trigger is called with
+ // the same ID.
+ Register(id uint64) <-chan interface{}
+ // Trigger triggers the waiting chans with the given ID.
+ Trigger(id uint64, x interface{})
+ IsRegistered(id uint64) bool
+}
+
+type list struct {
+ l sync.RWMutex
+ m map[uint64]chan interface{}
+}
+
+// New creates a Wait.
+func New() Wait {
+ return &list{m: make(map[uint64]chan interface{})}
+}
+
+func (w *list) Register(id uint64) <-chan interface{} {
+ w.l.Lock()
+ defer w.l.Unlock()
+ ch := w.m[id]
+ if ch == nil {
+ ch = make(chan interface{}, 1)
+ w.m[id] = ch
+ } else {
+ log.Panicf("dup id %x", id)
+ }
+ return ch
+}
+
+func (w *list) Trigger(id uint64, x interface{}) {
+ w.l.Lock()
+ ch := w.m[id]
+ delete(w.m, id)
+ w.l.Unlock()
+ if ch != nil {
+ ch <- x
+ close(ch)
+ }
+}
+
+func (w *list) IsRegistered(id uint64) bool {
+ w.l.RLock()
+ defer w.l.RUnlock()
+ _, ok := w.m[id]
+ return ok
+}
+
+type waitWithResponse struct {
+ ch <-chan interface{}
+}
+
+func NewWithResponse(ch <-chan interface{}) Wait {
+ return &waitWithResponse{ch: ch}
+}
+
+func (w *waitWithResponse) Register(id uint64) <-chan interface{} {
+ return w.ch
+}
+func (w *waitWithResponse) Trigger(id uint64, x interface{}) {}
+func (w *waitWithResponse) IsRegistered(id uint64) bool {
+ panic("waitWithResponse.IsRegistered() shouldn't be called")
+}
diff --git a/vendor/go.etcd.io/etcd/pkg/wait/wait_time.go b/vendor/go.etcd.io/etcd/pkg/wait/wait_time.go
new file mode 100644
index 0000000..297e48a
--- /dev/null
+++ b/vendor/go.etcd.io/etcd/pkg/wait/wait_time.go
@@ -0,0 +1,66 @@
+// 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 wait
+
+import "sync"
+
+type WaitTime interface {
+ // Wait returns a chan that waits on the given logical deadline.
+ // The chan will be triggered when Trigger is called with a
+ // deadline that is later than the one it is waiting for.
+ Wait(deadline uint64) <-chan struct{}
+ // Trigger triggers all the waiting chans with an earlier logical deadline.
+ Trigger(deadline uint64)
+}
+
+var closec chan struct{}
+
+func init() { closec = make(chan struct{}); close(closec) }
+
+type timeList struct {
+ l sync.Mutex
+ lastTriggerDeadline uint64
+ m map[uint64]chan struct{}
+}
+
+func NewTimeList() *timeList {
+ return &timeList{m: make(map[uint64]chan struct{})}
+}
+
+func (tl *timeList) Wait(deadline uint64) <-chan struct{} {
+ tl.l.Lock()
+ defer tl.l.Unlock()
+ if tl.lastTriggerDeadline >= deadline {
+ return closec
+ }
+ ch := tl.m[deadline]
+ if ch == nil {
+ ch = make(chan struct{})
+ tl.m[deadline] = ch
+ }
+ return ch
+}
+
+func (tl *timeList) Trigger(deadline uint64) {
+ tl.l.Lock()
+ defer tl.l.Unlock()
+ tl.lastTriggerDeadline = deadline
+ for t, ch := range tl.m {
+ if t <= deadline {
+ delete(tl.m, t)
+ close(ch)
+ }
+ }
+}