Add vendor folder to git

This commit is contained in:
Lucas Käldström 2017-06-26 19:23:05 +03:00
parent 66cf5eaafb
commit 183585f56f
No known key found for this signature in database
GPG key ID: 600FEFBBD0D40D21
6916 changed files with 2629581 additions and 1 deletions

2
vendor/github.com/coreos/etcd/pkg/README.md generated vendored Normal file
View file

@ -0,0 +1,2 @@
pkg/ is a collection of utility packages used by etcd without being specific to etcd itself. A package belongs here
only if it could possibly be moved out into its own repository in the future.

16
vendor/github.com/coreos/etcd/pkg/adt/doc.go generated vendored Normal file
View file

@ -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

37
vendor/github.com/coreos/etcd/pkg/adt/example_test.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
// 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_test
import (
"fmt"
"github.com/coreos/etcd/pkg/adt"
)
func Example() {
ivt := &adt.IntervalTree{}
ivt.Insert(adt.NewInt64Interval(1, 3), 123)
ivt.Insert(adt.NewInt64Interval(9, 13), 456)
ivt.Insert(adt.NewInt64Interval(7, 20), 789)
rs := ivt.Stab(adt.NewInt64Point(10))
for _, v := range rs {
fmt.Printf("Overlapping range: %+v\n", v)
}
// output:
// Overlapping range: &{Ivl:{Begin:7 End:20} Val:789}
// Overlapping range: &{Ivl:{Begin:9 End:13} Val:456}
}

531
vendor/github.com/coreos/etcd/pkg/adt/interval_tree.go generated vendored Normal file
View file

@ -0,0 +1,531 @@
// 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 (
"math"
)
// 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
)
// 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() rbcolor {
if x == nil {
return black
}
return x.c
}
func (n *intervalNode) height() int {
if n == nil {
return 0
}
ld := n.left.height()
rd := n.right.height()
if ld < rd {
return rd + 1
}
return ld + 1
}
func (x *intervalNode) min() *intervalNode {
for x.left != nil {
x = x.left
}
return x
}
// successor is the next in-order node in the tree
func (x *intervalNode) successor() *intervalNode {
if x.right != nil {
return x.right.min()
}
y := x.parent
for y != nil && 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() {
for x != nil {
oldmax := x.max
max := x.iv.Ivl.End
if x.left != nil && x.left.max.Compare(max) > 0 {
max = x.left.max
}
if x.right != nil && 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, nv nodeVisitor) {
if x == nil {
return
}
v := iv.Compare(&x.iv.Ivl)
switch {
case v < 0:
x.left.visit(iv, nv)
case v > 0:
maxiv := Interval{x.iv.Ivl.Begin, x.max}
if maxiv.Compare(iv) == 0 {
x.left.visit(iv, nv)
x.right.visit(iv, nv)
}
default:
nv(x)
x.left.visit(iv, nv)
x.right.visit(iv, nv)
}
}
type IntervalValue struct {
Ivl Interval
Val interface{}
}
// IntervalTree represents a (mostly) textbook implementation of the
// "Introduction to Algorithms" (Cormen et al, 2nd ed.) chapter 13 red-black tree
// and chapter 14.3 interval tree with search supporting "stabbing queries".
type IntervalTree struct {
root *intervalNode
count int
}
// 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 == nil {
return false
}
y := z
if z.left != nil && z.right != nil {
y = z.successor()
}
x := y.left
if x == nil {
x = y.right
}
if x != nil {
x.parent = y.parent
}
if y.parent == nil {
ivt.root = x
} else {
if y == y.parent.left {
y.parent.left = x
} else {
y.parent.right = x
}
y.parent.updateMax()
}
if y != z {
z.iv = y.iv
z.updateMax()
}
if y.color() == black && x != nil {
ivt.deleteFixup(x)
}
ivt.count--
return true
}
func (ivt *IntervalTree) deleteFixup(x *intervalNode) {
for x != ivt.root && x.color() == black && x.parent != nil {
if x == x.parent.left {
w := x.parent.right
if w.color() == red {
w.c = black
x.parent.c = red
ivt.rotateLeft(x.parent)
w = x.parent.right
}
if w == nil {
break
}
if w.left.color() == black && w.right.color() == black {
w.c = red
x = x.parent
} else {
if w.right.color() == black {
w.left.c = black
w.c = red
ivt.rotateRight(w)
w = x.parent.right
}
w.c = x.parent.color()
x.parent.c = black
w.right.c = black
ivt.rotateLeft(x.parent)
x = ivt.root
}
} else {
// same as above but with left and right exchanged
w := x.parent.left
if w.color() == red {
w.c = black
x.parent.c = red
ivt.rotateRight(x.parent)
w = x.parent.left
}
if w == nil {
break
}
if w.left.color() == black && w.right.color() == black {
w.c = red
x = x.parent
} else {
if w.left.color() == black {
w.right.c = black
w.c = red
ivt.rotateLeft(w)
w = x.parent.left
}
w.c = x.parent.color()
x.parent.c = black
w.left.c = black
ivt.rotateRight(x.parent)
x = ivt.root
}
}
}
if x != nil {
x.c = black
}
}
// Insert adds a node with the given interval into the tree.
func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) {
var y *intervalNode
z := &intervalNode{iv: IntervalValue{ivl, val}, max: ivl.End, c: red}
x := ivt.root
for x != nil {
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 == nil {
ivt.root = z
} else {
if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 {
y.left = z
} else {
y.right = z
}
y.updateMax()
}
z.c = red
ivt.insertFixup(z)
ivt.count++
}
func (ivt *IntervalTree) insertFixup(z *intervalNode) {
for z.parent != nil && z.parent.parent != nil && z.parent.color() == red {
if z.parent == z.parent.parent.left {
y := z.parent.parent.right
if y.color() == 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 {
// same as then with left/right exchanged
y := z.parent.parent.left
if y.color() == 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)
}
}
}
ivt.root.c = black
}
// rotateLeft moves x so it is left of its right child
func (ivt *IntervalTree) rotateLeft(x *intervalNode) {
y := x.right
x.right = y.left
if y.left != nil {
y.left.parent = x
}
x.updateMax()
ivt.replaceParent(x, y)
y.left = x
y.updateMax()
}
// rotateLeft moves x so it is right of its left child
func (ivt *IntervalTree) rotateRight(x *intervalNode) {
if x == nil {
return
}
y := x.left
x.left = y.right
if y.right != nil {
y.right.parent = x
}
x.updateMax()
ivt.replaceParent(x, y)
y.right = x
y.updateMax()
}
// replaceParent replaces x's parent with y
func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) {
y.parent = x.parent
if x.parent == nil {
ivt.root = y
} else {
if x == x.parent.left {
x.parent.left = y
} else {
x.parent.right = y
}
x.parent.updateMax()
}
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() }
// 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 searchs; return false to stop searching.
type IntervalVisitor func(n *IntervalValue) bool
// Visit calls a visitor function on every tree node intersecting the given interval.
func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) {
ivt.root.visit(&ivl, func(n *intervalNode) bool { return ivv(&n.iv) })
}
// find the exact node for a given interval
func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) {
f := func(n *intervalNode) bool {
if n.iv.Ivl != ivl {
return true
}
ret = n
return false
}
ivt.root.visit(&ivl, 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 == nil {
return nil
}
return &n.iv
}
// Contains returns true if there is some tree node intersecting the given interval.
func (ivt *IntervalTree) Contains(iv Interval) bool {
x := ivt.root
for x != nil && iv.Compare(&x.iv.Ivl) != 0 {
if x.left != nil && x.left.max.Compare(iv.Begin) > 0 {
x = x.left
} else {
x = x.right
}
}
return x != nil
}
// 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
}
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 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
}

View file

@ -0,0 +1,138 @@
// 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 (
"math/rand"
"testing"
"time"
)
func TestIntervalTreeContains(t *testing.T) {
ivt := &IntervalTree{}
ivt.Insert(NewStringInterval("1", "3"), 123)
if ivt.Contains(NewStringPoint("0")) {
t.Errorf("contains 0")
}
if !ivt.Contains(NewStringPoint("1")) {
t.Errorf("missing 1")
}
if !ivt.Contains(NewStringPoint("11")) {
t.Errorf("missing 11")
}
if !ivt.Contains(NewStringPoint("2")) {
t.Errorf("missing 2")
}
if ivt.Contains(NewStringPoint("3")) {
t.Errorf("contains 3")
}
}
func TestIntervalTreeStringAffine(t *testing.T) {
ivt := &IntervalTree{}
ivt.Insert(NewStringAffineInterval("8", ""), 123)
if !ivt.Contains(NewStringAffinePoint("9")) {
t.Errorf("missing 9")
}
if ivt.Contains(NewStringAffinePoint("7")) {
t.Errorf("contains 7")
}
}
func TestIntervalTreeStab(t *testing.T) {
ivt := &IntervalTree{}
ivt.Insert(NewStringInterval("0", "1"), 123)
ivt.Insert(NewStringInterval("0", "2"), 456)
ivt.Insert(NewStringInterval("5", "6"), 789)
ivt.Insert(NewStringInterval("6", "8"), 999)
ivt.Insert(NewStringInterval("0", "3"), 0)
if ivt.root.max.Compare(StringComparable("8")) != 0 {
t.Fatalf("wrong root max got %v, expected 8", ivt.root.max)
}
if x := len(ivt.Stab(NewStringPoint("0"))); x != 3 {
t.Errorf("got %d, expected 3", x)
}
if x := len(ivt.Stab(NewStringPoint("1"))); x != 2 {
t.Errorf("got %d, expected 2", x)
}
if x := len(ivt.Stab(NewStringPoint("2"))); x != 1 {
t.Errorf("got %d, expected 1", x)
}
if x := len(ivt.Stab(NewStringPoint("3"))); x != 0 {
t.Errorf("got %d, expected 0", x)
}
if x := len(ivt.Stab(NewStringPoint("5"))); x != 1 {
t.Errorf("got %d, expected 1", x)
}
if x := len(ivt.Stab(NewStringPoint("55"))); x != 1 {
t.Errorf("got %d, expected 1", x)
}
if x := len(ivt.Stab(NewStringPoint("6"))); x != 1 {
t.Errorf("got %d, expected 1", x)
}
}
type xy struct {
x int64
y int64
}
func TestIntervalTreeRandom(t *testing.T) {
// generate unique intervals
ivs := make(map[xy]struct{})
ivt := &IntervalTree{}
maxv := 128
rand.Seed(time.Now().UnixNano())
for i := rand.Intn(maxv) + 1; i != 0; i-- {
x, y := int64(rand.Intn(maxv)), int64(rand.Intn(maxv))
if x > y {
t := x
x = y
y = t
} else if x == y {
y++
}
iv := xy{x, y}
if _, ok := ivs[iv]; ok {
// don't double insert
continue
}
ivt.Insert(NewInt64Interval(x, y), 123)
ivs[iv] = struct{}{}
}
for ab := range ivs {
for xy := range ivs {
v := xy.x + int64(rand.Intn(int(xy.y-xy.x)))
if slen := len(ivt.Stab(NewInt64Point(v))); slen == 0 {
t.Fatalf("expected %v stab non-zero for [%+v)", v, xy)
}
if !ivt.Contains(NewInt64Point(v)) {
t.Fatalf("did not get %d as expected for [%+v)", v, xy)
}
}
if !ivt.Delete(NewInt64Interval(ab.x, ab.y)) {
t.Errorf("did not delete %v as expected", ab)
}
delete(ivs, ab)
}
if ivt.Len() != 0 {
t.Errorf("got ivt.Len() = %v, expected 0", ivt.Len())
}
}

View file

@ -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
}

16
vendor/github.com/coreos/etcd/pkg/contention/doc.go generated vendored Normal file
View file

@ -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

90
vendor/github.com/coreos/etcd/pkg/cors/cors.go generated vendored Normal file
View file

@ -0,0 +1,90 @@
// 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 cors handles cross-origin HTTP requests (CORS).
package cors
import (
"fmt"
"net/http"
"net/url"
"sort"
"strings"
)
type CORSInfo map[string]bool
// Set implements the flag.Value interface to allow users to define a list of CORS origins
func (ci *CORSInfo) Set(s string) error {
m := make(map[string]bool)
for _, v := range strings.Split(s, ",") {
v = strings.TrimSpace(v)
if v == "" {
continue
}
if v != "*" {
if _, err := url.Parse(v); err != nil {
return fmt.Errorf("Invalid CORS origin: %s", err)
}
}
m[v] = true
}
*ci = CORSInfo(m)
return nil
}
func (ci *CORSInfo) String() string {
o := make([]string, 0)
for k := range *ci {
o = append(o, k)
}
sort.StringSlice(o).Sort()
return strings.Join(o, ",")
}
// OriginAllowed determines whether the server will allow a given CORS origin.
func (c CORSInfo) OriginAllowed(origin string) bool {
return c["*"] || c[origin]
}
type CORSHandler struct {
Handler http.Handler
Info *CORSInfo
}
// addHeader adds the correct cors headers given an origin
func (h *CORSHandler) addHeader(w http.ResponseWriter, origin string) {
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Add("Access-Control-Allow-Origin", origin)
w.Header().Add("Access-Control-Allow-Headers", "accept, content-type, authorization")
}
// ServeHTTP adds the correct CORS headers based on the origin and returns immediately
// with a 200 OK if the method is OPTIONS.
func (h *CORSHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Write CORS header.
if h.Info.OriginAllowed("*") {
h.addHeader(w, "*")
} else if origin := req.Header.Get("Origin"); h.Info.OriginAllowed(origin) {
h.addHeader(w, origin)
}
if req.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
h.Handler.ServeHTTP(w, req)
}

125
vendor/github.com/coreos/etcd/pkg/cors/cors_test.go generated vendored Normal file
View file

@ -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.
package cors
import (
"net/http"
"net/http/httptest"
"reflect"
"testing"
)
func TestCORSInfo(t *testing.T) {
tests := []struct {
s string
winfo CORSInfo
ws string
}{
{"", CORSInfo{}, ""},
{"http://127.0.0.1", CORSInfo{"http://127.0.0.1": true}, "http://127.0.0.1"},
{"*", CORSInfo{"*": true}, "*"},
// with space around
{" http://127.0.0.1 ", CORSInfo{"http://127.0.0.1": true}, "http://127.0.0.1"},
// multiple addrs
{
"http://127.0.0.1,http://127.0.0.2",
CORSInfo{"http://127.0.0.1": true, "http://127.0.0.2": true},
"http://127.0.0.1,http://127.0.0.2",
},
}
for i, tt := range tests {
info := CORSInfo{}
if err := info.Set(tt.s); err != nil {
t.Errorf("#%d: set error = %v, want nil", i, err)
}
if !reflect.DeepEqual(info, tt.winfo) {
t.Errorf("#%d: info = %v, want %v", i, info, tt.winfo)
}
if g := info.String(); g != tt.ws {
t.Errorf("#%d: info string = %s, want %s", i, g, tt.ws)
}
}
}
func TestCORSInfoOriginAllowed(t *testing.T) {
tests := []struct {
set string
origin string
wallowed bool
}{
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.1", true},
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.2", true},
{"http://127.0.0.1,http://127.0.0.2", "*", false},
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.3", false},
{"*", "*", true},
{"*", "http://127.0.0.1", true},
}
for i, tt := range tests {
info := CORSInfo{}
if err := info.Set(tt.set); err != nil {
t.Errorf("#%d: set error = %v, want nil", i, err)
}
if g := info.OriginAllowed(tt.origin); g != tt.wallowed {
t.Errorf("#%d: allowed = %v, want %v", i, g, tt.wallowed)
}
}
}
func TestCORSHandler(t *testing.T) {
info := &CORSInfo{}
if err := info.Set("http://127.0.0.1,http://127.0.0.2"); err != nil {
t.Fatalf("unexpected set error: %v", err)
}
h := &CORSHandler{
Handler: http.NotFoundHandler(),
Info: info,
}
header := func(origin string) http.Header {
return http.Header{
"Access-Control-Allow-Methods": []string{"POST, GET, OPTIONS, PUT, DELETE"},
"Access-Control-Allow-Origin": []string{origin},
"Access-Control-Allow-Headers": []string{"accept, content-type, authorization"},
}
}
tests := []struct {
method string
origin string
wcode int
wheader http.Header
}{
{"GET", "http://127.0.0.1", http.StatusNotFound, header("http://127.0.0.1")},
{"GET", "http://127.0.0.2", http.StatusNotFound, header("http://127.0.0.2")},
{"GET", "http://127.0.0.3", http.StatusNotFound, http.Header{}},
{"OPTIONS", "http://127.0.0.1", http.StatusOK, header("http://127.0.0.1")},
}
for i, tt := range tests {
rr := httptest.NewRecorder()
req := &http.Request{
Method: tt.method,
Header: http.Header{"Origin": []string{tt.origin}},
}
h.ServeHTTP(rr, req)
if rr.Code != tt.wcode {
t.Errorf("#%d: code = %v, want %v", i, rr.Code, tt.wcode)
}
// it is set by http package, and there is no need to test it
rr.HeaderMap.Del("Content-Type")
rr.HeaderMap.Del("X-Content-Type-Options")
if !reflect.DeepEqual(rr.HeaderMap, tt.wheader) {
t.Errorf("#%d: header = %+v, want %+v", i, rr.HeaderMap, tt.wheader)
}
}
}

16
vendor/github.com/coreos/etcd/pkg/cpuutil/doc.go generated vendored Normal file
View file

@ -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

36
vendor/github.com/coreos/etcd/pkg/cpuutil/endian.go generated vendored Normal file
View file

@ -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() {
var i int = 0x1
if v := (*[intWidth]byte)(unsafe.Pointer(&i)); v[0] == 0 {
byteOrder = binary.BigEndian
} else {
byteOrder = binary.LittleEndian
}
}

43
vendor/github.com/coreos/etcd/pkg/crc/crc.go generated vendored Normal file
View file

@ -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))
}

59
vendor/github.com/coreos/etcd/pkg/crc/crc_test.go generated vendored Normal file
View file

@ -0,0 +1,59 @@
// 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
import (
"hash/crc32"
"reflect"
"testing"
)
// TestHash32 tests that Hash32 provided by this package can take an initial
// crc and behaves exactly the same as the standard one in the following calls.
func TestHash32(t *testing.T) {
stdhash := crc32.New(crc32.IEEETable)
if _, err := stdhash.Write([]byte("test data")); err != nil {
t.Fatalf("unexpected write error: %v", err)
}
// create a new hash with stdhash.Sum32() as initial crc
hash := New(stdhash.Sum32(), crc32.IEEETable)
wsize := stdhash.Size()
if g := hash.Size(); g != wsize {
t.Errorf("size = %d, want %d", g, wsize)
}
wbsize := stdhash.BlockSize()
if g := hash.BlockSize(); g != wbsize {
t.Errorf("block size = %d, want %d", g, wbsize)
}
wsum32 := stdhash.Sum32()
if g := hash.Sum32(); g != wsum32 {
t.Errorf("Sum32 = %d, want %d", g, wsum32)
}
wsum := stdhash.Sum(make([]byte, 32))
if g := hash.Sum(make([]byte, 32)); !reflect.DeepEqual(g, wsum) {
t.Errorf("sum = %v, want %v", g, wsum)
}
// write something
if _, err := stdhash.Write([]byte("test data")); err != nil {
t.Fatalf("unexpected write error: %v", err)
}
if _, err := hash.Write([]byte("test data")); err != nil {
t.Fatalf("unexpected write error: %v", err)
}
wsum32 = stdhash.Sum32()
if g := hash.Sum32(); g != wsum32 {
t.Errorf("Sum32 after write = %d, want %d", g, wsum32)
}
// reset
stdhash.Reset()
hash.Reset()
wsum32 = stdhash.Sum32()
if g := hash.Sum32(); g != wsum32 {
t.Errorf("Sum32 after reset = %d, want %d", g, wsum32)
}
}

160
vendor/github.com/coreos/etcd/pkg/expect/expect.go generated vendored Normal file
View file

@ -0,0 +1,160 @@
// 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 expect implements a small expect-style interface
package expect
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strings"
"sync"
"github.com/kr/pty"
)
type ExpectProcess struct {
cmd *exec.Cmd
fpty *os.File
wg sync.WaitGroup
ptyMu sync.Mutex // protects accessing fpty
cond *sync.Cond // for broadcasting updates are available
mu sync.Mutex // protects lines and err
lines []string
count int // increment whenever new line gets added
err error
}
var printDebugLines = os.Getenv("EXPECT_DEBUG") != ""
// NewExpect creates a new process for expect testing.
func NewExpect(name string, arg ...string) (ep *ExpectProcess, err error) {
ep = &ExpectProcess{cmd: exec.Command(name, arg...)}
ep.cond = sync.NewCond(&ep.mu)
ep.cmd.Stderr = ep.cmd.Stdout
ep.cmd.Stdin = nil
if ep.fpty, err = pty.Start(ep.cmd); err != nil {
return nil, err
}
ep.wg.Add(1)
go ep.read()
return ep, nil
}
func (ep *ExpectProcess) read() {
defer ep.wg.Done()
r := bufio.NewReader(ep.fpty)
for ep.err == nil {
ep.ptyMu.Lock()
l, rerr := r.ReadString('\n')
ep.ptyMu.Unlock()
ep.mu.Lock()
ep.err = rerr
if l != "" {
if printDebugLines {
fmt.Printf("%s-%d: %s", ep.cmd.Path, ep.cmd.Process.Pid, l)
}
ep.lines = append(ep.lines, l)
ep.count++
if len(ep.lines) == 1 {
ep.cond.Signal()
}
}
ep.mu.Unlock()
}
ep.cond.Signal()
}
// ExpectFunc returns the first line satisfying the function f.
func (ep *ExpectProcess) ExpectFunc(f func(string) bool) (string, error) {
ep.mu.Lock()
for {
for len(ep.lines) == 0 && ep.err == nil {
ep.cond.Wait()
}
if len(ep.lines) == 0 {
break
}
l := ep.lines[0]
ep.lines = ep.lines[1:]
if f(l) {
ep.mu.Unlock()
return l, nil
}
}
ep.mu.Unlock()
return "", ep.err
}
// Expect returns the first line containing the given string.
func (ep *ExpectProcess) Expect(s string) (string, error) {
return ep.ExpectFunc(func(txt string) bool { return strings.Contains(txt, s) })
}
// LineCount returns the number of recorded lines since
// the beginning of the process.
func (ep *ExpectProcess) LineCount() int {
ep.mu.Lock()
defer ep.mu.Unlock()
return ep.count
}
// Stop kills the expect process and waits for it to exit.
func (ep *ExpectProcess) Stop() error { return ep.close(true) }
// Signal sends a signal to the expect process
func (ep *ExpectProcess) Signal(sig os.Signal) error {
return ep.cmd.Process.Signal(sig)
}
// Close waits for the expect process to exit.
func (ep *ExpectProcess) Close() error { return ep.close(false) }
func (ep *ExpectProcess) close(kill bool) error {
if ep.cmd == nil {
return ep.err
}
if kill {
ep.cmd.Process.Kill()
}
err := ep.cmd.Wait()
ep.ptyMu.Lock()
ep.fpty.Close()
ep.ptyMu.Unlock()
ep.wg.Wait()
if err != nil {
ep.err = err
if !kill && strings.Contains(err.Error(), "exit status") {
// non-zero exit code
err = nil
} else if kill && strings.Contains(err.Error(), "signal:") {
err = nil
}
}
ep.cmd = nil
return err
}
func (ep *ExpectProcess) Send(command string) error {
_, err := io.WriteString(ep.fpty, command)
return err
}

120
vendor/github.com/coreos/etcd/pkg/expect/expect_test.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
// 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 expect
import (
"os"
"testing"
"time"
)
func TestExpectFunc(t *testing.T) {
ep, err := NewExpect("/bin/echo", "hello world")
if err != nil {
t.Fatal(err)
}
wstr := "hello world\r\n"
l, eerr := ep.ExpectFunc(func(a string) bool { return len(a) > 10 })
if eerr != nil {
t.Fatal(eerr)
}
if l != wstr {
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
}
if cerr := ep.Close(); cerr != nil {
t.Fatal(cerr)
}
}
func TestEcho(t *testing.T) {
ep, err := NewExpect("/bin/echo", "hello world")
if err != nil {
t.Fatal(err)
}
l, eerr := ep.Expect("world")
if eerr != nil {
t.Fatal(eerr)
}
wstr := "hello world"
if l[:len(wstr)] != wstr {
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
}
if cerr := ep.Close(); cerr != nil {
t.Fatal(cerr)
}
if _, eerr = ep.Expect("..."); eerr == nil {
t.Fatalf("expected error on closed expect process")
}
}
func TestLineCount(t *testing.T) {
ep, err := NewExpect("/usr/bin/printf", "1\n2\n3")
if err != nil {
t.Fatal(err)
}
wstr := "3"
l, eerr := ep.Expect(wstr)
if eerr != nil {
t.Fatal(eerr)
}
if l != wstr {
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
}
if ep.LineCount() != 3 {
t.Fatalf("got %d, expected 3", ep.LineCount())
}
if cerr := ep.Close(); cerr != nil {
t.Fatal(cerr)
}
}
func TestSend(t *testing.T) {
ep, err := NewExpect("/usr/bin/tr", "a", "b")
if err != nil {
t.Fatal(err)
}
if err := ep.Send("a\r"); err != nil {
t.Fatal(err)
}
if _, err := ep.Expect("b"); err != nil {
t.Fatal(err)
}
if err := ep.Stop(); err != nil {
t.Fatal(err)
}
}
func TestSignal(t *testing.T) {
ep, err := NewExpect("/bin/sleep", "100")
if err != nil {
t.Fatal(err)
}
ep.Signal(os.Interrupt)
donec := make(chan struct{})
go func() {
defer close(donec)
werr := "signal: interrupt"
if cerr := ep.Close(); cerr == nil || cerr.Error() != werr {
t.Fatalf("got error %v, wanted error %s", cerr, werr)
}
}()
select {
case <-time.After(5 * time.Second):
t.Fatalf("signal test timed out")
case <-donec:
}
}

22
vendor/github.com/coreos/etcd/pkg/fileutil/dir_unix.go generated vendored Normal file
View file

@ -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) }

View file

@ -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)
}

121
vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go generated vendored Normal file
View file

@ -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 fileutil implements utility functions related to files and paths.
package fileutil
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"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("github.com/coreos/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)
}
// ReadDir returns the filenames in the given directory in sorted order.
func ReadDir(dirpath string) ([]string, error) {
dir, err := os.Open(dirpath)
if err != nil {
return nil, err
}
defer dir.Close()
names, err := dir.Readdirnames(-1)
if err != nil {
return nil, err
}
sort.Strings(names)
return names, nil
}
// 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
}
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, os.SEEK_CUR)
if err != nil {
return err
}
lenf, lerr := f.Seek(0, os.SEEK_END)
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, os.SEEK_SET)
return err
}

View file

@ -0,0 +1,159 @@
// 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/ioutil"
"os"
"os/user"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
)
func TestIsDirWriteable(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
defer os.RemoveAll(tmpdir)
if err = IsDirWriteable(tmpdir); err != nil {
t.Fatalf("unexpected IsDirWriteable error: %v", err)
}
if err = os.Chmod(tmpdir, 0444); err != nil {
t.Fatalf("unexpected os.Chmod error: %v", err)
}
me, err := user.Current()
if err != nil {
// err can be non-nil when cross compiled
// http://stackoverflow.com/questions/20609415/cross-compiling-user-current-not-implemented-on-linux-amd64
t.Skipf("failed to get current user: %v", err)
}
if me.Name == "root" || runtime.GOOS == "windows" {
// ideally we should check CAP_DAC_OVERRIDE.
// but it does not matter for tests.
// Chmod is not supported under windows.
t.Skipf("running as a superuser or in windows")
}
if err := IsDirWriteable(tmpdir); err == nil {
t.Fatalf("expected IsDirWriteable to error")
}
}
func TestReadDir(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
defer os.RemoveAll(tmpdir)
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
files := []string{"def", "abc", "xyz", "ghi"}
for _, f := range files {
var fh *os.File
fh, err = os.Create(filepath.Join(tmpdir, f))
if err != nil {
t.Fatalf("error creating file: %v", err)
}
if err = fh.Close(); err != nil {
t.Fatalf("error closing file: %v", err)
}
}
fs, err := ReadDir(tmpdir)
if err != nil {
t.Fatalf("error calling ReadDir: %v", err)
}
wfs := []string{"abc", "def", "ghi", "xyz"}
if !reflect.DeepEqual(fs, wfs) {
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
}
}
func TestCreateDirAll(t *testing.T) {
tmpdir, err := ioutil.TempDir(os.TempDir(), "foo")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
tmpdir2 := filepath.Join(tmpdir, "testdir")
if err = CreateDirAll(tmpdir2); err != nil {
t.Fatal(err)
}
if err = ioutil.WriteFile(filepath.Join(tmpdir2, "text.txt"), []byte("test text"), PrivateFileMode); err != nil {
t.Fatal(err)
}
if err = CreateDirAll(tmpdir2); err == nil || !strings.Contains(err.Error(), "to be empty, got") {
t.Fatalf("unexpected error %v", err)
}
}
func TestExist(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "fileutil")
if err != nil {
t.Fatal(err)
}
f.Close()
if g := Exist(f.Name()); !g {
t.Errorf("exist = %v, want true", g)
}
os.Remove(f.Name())
if g := Exist(f.Name()); g {
t.Errorf("exist = %v, want false", g)
}
}
func TestZeroToEnd(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "fileutil")
if err != nil {
t.Fatal(err)
}
defer f.Close()
b := make([]byte, 1024)
for i := range b {
b[i] = 12
}
if _, err = f.Write(b); err != nil {
t.Fatal(err)
}
if _, err = f.Seek(512, os.SEEK_SET); err != nil {
t.Fatal(err)
}
if err = ZeroToEnd(f); err != nil {
t.Fatal(err)
}
off, serr := f.Seek(0, os.SEEK_CUR)
if serr != nil {
t.Fatal(serr)
}
if off != 512 {
t.Fatalf("expected offset 512, got %d", off)
}
b = make([]byte, 512)
if _, err = f.Read(b); err != nil {
t.Fatal(err)
}
for i := range b {
if b[i] != 0 {
t.Errorf("expected b[%d] = 0, got %d", i, b[i])
}
}
}

26
vendor/github.com/coreos/etcd/pkg/fileutil/lock.go generated vendored Normal file
View file

@ -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 }

View file

@ -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
}

View file

@ -0,0 +1,96 @@
// 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"
)
// 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(os.SEEK_SET),
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, 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, err
}
flock := wrlck
err = syscall.FcntlFlock(f.Fd(), F_OFD_SETLKW, &flock)
if err != nil {
f.Close()
return nil, err
}
return &LockedFile{f}, err
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -0,0 +1,89 @@
// 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/ioutil"
"os"
"testing"
"time"
)
func TestLockAndUnlock(t *testing.T) {
f, err := ioutil.TempFile("", "lock")
if err != nil {
t.Fatal(err)
}
f.Close()
defer func() {
err = os.Remove(f.Name())
if err != nil {
t.Fatal(err)
}
}()
// lock the file
l, err := LockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
if err != nil {
t.Fatal(err)
}
// try lock a locked file
if _, err = TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode); err != ErrLocked {
t.Fatal(err)
}
// unlock the file
if err = l.Close(); err != nil {
t.Fatal(err)
}
// try lock the unlocked file
dupl, err := TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
if err != nil {
t.Errorf("err = %v, want %v", err, nil)
}
// blocking on locked file
locked := make(chan struct{}, 1)
go func() {
bl, blerr := LockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
if blerr != nil {
t.Fatal(blerr)
}
locked <- struct{}{}
if blerr = bl.Close(); blerr != nil {
t.Fatal(blerr)
}
}()
select {
case <-locked:
t.Error("unexpected unblocking")
case <-time.After(100 * time.Millisecond):
}
// unlock
if err = dupl.Close(); err != nil {
t.Fatal(err)
}
// the previously blocked routine should be unblocked
select {
case <-locked:
case <-time.After(1 * time.Second):
t.Error("unexpected blocking")
}
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -0,0 +1,47 @@
// 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"
// 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 extendFile {
return preallocExtend(f, sizeInBytes)
}
return preallocFixed(f, sizeInBytes)
}
func preallocExtendTrunc(f *os.File, sizeInBytes int64) error {
curOff, err := f.Seek(0, os.SEEK_CUR)
if err != nil {
return err
}
size, err := f.Seek(sizeInBytes, os.SEEK_END)
if err != nil {
return err
}
if _, err = f.Seek(curOff, os.SEEK_SET); err != nil {
return err
}
if sizeInBytes > size {
return nil
}
return f.Truncate(sizeInBytes)
}

View file

@ -0,0 +1,43 @@
// 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 {
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
}
return errno
}

View file

@ -0,0 +1,67 @@
// 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/ioutil"
"os"
"testing"
)
func TestPreallocateExtend(t *testing.T) { runPreallocTest(t, testPreallocateExtend) }
func testPreallocateExtend(t *testing.T, f *os.File) {
size := int64(64 * 1000)
if err := Preallocate(f, size, true); err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
if err != nil {
t.Fatal(err)
}
if stat.Size() != size {
t.Errorf("size = %d, want %d", stat.Size(), size)
}
}
func TestPreallocateFixed(t *testing.T) { runPreallocTest(t, testPreallocateFixed) }
func testPreallocateFixed(t *testing.T, f *os.File) {
size := int64(64 * 1000)
if err := Preallocate(f, size, false); err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
if err != nil {
t.Fatal(err)
}
if stat.Size() != 0 {
t.Errorf("size = %d, want %d", stat.Size(), 0)
}
}
func runPreallocTest(t *testing.T, test func(*testing.T, *os.File)) {
p, err := ioutil.TempDir(os.TempDir(), "preallocateTest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(p)
f, err := ioutil.TempFile(p, "")
if err != nil {
t.Fatal(err)
}
test(t, f)
}

View file

@ -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
}

View file

@ -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 }

78
vendor/github.com/coreos/etcd/pkg/fileutil/purge.go generated vendored Normal file
View file

@ -0,0 +1,78 @@
// 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"
)
func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
return purgeFile(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(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 {
plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err)
errC <- err
return
}
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
}

View file

@ -0,0 +1,177 @@
// 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/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"time"
)
func TestPurgeFile(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
// minimal file set
for i := 0; i < 3; i++ {
f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
if ferr != nil {
t.Fatal(err)
}
f.Close()
}
stop, purgec := make(chan struct{}), make(chan string, 10)
// keep 3 most recent files
errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec)
select {
case f := <-purgec:
t.Errorf("unexpected purge on %q", f)
case <-time.After(10 * time.Millisecond):
}
// rest of the files
for i := 4; i < 10; i++ {
go func(n int) {
f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", n)))
if ferr != nil {
t.Fatal(err)
}
f.Close()
}(i)
}
// watch files purge away
for i := 4; i < 10; i++ {
select {
case <-purgec:
case <-time.After(time.Second):
t.Errorf("purge took too long")
}
}
fnames, rerr := ReadDir(dir)
if rerr != nil {
t.Fatal(rerr)
}
wnames := []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
// no error should be reported from purge routine
select {
case f := <-purgec:
t.Errorf("unexpected purge on %q", f)
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(10 * time.Millisecond):
}
close(stop)
}
func TestPurgeFileHoldingLockFile(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for i := 0; i < 10; i++ {
var f *os.File
f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
f.Close()
}
// create a purge barrier at 5
p := filepath.Join(dir, fmt.Sprintf("%d.test", 5))
l, err := LockFile(p, os.O_WRONLY, PrivateFileMode)
if err != nil {
t.Fatal(err)
}
stop, purgec := make(chan struct{}), make(chan string, 10)
errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec)
for i := 0; i < 5; i++ {
select {
case <-purgec:
case <-time.After(time.Second):
t.Fatalf("purge took too long")
}
}
fnames, rerr := ReadDir(dir)
if rerr != nil {
t.Fatal(rerr)
}
wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case s := <-purgec:
t.Errorf("unexpected purge %q", s)
case err = <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(10 * time.Millisecond):
}
// remove the purge barrier
if err = l.Close(); err != nil {
t.Fatal(err)
}
// wait for rest of purges (5, 6)
for i := 0; i < 2; i++ {
select {
case <-purgec:
case <-time.After(time.Second):
t.Fatalf("purge took too long")
}
}
fnames, rerr = ReadDir(dir)
if rerr != nil {
t.Fatal(rerr)
}
wnames = []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case f := <-purgec:
t.Errorf("unexpected purge on %q", f)
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(10 * time.Millisecond):
}
close(stop)
}

29
vendor/github.com/coreos/etcd/pkg/fileutil/sync.go generated vendored Normal file
View file

@ -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()
}

View file

@ -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)
}

View file

@ -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()))
}

164
vendor/github.com/coreos/etcd/pkg/flags/flag.go generated vendored Normal file
View file

@ -0,0 +1,164 @@
// 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"
"net/url"
"os"
"strings"
"github.com/coreos/pkg/capnslog"
"github.com/spf13/pflag"
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/flags")
)
// DeprecatedFlag encapsulates a flag that may have been previously valid but
// is now deprecated. If a DeprecatedFlag is set, an error occurs.
type DeprecatedFlag struct {
Name string
}
func (f *DeprecatedFlag) Set(_ string) error {
return fmt.Errorf(`flag "-%s" is no longer supported.`, f.Name)
}
func (f *DeprecatedFlag) String() string {
return ""
}
// 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 ""
}
// 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) {
err = setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, true)
})
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
}
})
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.Infof("recognized environment variable %s, but unused: shadowed by corresponding flag ", kv[0])
continue
}
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
}
// 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))
}
func IsSet(fs *flag.FlagSet, name string) bool {
set := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
set = true
}
})
return set
}

78
vendor/github.com/coreos/etcd/pkg/flags/flag_test.go generated vendored Normal file
View file

@ -0,0 +1,78 @@
// 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"
"os"
"testing"
)
func TestSetFlagsFromEnv(t *testing.T) {
fs := flag.NewFlagSet("testing", flag.ExitOnError)
fs.String("a", "", "")
fs.String("b", "", "")
fs.String("c", "", "")
fs.Parse([]string{})
os.Clearenv()
// flags should be settable using env vars
os.Setenv("ETCD_A", "foo")
// and command-line flags
if err := fs.Set("b", "bar"); err != nil {
t.Fatal(err)
}
// command-line flags take precedence over env vars
os.Setenv("ETCD_C", "woof")
if err := fs.Set("c", "quack"); err != nil {
t.Fatal(err)
}
// first verify that flags are as expected before reading the env
for f, want := range map[string]string{
"a": "",
"b": "bar",
"c": "quack",
} {
if got := fs.Lookup(f).Value.String(); got != want {
t.Fatalf("flag %q=%q, want %q", f, got, want)
}
}
// now read the env and verify flags were updated as expected
err := SetFlagsFromEnv("ETCD", fs)
if err != nil {
t.Errorf("err=%v, want nil", err)
}
for f, want := range map[string]string{
"a": "foo",
"b": "bar",
"c": "quack",
} {
if got := fs.Lookup(f).Value.String(); got != want {
t.Errorf("flag %q=%q, want %q", f, got, want)
}
}
}
func TestSetFlagsFromEnvBad(t *testing.T) {
// now verify that an error is propagated
fs := flag.NewFlagSet("testing", flag.ExitOnError)
fs.Int("x", 0, "")
os.Setenv("ETCD_X", "not_a_number")
if err := SetFlagsFromEnv("ETCD", fs); err == nil {
t.Errorf("err=nil, want != nil")
}
}

46
vendor/github.com/coreos/etcd/pkg/flags/strings.go generated vendored Normal file
View file

@ -0,0 +1,46 @@
// 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 "errors"
// NewStringsFlag creates a new string flag for which any one of the given
// strings is a valid value, and any other value is an error.
func NewStringsFlag(valids ...string) *StringsFlag {
return &StringsFlag{Values: valids}
}
// StringsFlag implements the flag.Value interface.
type StringsFlag struct {
Values []string
val string
}
// Set verifies the argument to be a valid member of the allowed values
// before setting the underlying flag value.
func (ss *StringsFlag) Set(s string) error {
for _, v := range ss.Values {
if s == v {
ss.val = s
return nil
}
}
return errors.New("invalid value")
}
// String returns the set value (if any) of the StringsFlag
func (ss *StringsFlag) String() string {
return ss.val
}

View file

@ -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 flags
import (
"testing"
)
func TestStringsSet(t *testing.T) {
tests := []struct {
vals []string
val string
pass bool
}{
// known values
{[]string{"abc", "def"}, "abc", true},
{[]string{"on", "off", "false"}, "on", true},
// unrecognized values
{[]string{"abc", "def"}, "ghi", false},
{[]string{"on", "off"}, "", false},
{[]string{}, "asdf", false},
}
for i, tt := range tests {
sf := NewStringsFlag(tt.vals...)
err := sf.Set(tt.val)
if tt.pass != (err == nil) {
t.Errorf("#%d: want pass=%t, but got err=%v", i, tt.pass, err)
}
}
}

52
vendor/github.com/coreos/etcd/pkg/flags/urls.go generated vendored Normal file
View file

@ -0,0 +1,52 @@
// 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 (
"strings"
"github.com/coreos/etcd/pkg/types"
)
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
func (us *URLsValue) Set(s string) error {
strs := strings.Split(s, ",")
nus, err := types.NewURLs(strs)
if err != nil {
return err
}
*us = URLsValue(nus)
return nil
}
func (us *URLsValue) String() string {
all := make([]string, len(*us))
for i, u := range *us {
all[i] = u.String()
}
return strings.Join(all, ",")
}
func NewURLsValue(init string) *URLsValue {
v := &URLsValue{}
if err := v.Set(init); err != nil {
plog.Panicf("new URLsValue should never fail: %v", err)
}
return v
}

61
vendor/github.com/coreos/etcd/pkg/flags/urls_test.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
// 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 (
"testing"
)
func TestValidateURLsValueBad(t *testing.T) {
tests := []string{
// bad IP specification
":2379",
"127.0:8080",
"123:456",
// bad port specification
"127.0.0.1:foo",
"127.0.0.1:",
// unix sockets not supported
"unix://",
"unix://tmp/etcd.sock",
// bad strings
"somewhere",
"234#$",
"file://foo/bar",
"http://hello/asdf",
"http://10.1.1.1",
}
for i, in := range tests {
u := URLsValue{}
if err := u.Set(in); err == nil {
t.Errorf(`#%d: unexpected nil error for in=%q`, i, in)
}
}
}
func TestValidateURLsValueGood(t *testing.T) {
tests := []string{
"https://1.2.3.4:8080",
"http://10.1.1.1:80",
"http://localhost:80",
"http://:80",
}
for i, in := range tests {
u := URLsValue{}
if err := u.Set(in); err != nil {
t.Errorf("#%d: err=%v, want nil for in=%q", i, err, in)
}
}
}

31
vendor/github.com/coreos/etcd/pkg/httputil/httputil.go generated vendored Normal file
View file

@ -0,0 +1,31 @@
// 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.
// borrowed from golang/net/context/ctxhttp/cancelreq.go
// Package httputil provides HTTP utility functions.
package httputil
import (
"io"
"io/ioutil"
"net/http"
)
func RequestCanceler(req *http.Request) func() {
ch := make(chan struct{})
req.Cancel = ch
return func() {
close(ch)
}
}
// GracefulClose drains http.Response.Body until it hits EOF
// and closes it. This prevents TCP/TLS connections from closing,
// therefore available for reuse.
func GracefulClose(resp *http.Response) {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}

78
vendor/github.com/coreos/etcd/pkg/idutil/id.go generated vendored Normal file
View file

@ -0,0 +1,78 @@
// 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"
"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 byte is memberID, next 5 bytes are from timestamp,
// and low order 2 bytes are 0s.
// | 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 {
mu sync.Mutex
// 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 {
g.mu.Lock()
defer g.mu.Unlock()
g.suffix++
id := g.prefix | lowbit(g.suffix, suffixLen)
return id
}
func lowbit(x uint64, n uint) uint64 {
return x & (math.MaxUint64 >> (64 - n))
}

55
vendor/github.com/coreos/etcd/pkg/idutil/id_test.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
// 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
import (
"testing"
"time"
)
func TestNewGenerator(t *testing.T) {
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
id := g.Next()
wid := uint64(0x12000000345601)
if id != wid {
t.Errorf("id = %x, want %x", id, wid)
}
}
func TestNewGeneratorUnique(t *testing.T) {
g := NewGenerator(0, time.Time{})
id := g.Next()
// different server generates different ID
g1 := NewGenerator(1, time.Time{})
if gid := g1.Next(); id == gid {
t.Errorf("generate the same id %x using different server ID", id)
}
// restarted server generates different ID
g2 := NewGenerator(0, time.Now())
if gid := g2.Next(); id == gid {
t.Errorf("generate the same id %x after restart", id)
}
}
func TestNext(t *testing.T) {
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
wid := uint64(0x12000000345601)
for i := 0; i < 1000; i++ {
id := g.Next()
if id != wid+uint64(i) {
t.Errorf("id = %x, want %x", id, wid+uint64(i))
}
}
}

106
vendor/github.com/coreos/etcd/pkg/ioutil/pagewriter.go generated vendored Normal file
View file

@ -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
}

View file

@ -0,0 +1,129 @@
// 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 (
"math/rand"
"testing"
)
func TestPageWriterRandom(t *testing.T) {
// smaller buffer for stress testing
defaultBufferBytes = 8 * 1024
pageBytes := 128
buf := make([]byte, 4*defaultBufferBytes)
cw := &checkPageWriter{pageBytes: pageBytes, t: t}
w := NewPageWriter(cw, pageBytes, 0)
n := 0
for i := 0; i < 4096; i++ {
c, err := w.Write(buf[:rand.Intn(len(buf))])
if err != nil {
t.Fatal(err)
}
n += c
}
if cw.writeBytes > n {
t.Fatalf("wrote %d bytes to io.Writer, but only wrote %d bytes", cw.writeBytes, n)
}
if cw.writeBytes-n > pageBytes {
t.Fatalf("got %d bytes pending, expected less than %d bytes", cw.writeBytes-n, pageBytes)
}
t.Logf("total writes: %d", cw.writes)
t.Logf("total write bytes: %d (of %d)", cw.writeBytes, n)
}
// TestPageWriterPariallack tests the case where a write overflows the buffer
// but there is not enough data to complete the slack write.
func TestPageWriterPartialSlack(t *testing.T) {
defaultBufferBytes = 1024
pageBytes := 128
buf := make([]byte, defaultBufferBytes)
cw := &checkPageWriter{pageBytes: 64, t: t}
w := NewPageWriter(cw, pageBytes, 0)
// put writer in non-zero page offset
if _, err := w.Write(buf[:64]); err != nil {
t.Fatal(err)
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
if cw.writes != 1 {
t.Fatalf("got %d writes, expected 1", cw.writes)
}
// nearly fill buffer
if _, err := w.Write(buf[:1022]); err != nil {
t.Fatal(err)
}
// overflow buffer, but without enough to write as aligned
if _, err := w.Write(buf[:8]); err != nil {
t.Fatal(err)
}
if cw.writes != 1 {
t.Fatalf("got %d writes, expected 1", cw.writes)
}
// finish writing slack space
if _, err := w.Write(buf[:128]); err != nil {
t.Fatal(err)
}
if cw.writes != 2 {
t.Fatalf("got %d writes, expected 2", cw.writes)
}
}
// TestPageWriterOffset tests if page writer correctly repositions when offset is given.
func TestPageWriterOffset(t *testing.T) {
defaultBufferBytes = 1024
pageBytes := 128
buf := make([]byte, defaultBufferBytes)
cw := &checkPageWriter{pageBytes: 64, t: t}
w := NewPageWriter(cw, pageBytes, 0)
if _, err := w.Write(buf[:64]); err != nil {
t.Fatal(err)
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
if w.pageOffset != 64 {
t.Fatalf("w.pageOffset expected 64, got %d", w.pageOffset)
}
w = NewPageWriter(cw, w.pageOffset, pageBytes)
if _, err := w.Write(buf[:64]); err != nil {
t.Fatal(err)
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
if w.pageOffset != 0 {
t.Fatalf("w.pageOffset expected 0, got %d", w.pageOffset)
}
}
// checkPageWriter implements an io.Writer that fails a test on unaligned writes.
type checkPageWriter struct {
pageBytes int
writes int
writeBytes int
t *testing.T
}
func (cw *checkPageWriter) Write(p []byte) (int, error) {
if len(p)%cw.pageBytes != 0 {
cw.t.Fatalf("got write len(p) = %d, expected len(p) == k*cw.pageBytes", len(p))
}
cw.writes++
cw.writeBytes += len(p)
return len(p), nil
}

66
vendor/github.com/coreos/etcd/pkg/ioutil/readcloser.go generated vendored Normal file
View file

@ -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
}

View file

@ -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.
package ioutil
import (
"bytes"
"io"
"testing"
)
type readerNilCloser struct{ io.Reader }
func (rc *readerNilCloser) Close() error { return nil }
// TestExactReadCloserExpectEOF expects an eof when reading too much.
func TestExactReadCloserExpectEOF(t *testing.T) {
buf := bytes.NewBuffer(make([]byte, 10))
rc := NewExactReadCloser(&readerNilCloser{buf}, 1)
if _, err := rc.Read(make([]byte, 10)); err != ErrExpectEOF {
t.Fatalf("expected %v, got %v", ErrExpectEOF, err)
}
}
// TestExactReadCloserShort expects an eof when reading too little
func TestExactReadCloserShort(t *testing.T) {
buf := bytes.NewBuffer(make([]byte, 5))
rc := NewExactReadCloser(&readerNilCloser{buf}, 10)
if _, err := rc.Read(make([]byte, 10)); err != nil {
t.Fatalf("Read expected nil err, got %v", err)
}
if err := rc.Close(); err != ErrShortRead {
t.Fatalf("Close expected %v, got %v", ErrShortRead, err)
}
}

40
vendor/github.com/coreos/etcd/pkg/ioutil/reader.go generated vendored Normal file
View file

@ -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)
}

View file

@ -0,0 +1,33 @@
// 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 (
"bytes"
"testing"
)
func TestLimitedBufferReaderRead(t *testing.T) {
buf := bytes.NewBuffer(make([]byte, 10))
ln := 1
lr := NewLimitedBufferReader(buf, ln)
n, err := lr.Read(make([]byte, 10))
if err != nil {
t.Fatalf("unexpected read error: %v", err)
}
if n != ln {
t.Errorf("len(data read) = %d, want %d", n, ln)
}
}

43
vendor/github.com/coreos/etcd/pkg/ioutil/util.go generated vendored Normal file
View file

@ -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"
"github.com/coreos/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
}

View file

@ -0,0 +1,195 @@
// 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 logutil includes utilities to facilitate logging.
package logutil
import (
"fmt"
"sync"
"time"
"github.com/coreos/pkg/capnslog"
)
var (
defaultMergePeriod = time.Second
defaultTimeOutputScale = 10 * time.Millisecond
outputInterval = time.Second
)
// line represents a log line that can be printed out
// through capnslog.PackageLogger.
type line struct {
level capnslog.LogLevel
str string
}
func (l line) append(s string) line {
return line{
level: l.level,
str: l.str + " " + s,
}
}
// status represents the merge status of a line.
type status struct {
period time.Duration
start time.Time // start time of latest merge period
count int // number of merged lines from starting
}
func (s *status) isInMergePeriod(now time.Time) bool {
return s.period == 0 || s.start.Add(s.period).After(now)
}
func (s *status) isEmpty() bool { return s.count == 0 }
func (s *status) summary(now time.Time) string {
ts := s.start.Round(defaultTimeOutputScale)
took := now.Round(defaultTimeOutputScale).Sub(ts)
return fmt.Sprintf("[merged %d repeated lines in %s]", s.count, took)
}
func (s *status) reset(now time.Time) {
s.start = now
s.count = 0
}
// MergeLogger supports merge logging, which merges repeated log lines
// and prints summary log lines instead.
//
// For merge logging, MergeLogger prints out the line when the line appears
// at the first time. MergeLogger holds the same log line printed within
// defaultMergePeriod, and prints out summary log line at the end of defaultMergePeriod.
// It stops merging when the line doesn't appear within the
// defaultMergePeriod.
type MergeLogger struct {
*capnslog.PackageLogger
mu sync.Mutex // protect statusm
statusm map[line]*status
}
func NewMergeLogger(logger *capnslog.PackageLogger) *MergeLogger {
l := &MergeLogger{
PackageLogger: logger,
statusm: make(map[line]*status),
}
go l.outputLoop()
return l
}
func (l *MergeLogger) MergeInfo(entries ...interface{}) {
l.merge(line{
level: capnslog.INFO,
str: fmt.Sprint(entries...),
})
}
func (l *MergeLogger) MergeInfof(format string, args ...interface{}) {
l.merge(line{
level: capnslog.INFO,
str: fmt.Sprintf(format, args...),
})
}
func (l *MergeLogger) MergeNotice(entries ...interface{}) {
l.merge(line{
level: capnslog.NOTICE,
str: fmt.Sprint(entries...),
})
}
func (l *MergeLogger) MergeNoticef(format string, args ...interface{}) {
l.merge(line{
level: capnslog.NOTICE,
str: fmt.Sprintf(format, args...),
})
}
func (l *MergeLogger) MergeWarning(entries ...interface{}) {
l.merge(line{
level: capnslog.WARNING,
str: fmt.Sprint(entries...),
})
}
func (l *MergeLogger) MergeWarningf(format string, args ...interface{}) {
l.merge(line{
level: capnslog.WARNING,
str: fmt.Sprintf(format, args...),
})
}
func (l *MergeLogger) MergeError(entries ...interface{}) {
l.merge(line{
level: capnslog.ERROR,
str: fmt.Sprint(entries...),
})
}
func (l *MergeLogger) MergeErrorf(format string, args ...interface{}) {
l.merge(line{
level: capnslog.ERROR,
str: fmt.Sprintf(format, args...),
})
}
func (l *MergeLogger) merge(ln line) {
l.mu.Lock()
// increase count if the logger is merging the line
if status, ok := l.statusm[ln]; ok {
status.count++
l.mu.Unlock()
return
}
// initialize status of the line
l.statusm[ln] = &status{
period: defaultMergePeriod,
start: time.Now(),
}
// release the lock before IO operation
l.mu.Unlock()
// print out the line at its first time
l.PackageLogger.Logf(ln.level, ln.str)
}
func (l *MergeLogger) outputLoop() {
for now := range time.Tick(outputInterval) {
var outputs []line
l.mu.Lock()
for ln, status := range l.statusm {
if status.isInMergePeriod(now) {
continue
}
if status.isEmpty() {
delete(l.statusm, ln)
continue
}
outputs = append(outputs, ln.append(status.summary(now)))
status.reset(now)
}
l.mu.Unlock()
for _, o := range outputs {
l.PackageLogger.Logf(o.level, o.str)
}
}
}

View file

@ -0,0 +1,71 @@
// 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 logutil
import (
"fmt"
"strings"
"testing"
"time"
"github.com/coreos/pkg/capnslog"
)
var (
testLogger = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/logutil")
)
func TestMergeLogger(t *testing.T) {
var (
txt = "hello"
repeatN = 6
duration = 2049843762 * time.Nanosecond
mg = NewMergeLogger(testLogger)
)
// overwrite this for testing
defaultMergePeriod = time.Minute
for i := 0; i < repeatN; i++ {
mg.MergeError(txt)
if i == 0 {
time.Sleep(duration)
}
}
if len(mg.statusm) != 1 {
t.Errorf("got = %d, want = %d", len(mg.statusm), 1)
}
var l line
for k := range mg.statusm {
l = k
break
}
if l.level != capnslog.ERROR {
t.Errorf("got = %v, want = %v", l.level, capnslog.DEBUG)
}
if l.str != txt {
t.Errorf("got = %s, want = %s", l.str, txt)
}
if mg.statusm[l].count != repeatN-1 {
t.Errorf("got = %d, want = %d", mg.statusm[l].count, repeatN-1)
}
sum := mg.statusm[l].summary(time.Now())
pre := fmt.Sprintf("[merged %d repeated lines in ", repeatN-1)
if !strings.HasPrefix(sum, pre) {
t.Errorf("got = %s, want = %s...", sum, pre)
}
}

View file

@ -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 mockstorage provides mock implementations for etcdserver's storage interface.
package mockstorage

View file

@ -0,0 +1,59 @@
// 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 mockstorage
import (
"fmt"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/raft"
"github.com/coreos/etcd/raft/raftpb"
)
type storageRecorder struct {
testutil.Recorder
dbPath string // must have '/' suffix if set
}
func NewStorageRecorder(db string) *storageRecorder {
return &storageRecorder{&testutil.RecorderBuffered{}, db}
}
func NewStorageRecorderStream(db string) *storageRecorder {
return &storageRecorder{testutil.NewRecorderStream(), db}
}
func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) error {
p.Record(testutil.Action{Name: "Save"})
return nil
}
func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) error {
if !raft.IsEmptySnap(st) {
p.Record(testutil.Action{Name: "SaveSnap"})
}
return nil
}
func (p *storageRecorder) DBFilePath(id uint64) (string, error) {
p.Record(testutil.Action{Name: "DBFilePath"})
path := p.dbPath
if path != "" {
path = path + "/"
}
return fmt.Sprintf("%s%016x.snap.db", path, id), nil
}
func (p *storageRecorder) Close() error { return nil }

View file

@ -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 mockstore provides mock structures for the etcd store package.
package mockstore

View file

@ -0,0 +1,157 @@
// 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 mockstore
import (
"time"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/store"
)
// StoreRecorder provides a Store interface with a testutil.Recorder
type StoreRecorder struct {
store.Store
testutil.Recorder
}
// storeRecorder records all the methods it receives.
// storeRecorder DOES NOT work as a actual store.
// It always returns invalid empty response and no error.
type storeRecorder struct {
store.Store
testutil.Recorder
}
func NewNop() store.Store { return &storeRecorder{Recorder: &testutil.RecorderBuffered{}} }
func NewRecorder() *StoreRecorder {
sr := &storeRecorder{Recorder: &testutil.RecorderBuffered{}}
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
}
func NewRecorderStream() *StoreRecorder {
sr := &storeRecorder{Recorder: testutil.NewRecorderStream()}
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
}
func (s *storeRecorder) Version() int { return 0 }
func (s *storeRecorder) Index() uint64 { return 0 }
func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
s.Record(testutil.Action{
Name: "Get",
Params: []interface{}{path, recursive, sorted},
})
return &store.Event{}, nil
}
func (s *storeRecorder) Set(path string, dir bool, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
s.Record(testutil.Action{
Name: "Set",
Params: []interface{}{path, dir, val, expireOpts},
})
return &store.Event{}, nil
}
func (s *storeRecorder) Update(path, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
s.Record(testutil.Action{
Name: "Update",
Params: []interface{}{path, val, expireOpts},
})
return &store.Event{}, nil
}
func (s *storeRecorder) Create(path string, dir bool, val string, uniq bool, expireOpts store.TTLOptionSet) (*store.Event, error) {
s.Record(testutil.Action{
Name: "Create",
Params: []interface{}{path, dir, val, uniq, expireOpts},
})
return &store.Event{}, nil
}
func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
s.Record(testutil.Action{
Name: "CompareAndSwap",
Params: []interface{}{path, prevVal, prevIdx, val, expireOpts},
})
return &store.Event{}, nil
}
func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) {
s.Record(testutil.Action{
Name: "Delete",
Params: []interface{}{path, dir, recursive},
})
return &store.Event{}, nil
}
func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) {
s.Record(testutil.Action{
Name: "CompareAndDelete",
Params: []interface{}{path, prevVal, prevIdx},
})
return &store.Event{}, nil
}
func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) {
s.Record(testutil.Action{Name: "Watch"})
return store.NewNopWatcher(), nil
}
func (s *storeRecorder) Save() ([]byte, error) {
s.Record(testutil.Action{Name: "Save"})
return nil, nil
}
func (s *storeRecorder) Recovery(b []byte) error {
s.Record(testutil.Action{Name: "Recovery"})
return nil
}
func (s *storeRecorder) SaveNoCopy() ([]byte, error) {
s.Record(testutil.Action{Name: "SaveNoCopy"})
return nil, nil
}
func (s *storeRecorder) Clone() store.Store {
s.Record(testutil.Action{Name: "Clone"})
return s
}
func (s *storeRecorder) JsonStats() []byte { return nil }
func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) {
s.Record(testutil.Action{
Name: "DeleteExpiredKeys",
Params: []interface{}{cutoff},
})
}
func (s *storeRecorder) HasTTLKeys() bool {
s.Record(testutil.Action{
Name: "HasTTLKeys",
})
return true
}
// errStoreRecorder is a storeRecorder, but returns the given error on
// Get, Watch methods.
type errStoreRecorder struct {
storeRecorder
err error
}
func NewErrRecorder(err error) *StoreRecorder {
sr := &errStoreRecorder{err: err}
sr.Recorder = &testutil.RecorderBuffered{}
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
}
func (s *errStoreRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
s.storeRecorder.Get(path, recursive, sorted)
return nil, s.err
}
func (s *errStoreRecorder) Watch(path string, recursive, sorted bool, index uint64) (store.Watcher, error) {
s.storeRecorder.Watch(path, recursive, sorted, index)
return nil, s.err
}

16
vendor/github.com/coreos/etcd/pkg/mock/mockwait/doc.go generated vendored Normal file
View file

@ -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 mockwait provides mock implementations for pkg/wait.
package mockwait

View file

@ -0,0 +1,47 @@
// 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 mockwait
import (
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/pkg/wait"
)
type WaitRecorder struct {
wait.Wait
testutil.Recorder
}
type waitRecorder struct {
testutil.RecorderBuffered
}
func NewRecorder() *WaitRecorder {
wr := &waitRecorder{}
return &WaitRecorder{Wait: wr, Recorder: wr}
}
func NewNop() wait.Wait { return NewRecorder() }
func (w *waitRecorder) Register(id uint64) <-chan interface{} {
w.Record(testutil.Action{Name: "Register"})
return nil
}
func (w *waitRecorder) Trigger(id uint64, x interface{}) {
w.Record(testutil.Action{Name: "Trigger"})
}
func (w *waitRecorder) IsRegistered(id uint64) bool {
panic("waitRecorder.IsRegistered() shouldn't be called")
}

View file

@ -0,0 +1,6 @@
// Copyright (C) 2016 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
// This file is intentionally empty.
// It's a workaround for https://github.com/golang/go/issues/15006

26
vendor/github.com/coreos/etcd/pkg/monotime/monotime.go generated vendored Normal file
View file

@ -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 monotime
import (
"time"
)
// Time represents a point in monotonic time
type Time uint64
func (t Time) Add(d time.Duration) Time {
return Time(uint64(t) + uint64(d.Nanoseconds()))
}

24
vendor/github.com/coreos/etcd/pkg/monotime/nanotime.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
// Copyright (C) 2016 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
// Package monotime provides a fast monotonic clock source.
package monotime
import (
_ "unsafe" // required to use //go:linkname
)
//go:noescape
//go:linkname nanotime runtime.nanotime
func nanotime() int64
// Now returns the current time in nanoseconds from a monotonic clock.
// The time returned is based on some arbitrary platform-specific point in the
// past. The time returned is guaranteed to increase monotonically at a
// constant rate, unlike time.Now() from the Go standard library, which may
// slow down, speed up, jump forward or backward, due to NTP activity or leap
// seconds.
func Now() Time {
return Time(nanotime())
}

View file

@ -0,0 +1,22 @@
// Copyright (C) 2016 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// Package monotime provides a fast monotonic clock source.
package monotime
import (
"testing"
)
func TestNow(t *testing.T) {
for i := 0; i < 100; i++ {
t1 := Now()
t2 := Now()
// I honestly thought that we needed >= here, but in some environments
// two consecutive calls can return the same value!
if t1 > t2 {
t.Fatalf("t1=%d should have been less than or equal to t2=%d", t1, t2)
}
}
}

View file

@ -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
}

View file

@ -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 }

143
vendor/github.com/coreos/etcd/pkg/netutil/netutil.go generated vendored Normal file
View file

@ -0,0 +1,143 @@
// 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 implements network-related utility functions.
package netutil
import (
"net"
"net/url"
"reflect"
"sort"
"time"
"golang.org/x/net/context"
"github.com/coreos/etcd/pkg/types"
"github.com/coreos/pkg/capnslog"
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/netutil")
// indirection for testing
resolveTCPAddr = net.ResolveTCPAddr
)
const retryInterval = time.Second
// 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, 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, err
}
nus[i] = *nu
}
for i, u := range nus {
h, err := resolveURL(ctx, u)
if err != nil {
return nil, err
}
if h != "" {
nus[i].Host = h
}
}
newurls = append(newurls, nus)
}
return newurls, nil
}
func resolveURL(ctx context.Context, u url.URL) (string, error) {
for ctx.Err() == nil {
host, _, err := net.SplitHostPort(u.Host)
if err != nil {
plog.Errorf("could not parse url %s during tcp resolving", u.Host)
return "", err
}
if host == "localhost" || net.ParseIP(host) != nil {
return "", nil
}
tcpAddr, err := resolveTCPAddr("tcp", u.Host)
if err == nil {
plog.Infof("resolving %s to %s", u.Host, tcpAddr.String())
return tcpAddr.String(), nil
}
plog.Warningf("failed resolving host %s (%v); retrying in %v", u.Host, err, retryInterval)
select {
case <-ctx.Done():
plog.Errorf("could not resolve host %s", u.Host)
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, a []url.URL, b []url.URL) bool {
if len(a) != len(b) {
return false
}
urls, err := resolveTCPAddrs(ctx, [][]url.URL{a, b})
if err != nil {
return false
}
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
}
}
return true
}
func URLStringsEqual(ctx context.Context, a []string, b []string) bool {
if len(a) != len(b) {
return false
}
urlsA := make([]url.URL, 0)
for _, str := range a {
u, err := url.Parse(str)
if err != nil {
return false
}
urlsA = append(urlsA, *u)
}
urlsB := make([]url.URL, 0)
for _, str := range b {
u, err := url.Parse(str)
if err != nil {
return false
}
urlsB = append(urlsB, *u)
}
return urlsEqual(ctx, urlsA, urlsB)
}
func IsNetworkTimeoutError(err error) bool {
nerr, ok := err.(net.Error)
return ok && nerr.Timeout()
}

View file

@ -0,0 +1,263 @@
// 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 (
"errors"
"net"
"net/url"
"reflect"
"strconv"
"testing"
"time"
"golang.org/x/net/context"
)
func TestResolveTCPAddrs(t *testing.T) {
defer func() { resolveTCPAddr = net.ResolveTCPAddr }()
tests := []struct {
urls [][]url.URL
expected [][]url.URL
hostMap map[string]string
hasError bool
}{
{
urls: [][]url.URL{
{
{Scheme: "http", Host: "127.0.0.1:4001"},
{Scheme: "http", Host: "127.0.0.1:2379"},
},
{
{Scheme: "http", Host: "127.0.0.1:7001"},
{Scheme: "http", Host: "127.0.0.1:2380"},
},
},
expected: [][]url.URL{
{
{Scheme: "http", Host: "127.0.0.1:4001"},
{Scheme: "http", Host: "127.0.0.1:2379"},
},
{
{Scheme: "http", Host: "127.0.0.1:7001"},
{Scheme: "http", Host: "127.0.0.1:2380"},
},
},
},
{
urls: [][]url.URL{
{
{Scheme: "http", Host: "infra0.example.com:4001"},
{Scheme: "http", Host: "infra0.example.com:2379"},
},
{
{Scheme: "http", Host: "infra0.example.com:7001"},
{Scheme: "http", Host: "infra0.example.com:2380"},
},
},
expected: [][]url.URL{
{
{Scheme: "http", Host: "10.0.1.10:4001"},
{Scheme: "http", Host: "10.0.1.10:2379"},
},
{
{Scheme: "http", Host: "10.0.1.10:7001"},
{Scheme: "http", Host: "10.0.1.10:2380"},
},
},
hostMap: map[string]string{
"infra0.example.com": "10.0.1.10",
},
hasError: false,
},
{
urls: [][]url.URL{
{
{Scheme: "http", Host: "infra0.example.com:4001"},
{Scheme: "http", Host: "infra0.example.com:2379"},
},
{
{Scheme: "http", Host: "infra0.example.com:7001"},
{Scheme: "http", Host: "infra0.example.com:2380"},
},
},
hostMap: map[string]string{
"infra0.example.com": "",
},
hasError: true,
},
{
urls: [][]url.URL{
{
{Scheme: "http", Host: "ssh://infra0.example.com:4001"},
{Scheme: "http", Host: "ssh://infra0.example.com:2379"},
},
{
{Scheme: "http", Host: "ssh://infra0.example.com:7001"},
{Scheme: "http", Host: "ssh://infra0.example.com:2380"},
},
},
hasError: true,
},
}
for _, tt := range tests {
resolveTCPAddr = func(network, addr string) (*net.TCPAddr, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
if tt.hostMap[host] == "" {
return nil, errors.New("cannot resolve host.")
}
i, err := strconv.Atoi(port)
if err != nil {
return nil, err
}
return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
}
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
urls, err := resolveTCPAddrs(ctx, tt.urls)
cancel()
if tt.hasError {
if err == nil {
t.Errorf("expected error")
}
continue
}
if !reflect.DeepEqual(urls, tt.expected) {
t.Errorf("expected: %v, got %v", tt.expected, urls)
}
}
}
func TestURLsEqual(t *testing.T) {
defer func() { resolveTCPAddr = net.ResolveTCPAddr }()
hostm := map[string]string{
"example.com": "10.0.10.1",
"first.com": "10.0.11.1",
"second.com": "10.0.11.2",
}
resolveTCPAddr = func(network, addr string) (*net.TCPAddr, error) {
host, port, err := net.SplitHostPort(addr)
if _, ok := hostm[host]; !ok {
return nil, errors.New("cannot resolve host.")
}
i, err := strconv.Atoi(port)
if err != nil {
return nil, err
}
return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
}
tests := []struct {
a []url.URL
b []url.URL
expect bool
}{
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false,
},
{
a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
expect: true,
},
{
a: []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
expect: true,
},
}
for _, test := range tests {
result := urlsEqual(context.TODO(), test.a, test.b)
if result != test.expect {
t.Errorf("a:%v b:%v, expected %v but %v", test.a, test.b, test.expect, result)
}
}
}
func TestURLStringsEqual(t *testing.T) {
result := URLStringsEqual(context.TODO(), []string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"})
if !result {
t.Errorf("unexpected result %v", result)
}
}

33
vendor/github.com/coreos/etcd/pkg/netutil/routes.go generated vendored Normal file
View file

@ -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)
}

View file

@ -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"
"github.com/coreos/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
}

View file

@ -0,0 +1,35 @@
// 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 "testing"
func TestGetDefaultInterface(t *testing.T) {
ifc, err := GetDefaultInterfaces()
if err != nil {
t.Fatal(err)
}
t.Logf("default network interfaces: %+v\n", ifc)
}
func TestGetDefaultHost(t *testing.T) {
ip, err := GetDefaultHost()
if err != nil {
t.Fatal(err)
}
t.Logf("default ip: %v", ip)
}

View file

@ -0,0 +1,79 @@
// 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
package osutil
import (
"os"
"os/signal"
"sync"
"syscall"
)
// InterruptHandler is a function that is called on receiving a
// SIGTERM or SIGINT signal.
type InterruptHandler func()
var (
interruptRegisterMu, interruptExitMu sync.Mutex
// interruptHandlers holds all registered InterruptHandlers in order
// they will be executed.
interruptHandlers = []InterruptHandler{}
)
// RegisterInterruptHandler registers a new InterruptHandler. Handlers registered
// after interrupt handing was initiated will not be executed.
func RegisterInterruptHandler(h InterruptHandler) {
interruptRegisterMu.Lock()
defer interruptRegisterMu.Unlock()
interruptHandlers = append(interruptHandlers, h)
}
// HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM.
func HandleInterrupts() {
notifier := make(chan os.Signal, 1)
signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-notifier
interruptRegisterMu.Lock()
ihs := make([]InterruptHandler, len(interruptHandlers))
copy(ihs, interruptHandlers)
interruptRegisterMu.Unlock()
interruptExitMu.Lock()
plog.Noticef("received %v signal, shutting down...", sig)
for _, h := range ihs {
h()
}
signal.Stop(notifier)
pid := syscall.Getpid()
// exit directly if it is the "init" process, since the kernel will not help to kill pid 1.
if pid == 1 {
os.Exit(0)
}
syscall.Kill(pid, sig.(syscall.Signal))
}()
}
// Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise.
func Exit(code int) {
interruptExitMu.Lock()
os.Exit(code)
}

View file

@ -0,0 +1,32 @@
// 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 osutil
import "os"
type InterruptHandler func()
// RegisterInterruptHandler is a no-op on windows
func RegisterInterruptHandler(h InterruptHandler) {}
// HandleInterrupts is a no-op on windows
func HandleInterrupts() {}
// Exit calls os.Exit
func Exit(code int) {
os.Exit(code)
}

42
vendor/github.com/coreos/etcd/pkg/osutil/osutil.go generated vendored Normal file
View file

@ -0,0 +1,42 @@
// 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 osutil implements operating system-related utility functions.
package osutil
import (
"os"
"strings"
"github.com/coreos/pkg/capnslog"
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/osutil")
)
func Unsetenv(key string) error {
envs := os.Environ()
os.Clearenv()
for _, e := range envs {
strs := strings.SplitN(e, "=", 2)
if strs[0] == key {
continue
}
if err := os.Setenv(strs[0], strs[1]); err != nil {
return err
}
}
return nil
}

View file

@ -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 osutil
import (
"os"
"os/signal"
"reflect"
"syscall"
"testing"
"time"
)
func TestUnsetenv(t *testing.T) {
tests := []string{
"data",
"space data",
"equal=data",
}
for i, tt := range tests {
key := "ETCD_UNSETENV_TEST"
if os.Getenv(key) != "" {
t.Fatalf("#%d: cannot get empty %s", i, key)
}
env := os.Environ()
if err := os.Setenv(key, tt); err != nil {
t.Fatalf("#%d: cannot set %s: %v", i, key, err)
}
if err := Unsetenv(key); err != nil {
t.Errorf("#%d: unsetenv %s error: %v", i, key, err)
}
if g := os.Environ(); !reflect.DeepEqual(g, env) {
t.Errorf("#%d: env = %+v, want %+v", i, g, env)
}
}
}
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
select {
case s := <-c:
if s != sig {
t.Fatalf("signal was %v, want %v", s, sig)
}
case <-time.After(1 * time.Second):
t.Fatalf("timeout waiting for %v", sig)
}
}
func TestHandleInterrupts(t *testing.T) {
for _, sig := range []syscall.Signal{syscall.SIGINT, syscall.SIGTERM} {
n := 1
RegisterInterruptHandler(func() { n++ })
RegisterInterruptHandler(func() { n *= 2 })
c := make(chan os.Signal, 2)
signal.Notify(c, sig)
HandleInterrupts()
syscall.Kill(syscall.Getpid(), sig)
// we should receive the signal once from our own kill and
// a second time from HandleInterrupts
waitSig(t, c, sig)
waitSig(t, c, sig)
if n == 3 {
t.Fatalf("interrupt handlers were called in wrong order")
}
if n != 4 {
t.Fatalf("interrupt handlers were not called properly")
}
// reset interrupt handlers
interruptHandlers = interruptHandlers[:0]
interruptExitMu.Unlock()
}
}

31
vendor/github.com/coreos/etcd/pkg/pathutil/path.go generated vendored Normal file
View file

@ -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
}

View file

@ -0,0 +1,38 @@
// 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 pathutil
import "testing"
func TestCanonicalURLPath(t *testing.T) {
tests := []struct {
p string
wp string
}{
{"/a", "/a"},
{"", "/"},
{"a", "/a"},
{"//a", "/a"},
{"/a/.", "/a"},
{"/a/..", "/"},
{"/a/", "/a/"},
{"/a//", "/a/"},
}
for i, tt := range tests {
if g := CanonicalURLPath(tt.p); g != tt.wp {
t.Errorf("#%d: canonical path = %s, want %s", i, g, tt.wp)
}
}
}

60
vendor/github.com/coreos/etcd/pkg/pbutil/pbutil.go generated vendored Normal file
View file

@ -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("github.com/coreos/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 }

View file

@ -0,0 +1,98 @@
// 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
import (
"errors"
"reflect"
"testing"
)
func TestMarshaler(t *testing.T) {
data := []byte("test data")
m := &fakeMarshaler{data: data}
if g := MustMarshal(m); !reflect.DeepEqual(g, data) {
t.Errorf("data = %s, want %s", g, m)
}
}
func TestMarshalerPanic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("recover = nil, want error")
}
}()
m := &fakeMarshaler{err: errors.New("blah")}
MustMarshal(m)
}
func TestUnmarshaler(t *testing.T) {
data := []byte("test data")
m := &fakeUnmarshaler{}
MustUnmarshal(m, data)
if !reflect.DeepEqual(m.data, data) {
t.Errorf("data = %s, want %s", m.data, m)
}
}
func TestUnmarshalerPanic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("recover = nil, want error")
}
}()
m := &fakeUnmarshaler{err: errors.New("blah")}
MustUnmarshal(m, nil)
}
func TestGetBool(t *testing.T) {
tests := []struct {
b *bool
wb bool
wset bool
}{
{nil, false, false},
{Boolp(true), true, true},
{Boolp(false), false, true},
}
for i, tt := range tests {
b, set := GetBool(tt.b)
if b != tt.wb {
t.Errorf("#%d: value = %v, want %v", i, b, tt.wb)
}
if set != tt.wset {
t.Errorf("#%d: set = %v, want %v", i, set, tt.wset)
}
}
}
type fakeMarshaler struct {
data []byte
err error
}
func (m *fakeMarshaler) Marshal() ([]byte, error) {
return m.data, m.err
}
type fakeUnmarshaler struct {
data []byte
err error
}
func (m *fakeUnmarshaler) Unmarshal(data []byte) error {
m.data = data
return m.err
}

16
vendor/github.com/coreos/etcd/pkg/report/doc.go generated vendored Normal file
View file

@ -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 report generates human-readable benchmark reports.
package report

288
vendor/github.com/coreos/etcd/pkg/report/report.go generated vendored Normal file
View file

@ -0,0 +1,288 @@
// Copyright 2014 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.
// the file is borrowed from github.com/rakyll/boom/boomer/print.go
package report
import (
"fmt"
"math"
"sort"
"strings"
"time"
)
const (
barChar = "∎"
)
// Result describes the timings for an operation.
type Result struct {
Start time.Time
End time.Time
Err error
}
func (res *Result) Duration() time.Duration { return res.End.Sub(res.Start) }
type report struct {
results chan Result
precision string
avgTotal float64
fastest float64
slowest float64
average float64
stddev float64
rps float64
total time.Duration
errorDist map[string]int
lats []float64
sps *secondPoints
}
// Stats exposes results raw data.
type Stats struct {
AvgTotal float64
Fastest float64
Slowest float64
Average float64
Stddev float64
RPS float64
Total time.Duration
ErrorDist map[string]int
Lats []float64
TimeSeries TimeSeries
}
// Report processes a result stream until it is closed, then produces a
// string with information about the consumed result data.
type Report interface {
Results() chan<- Result
// Run returns results in print-friendly format.
Run() <-chan string
// Stats returns results in raw data.
Stats() <-chan Stats
}
func NewReport(precision string) Report {
return &report{
results: make(chan Result, 16),
precision: precision,
errorDist: make(map[string]int),
}
}
func NewReportSample(precision string) Report {
r := NewReport(precision).(*report)
r.sps = newSecondPoints()
return r
}
func (r *report) Results() chan<- Result { return r.results }
func (r *report) Run() <-chan string {
donec := make(chan string, 1)
go func() {
defer close(donec)
r.processResults()
donec <- r.String()
}()
return donec
}
func (r *report) Stats() <-chan Stats {
donec := make(chan Stats, 1)
go func() {
defer close(donec)
r.processResults()
var ts TimeSeries
if r.sps != nil {
ts = r.sps.getTimeSeries()
}
donec <- Stats{
AvgTotal: r.avgTotal,
Fastest: r.fastest,
Slowest: r.slowest,
Average: r.average,
Stddev: r.stddev,
RPS: r.rps,
Total: r.total,
ErrorDist: copyMap(r.errorDist),
Lats: copyFloats(r.lats),
TimeSeries: ts,
}
}()
return donec
}
func copyMap(m map[string]int) (c map[string]int) {
c = make(map[string]int, len(m))
for k, v := range m {
c[k] = v
}
return
}
func copyFloats(s []float64) (c []float64) {
c = make([]float64, len(s))
copy(c, s)
return
}
func (r *report) String() (s string) {
if len(r.lats) > 0 {
s += fmt.Sprintf("\nSummary:\n")
s += fmt.Sprintf(" Total:\t%s.\n", r.sec2str(r.total.Seconds()))
s += fmt.Sprintf(" Slowest:\t%s.\n", r.sec2str(r.slowest))
s += fmt.Sprintf(" Fastest:\t%s.\n", r.sec2str(r.fastest))
s += fmt.Sprintf(" Average:\t%s.\n", r.sec2str(r.average))
s += fmt.Sprintf(" Stddev:\t%s.\n", r.sec2str(r.stddev))
s += fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
s += r.histogram()
s += r.sprintLatencies()
if r.sps != nil {
s += fmt.Sprintf("%v\n", r.sps.getTimeSeries())
}
}
if len(r.errorDist) > 0 {
s += r.errors()
}
return s
}
func (r *report) sec2str(sec float64) string { return fmt.Sprintf(r.precision+" secs", sec) }
type reportRate struct{ *report }
func NewReportRate(precision string) Report {
return &reportRate{NewReport(precision).(*report)}
}
func (r *reportRate) String() string {
return fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
}
func (r *report) processResult(res *Result) {
if res.Err != nil {
r.errorDist[res.Err.Error()]++
return
}
dur := res.Duration()
r.lats = append(r.lats, dur.Seconds())
r.avgTotal += dur.Seconds()
if r.sps != nil {
r.sps.Add(res.Start, dur)
}
}
func (r *report) processResults() {
st := time.Now()
for res := range r.results {
r.processResult(&res)
}
r.total = time.Since(st)
r.rps = float64(len(r.lats)) / r.total.Seconds()
r.average = r.avgTotal / float64(len(r.lats))
for i := range r.lats {
dev := r.lats[i] - r.average
r.stddev += dev * dev
}
r.stddev = math.Sqrt(r.stddev / float64(len(r.lats)))
sort.Float64s(r.lats)
if len(r.lats) > 0 {
r.fastest = r.lats[0]
r.slowest = r.lats[len(r.lats)-1]
}
}
var pctls = []float64{10, 25, 50, 75, 90, 95, 99, 99.9}
// Percentiles returns percentile distribution of float64 slice.
func Percentiles(nums []float64) (pcs []float64, data []float64) {
return pctls, percentiles(nums)
}
func percentiles(nums []float64) (data []float64) {
data = make([]float64, len(pctls))
j := 0
n := len(nums)
for i := 0; i < n && j < len(pctls); i++ {
current := float64(i) * 100.0 / float64(n)
if current >= pctls[j] {
data[j] = nums[i]
j++
}
}
return
}
func (r *report) sprintLatencies() string {
data := percentiles(r.lats)
s := fmt.Sprintf("\nLatency distribution:\n")
for i := 0; i < len(pctls); i++ {
if data[i] > 0 {
s += fmt.Sprintf(" %v%% in %s.\n", pctls[i], r.sec2str(data[i]))
}
}
return s
}
func (r *report) histogram() string {
bc := 10
buckets := make([]float64, bc+1)
counts := make([]int, bc+1)
bs := (r.slowest - r.fastest) / float64(bc)
for i := 0; i < bc; i++ {
buckets[i] = r.fastest + bs*float64(i)
}
buckets[bc] = r.slowest
var bi int
var max int
for i := 0; i < len(r.lats); {
if r.lats[i] <= buckets[bi] {
i++
counts[bi]++
if max < counts[bi] {
max = counts[bi]
}
} else if bi < len(buckets)-1 {
bi++
}
}
s := fmt.Sprintf("\nResponse time histogram:\n")
for i := 0; i < len(buckets); i++ {
// Normalize bar lengths.
var barLen int
if max > 0 {
barLen = counts[i] * 40 / max
}
s += fmt.Sprintf(" "+r.precision+" [%v]\t|%v\n", buckets[i], counts[i], strings.Repeat(barChar, barLen))
}
return s
}
func (r *report) errors() string {
s := fmt.Sprintf("\nError distribution:\n")
for err, num := range r.errorDist {
s += fmt.Sprintf(" [%d]\t%s\n", num, err)
}
return s
}

View file

@ -0,0 +1,33 @@
// 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 report
import "testing"
func TestPercentiles(t *testing.T) {
nums := make([]float64, 100)
nums[99] = 1 // 99-percentile (1 out of 100)
data := percentiles(nums)
if data[len(pctls)-2] != 1 {
t.Fatalf("99-percentile expected 1, got %f", data[len(pctls)-2])
}
nums = make([]float64, 1000)
nums[999] = 1 // 99.9-percentile (1 out of 1000)
data = percentiles(nums)
if data[len(pctls)-1] != 1 {
t.Fatalf("99.9-percentile expected 1, got %f", data[len(pctls)-1])
}
}

134
vendor/github.com/coreos/etcd/pkg/report/timeseries.go generated vendored Normal file
View file

@ -0,0 +1,134 @@
// 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 report
import (
"bytes"
"encoding/csv"
"fmt"
"log"
"math"
"sort"
"sync"
"time"
)
type DataPoint struct {
Timestamp int64
AvgLatency time.Duration
ThroughPut int64
}
type TimeSeries []DataPoint
func (t TimeSeries) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t TimeSeries) Len() int { return len(t) }
func (t TimeSeries) Less(i, j int) bool { return t[i].Timestamp < t[j].Timestamp }
type secondPoint struct {
totalLatency time.Duration
count int64
}
type secondPoints struct {
mu sync.Mutex
tm map[int64]secondPoint
}
func newSecondPoints() *secondPoints {
return &secondPoints{tm: make(map[int64]secondPoint)}
}
func (sp *secondPoints) Add(ts time.Time, lat time.Duration) {
sp.mu.Lock()
defer sp.mu.Unlock()
tk := ts.Unix()
if v, ok := sp.tm[tk]; !ok {
sp.tm[tk] = secondPoint{totalLatency: lat, count: 1}
} else {
v.totalLatency += lat
v.count += 1
sp.tm[tk] = v
}
}
func (sp *secondPoints) getTimeSeries() TimeSeries {
sp.mu.Lock()
defer sp.mu.Unlock()
var (
minTs int64 = math.MaxInt64
maxTs int64 = -1
)
for k := range sp.tm {
if minTs > k {
minTs = k
}
if maxTs < k {
maxTs = k
}
}
for ti := minTs; ti < maxTs; ti++ {
if _, ok := sp.tm[ti]; !ok { // fill-in empties
sp.tm[ti] = secondPoint{totalLatency: 0, count: 0}
}
}
var (
tslice = make(TimeSeries, len(sp.tm))
i int
)
for k, v := range sp.tm {
var lat time.Duration
if v.count > 0 {
lat = time.Duration(v.totalLatency) / time.Duration(v.count)
}
tslice[i] = DataPoint{
Timestamp: k,
AvgLatency: lat,
ThroughPut: v.count,
}
i++
}
sort.Sort(tslice)
return tslice
}
func (ts TimeSeries) String() string {
buf := new(bytes.Buffer)
wr := csv.NewWriter(buf)
if err := wr.Write([]string{"UNIX-TS", "AVG-LATENCY-MS", "AVG-THROUGHPUT"}); err != nil {
log.Fatal(err)
}
rows := [][]string{}
for i := range ts {
row := []string{
fmt.Sprintf("%d", ts[i].Timestamp),
fmt.Sprintf("%s", ts[i].AvgLatency),
fmt.Sprintf("%d", ts[i].ThroughPut),
}
rows = append(rows, row)
}
if err := wr.WriteAll(rows); err != nil {
log.Fatal(err)
}
wr.Flush()
if err := wr.Error(); err != nil {
log.Fatal(err)
}
return fmt.Sprintf("\nSample in one second (unix latency throughput):\n%s", buf.String())
}

View file

@ -0,0 +1,31 @@
// 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 report
import (
"testing"
"time"
)
func TestGetTimeseries(t *testing.T) {
sp := newSecondPoints()
now := time.Now()
sp.Add(now, time.Second)
sp.Add(now.Add(5*time.Second), time.Second)
n := sp.getTimeSeries().Len()
if n < 3 {
t.Fatalf("expected at 6 points of time series, got %s", sp.getTimeSeries())
}
}

37
vendor/github.com/coreos/etcd/pkg/runtime/fds_linux.go generated vendored Normal file
View file

@ -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
}

30
vendor/github.com/coreos/etcd/pkg/runtime/fds_other.go generated vendored Normal file
View file

@ -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)
}

16
vendor/github.com/coreos/etcd/pkg/schedule/doc.go generated vendored Normal file
View file

@ -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

168
vendor/github.com/coreos/etcd/pkg/schedule/schedule.go generated vendored Normal file
View file

@ -0,0 +1,168 @@
// 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 (
"sync"
"golang.org/x/net/context"
)
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)
return
}
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()
}
}
}

View file

@ -0,0 +1,50 @@
// 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 (
"testing"
"golang.org/x/net/context"
)
func TestFIFOSchedule(t *testing.T) {
s := NewFIFOScheduler()
defer s.Stop()
next := 0
jobCreator := func(i int) Job {
return func(ctx context.Context) {
if next != i {
t.Fatalf("job#%d: got %d, want %d", i, next, i)
}
next = i + 1
}
}
var jobs []Job
for i := 0; i < 100; i++ {
jobs = append(jobs, jobCreator(i))
}
for _, j := range jobs {
s.Schedule(j)
}
s.WaitFinish(100)
if s.Scheduled() != 100 {
t.Errorf("scheduled = %d, want %d", s.Scheduled(), 100)
}
}

View file

@ -0,0 +1,54 @@
// 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 stringutil
import "math/rand"
const (
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
)
// UniqueStrings retruns a slice of randomly generated unique strings.
func UniqueStrings(maxlen uint, n int) []string {
exist := make(map[string]bool)
ss := make([]string, 0)
for len(ss) < n {
s := randomString(maxlen)
if !exist[s] {
exist[s] = true
ss = append(ss, s)
}
}
return ss
}
// RandomStrings retruns a slice of randomly generated strings.
func RandomStrings(maxlen uint, n int) []string {
ss := make([]string, 0)
for i := 0; i < n; i++ {
ss = append(ss, randomString(maxlen))
}
return ss
}
func randomString(l uint) string {
s := make([]byte, l)
for i := 0; i < int(l); i++ {
s[i] = chars[rand.Intn(len(chars))]
}
return string(s)
}

125
vendor/github.com/coreos/etcd/pkg/testutil/leak.go generated vendored Normal file
View file

@ -0,0 +1,125 @@
// Copyright 2013 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 testutil
import (
"fmt"
"net/http"
"os"
"regexp"
"runtime"
"sort"
"strings"
"testing"
"time"
)
/*
CheckLeakedGoroutine verifies tests do not leave any leaky
goroutines. It returns true when there are goroutines still
running(leaking) after all tests.
import "github.com/coreos/etcd/pkg/testutil"
func TestMain(m *testing.M) {
v := m.Run()
if v == 0 && testutil.CheckLeakedGoroutine() {
os.Exit(1)
}
os.Exit(v)
}
func TestSample(t *testing.T) {
defer testutil.AfterTest(t)
...
}
*/
func CheckLeakedGoroutine() bool {
if testing.Short() {
// not counting goroutines for leakage in -short mode
return false
}
gs := interestingGoroutines()
if len(gs) == 0 {
return false
}
stackCount := make(map[string]int)
re := regexp.MustCompile(`\(0[0-9a-fx, ]*\)`)
for _, g := range gs {
// strip out pointer arguments in first function of stack dump
normalized := string(re.ReplaceAll([]byte(g), []byte("(...)")))
stackCount[normalized]++
}
fmt.Fprintf(os.Stderr, "Too many goroutines running after all test(s).\n")
for stack, count := range stackCount {
fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
}
return true
}
func AfterTest(t *testing.T) {
http.DefaultTransport.(*http.Transport).CloseIdleConnections()
if testing.Short() {
return
}
var bad string
badSubstring := map[string]string{
").writeLoop(": "a Transport",
"created by net/http/httptest.(*Server).Start": "an httptest.Server",
"timeoutHandler": "a TimeoutHandler",
"net.(*netFD).connect(": "a timing out dial",
").noteClientGone(": "a closenotifier sender",
").readLoop(": "a Transport",
}
var stacks string
for i := 0; i < 6; i++ {
bad = ""
stacks = strings.Join(interestingGoroutines(), "\n\n")
for substr, what := range badSubstring {
if strings.Contains(stacks, substr) {
bad = what
}
}
if bad == "" {
return
}
// Bad stuff found, but goroutines might just still be
// shutting down, so give it some time.
time.Sleep(50 * time.Millisecond)
}
t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
}
func interestingGoroutines() (gs []string) {
buf := make([]byte, 2<<20)
buf = buf[:runtime.Stack(buf, true)]
for _, g := range strings.Split(string(buf), "\n\n") {
sl := strings.SplitN(g, "\n", 2)
if len(sl) != 2 {
continue
}
stack := strings.TrimSpace(sl[1])
if stack == "" ||
strings.Contains(stack, "created by os/signal.init") ||
strings.Contains(stack, "runtime/panic.go") ||
strings.Contains(stack, "created by testing.RunTests") ||
strings.Contains(stack, "testing.Main(") ||
strings.Contains(stack, "runtime.goexit") ||
strings.Contains(stack, "github.com/coreos/etcd/pkg/testutil.interestingGoroutines") ||
strings.Contains(stack, "github.com/coreos/etcd/pkg/logutil.(*MergeLogger).outputLoop") ||
strings.Contains(stack, "github.com/golang/glog.(*loggingT).flushDaemon") ||
strings.Contains(stack, "created by runtime.gc") ||
strings.Contains(stack, "runtime.MHeap_Scavenger") {
continue
}
gs = append(gs, stack)
}
sort.Strings(gs)
return
}

View file

@ -0,0 +1,44 @@
// 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 testutil
import (
"fmt"
"os"
"testing"
)
// so tests pass if given a -run that doesn't include TestSample
var ranSample = false
func TestMain(m *testing.M) {
m.Run()
isLeaked := CheckLeakedGoroutine()
if ranSample && !isLeaked {
fmt.Fprintln(os.Stderr, "expected leaky goroutines but none is detected")
os.Exit(1)
}
os.Exit(0)
}
func TestSample(t *testing.T) {
defer AfterTest(t)
ranSample = true
for range make([]struct{}, 100) {
go func() {
select {}
}()
}
}

View file

@ -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 testutil
import (
"net/http"
"sync"
)
type PauseableHandler struct {
Next http.Handler
mu sync.Mutex
paused bool
}
func (ph *PauseableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ph.mu.Lock()
paused := ph.paused
ph.mu.Unlock()
if !paused {
ph.Next.ServeHTTP(w, r)
} else {
hj, ok := w.(http.Hijacker)
if !ok {
panic("webserver doesn't support hijacking")
}
conn, _, err := hj.Hijack()
if err != nil {
panic(err.Error())
}
conn.Close()
}
}
func (ph *PauseableHandler) Pause() {
ph.mu.Lock()
defer ph.mu.Unlock()
ph.paused = true
}
func (ph *PauseableHandler) Resume() {
ph.mu.Lock()
defer ph.mu.Unlock()
ph.paused = false
}

132
vendor/github.com/coreos/etcd/pkg/testutil/recorder.go generated vendored Normal file
View file

@ -0,0 +1,132 @@
// 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 testutil
import (
"errors"
"fmt"
"sync"
"time"
)
type Action struct {
Name string
Params []interface{}
}
type Recorder interface {
// Record publishes an Action (e.g., function call) which will
// be reflected by Wait() or Chan()
Record(a Action)
// Wait waits until at least n Actions are available or returns with error
Wait(n int) ([]Action, error)
// Action returns immediately available Actions
Action() []Action
// Chan returns the channel for actions published by Record
Chan() <-chan Action
}
// RecorderBuffered appends all Actions to a slice
type RecorderBuffered struct {
sync.Mutex
actions []Action
}
func (r *RecorderBuffered) Record(a Action) {
r.Lock()
r.actions = append(r.actions, a)
r.Unlock()
}
func (r *RecorderBuffered) Action() []Action {
r.Lock()
cpy := make([]Action, len(r.actions))
copy(cpy, r.actions)
r.Unlock()
return cpy
}
func (r *RecorderBuffered) Wait(n int) (acts []Action, err error) {
// legacy racey behavior
WaitSchedule()
acts = r.Action()
if len(acts) < n {
err = newLenErr(n, len(acts))
}
return acts, err
}
func (r *RecorderBuffered) Chan() <-chan Action {
ch := make(chan Action)
go func() {
acts := r.Action()
for i := range acts {
ch <- acts[i]
}
close(ch)
}()
return ch
}
// RecorderStream writes all Actions to an unbuffered channel
type recorderStream struct {
ch chan Action
}
func NewRecorderStream() Recorder {
return &recorderStream{ch: make(chan Action)}
}
func (r *recorderStream) Record(a Action) {
r.ch <- a
}
func (r *recorderStream) Action() (acts []Action) {
for {
select {
case act := <-r.ch:
acts = append(acts, act)
default:
return acts
}
}
}
func (r *recorderStream) Chan() <-chan Action {
return r.ch
}
func (r *recorderStream) Wait(n int) ([]Action, error) {
acts := make([]Action, n)
timeoutC := time.After(5 * time.Second)
for i := 0; i < n; i++ {
select {
case acts[i] = <-r.ch:
case <-timeoutC:
acts = acts[:i]
return acts, newLenErr(n, i)
}
}
// extra wait to catch any Action spew
select {
case act := <-r.ch:
acts = append(acts, act)
case <-time.After(10 * time.Millisecond):
}
return acts, nil
}
func newLenErr(expected int, actual int) error {
s := fmt.Sprintf("len(actions) = %d, expected >= %d", actual, expected)
return errors.New(s)
}

57
vendor/github.com/coreos/etcd/pkg/testutil/testutil.go generated vendored Normal file
View file

@ -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 testutil provides test utility functions.
package testutil
import (
"net/url"
"runtime"
"testing"
"time"
)
// WaitSchedule briefly sleeps in order to invoke the go scheduler.
// TODO: improve this when we are able to know the schedule or status of target go-routine.
func WaitSchedule() {
time.Sleep(10 * time.Millisecond)
}
func MustNewURLs(t *testing.T, urls []string) []url.URL {
if urls == nil {
return nil
}
var us []url.URL
for _, url := range urls {
u := MustNewURL(t, url)
us = append(us, *u)
}
return us
}
func MustNewURL(t *testing.T, s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
t.Fatalf("parse %v error: %v", s, err)
}
return u
}
// FatalStack helps to fatal the test and print out the stacks of all running goroutines.
func FatalStack(t *testing.T, s string) {
stackTrace := make([]byte, 1024*1024)
n := runtime.Stack(stackTrace, true)
t.Error(string(stackTrace[:n]))
t.Fatalf(s)
}

16
vendor/github.com/coreos/etcd/pkg/tlsutil/doc.go generated vendored Normal file
View file

@ -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

72
vendor/github.com/coreos/etcd/pkg/tlsutil/tlsutil.go generated vendored Normal file
View file

@ -0,0 +1,72 @@
// 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
}

17
vendor/github.com/coreos/etcd/pkg/transport/doc.go generated vendored Normal file
View file

@ -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

View file

@ -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
}
// 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
}

Some files were not shown because too many files have changed in this diff Show more