mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Updating kubernetes proper to use latest etcd client library
This commit is contained in:
		@@ -63,9 +63,10 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/test/integration"
 | 
						"k8s.io/kubernetes/test/integration"
 | 
				
			||||||
	"k8s.io/kubernetes/test/integration/framework"
 | 
						"k8s.io/kubernetes/test/integration/framework"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	"github.com/spf13/pflag"
 | 
						"github.com/spf13/pflag"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -93,17 +94,23 @@ func (h *delegateHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func startComponents(firstManifestURL, secondManifestURL string) (string, string) {
 | 
					func startComponents(firstManifestURL, secondManifestURL string) (string, string) {
 | 
				
			||||||
	// Setup
 | 
						// Setup
 | 
				
			||||||
	servers := []string{}
 | 
					 | 
				
			||||||
	glog.Infof("Creating etcd client pointing to %v", servers)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	handler := delegateHandler{}
 | 
						handler := delegateHandler{}
 | 
				
			||||||
	apiServer := httptest.NewServer(&handler)
 | 
						apiServer := httptest.NewServer(&handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	etcdClient := etcd.NewClient(servers)
 | 
						cfg := etcd.Config{
 | 
				
			||||||
 | 
							Endpoints: []string{"http://127.0.0.1:4001"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						etcdClient, err := etcd.New(cfg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Fatalf("Error creating etcd client: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						glog.Infof("Creating etcd client pointing to %v", cfg.Endpoints)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keysAPI := etcd.NewKeysAPI(etcdClient)
 | 
				
			||||||
	sleep := 4 * time.Second
 | 
						sleep := 4 * time.Second
 | 
				
			||||||
	ok := false
 | 
						ok := false
 | 
				
			||||||
	for i := 0; i < 3; i++ {
 | 
						for i := 0; i < 3; i++ {
 | 
				
			||||||
		keys, err := etcdClient.Get("/", false, false)
 | 
							keys, err := keysAPI.Get(context.TODO(), "/", nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.Warningf("Unable to list root etcd keys: %v", err)
 | 
								glog.Warningf("Unable to list root etcd keys: %v", err)
 | 
				
			||||||
			if i < 2 {
 | 
								if i < 2 {
 | 
				
			||||||
@@ -113,7 +120,7 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, node := range keys.Node.Nodes {
 | 
							for _, node := range keys.Node.Nodes {
 | 
				
			||||||
			if _, err := etcdClient.Delete(node.Key, true); err != nil {
 | 
								if _, err := keysAPI.Delete(context.TODO(), node.Key, &etcd.DeleteOptions{Recursive: true}); err != nil {
 | 
				
			||||||
				glog.Fatalf("Unable delete key: %v", err)
 | 
									glog.Fatalf("Unable delete key: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,10 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
						"k8s.io/kubernetes/pkg/api/unversioned"
 | 
				
			||||||
	etcdutil "k8s.io/kubernetes/pkg/storage/etcd/util"
 | 
						etcdutil "k8s.io/kubernetes/pkg/storage/etcd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util"
 | 
						"k8s.io/kubernetes/pkg/util"
 | 
				
			||||||
@@ -38,15 +40,15 @@ type Master string
 | 
				
			|||||||
func (obj Master) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }
 | 
					func (obj Master) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewEtcdMasterElector returns an implementation of election.MasterElector backed by etcd.
 | 
					// NewEtcdMasterElector returns an implementation of election.MasterElector backed by etcd.
 | 
				
			||||||
func NewEtcdMasterElector(h *etcd.Client) MasterElector {
 | 
					func NewEtcdMasterElector(h etcd.Client) MasterElector {
 | 
				
			||||||
	return &etcdMasterElector{etcd: h}
 | 
						return &etcdMasterElector{etcd: etcd.NewKeysAPI(h)}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type empty struct{}
 | 
					type empty struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// internal implementation struct
 | 
					// internal implementation struct
 | 
				
			||||||
type etcdMasterElector struct {
 | 
					type etcdMasterElector struct {
 | 
				
			||||||
	etcd   *etcd.Client
 | 
						etcd   etcd.KeysAPI
 | 
				
			||||||
	done   chan empty
 | 
						done   chan empty
 | 
				
			||||||
	events chan watch.Event
 | 
						events chan watch.Event
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -90,7 +92,12 @@ func (e *etcdMasterElector) extendMaster(path, id string, ttl uint64, res *etcd.
 | 
				
			|||||||
	// Uses compare and swap, so that if we TTL out in the meantime, the write will fail.
 | 
						// Uses compare and swap, so that if we TTL out in the meantime, the write will fail.
 | 
				
			||||||
	// We don't handle the TTL delete w/o a write case here, it's handled in the next loop
 | 
						// We don't handle the TTL delete w/o a write case here, it's handled in the next loop
 | 
				
			||||||
	// iteration.
 | 
						// iteration.
 | 
				
			||||||
	_, err := e.etcd.CompareAndSwap(path, id, ttl, "", res.Node.ModifiedIndex)
 | 
						opts := etcd.SetOptions{
 | 
				
			||||||
 | 
							TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
							PrevValue: "",
 | 
				
			||||||
 | 
							PrevIndex: res.Node.ModifiedIndex,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := e.etcd.Set(context.TODO(), path, id, &opts)
 | 
				
			||||||
	if err != nil && !etcdutil.IsEtcdTestFailed(err) {
 | 
						if err != nil && !etcdutil.IsEtcdTestFailed(err) {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -105,7 +112,12 @@ func (e *etcdMasterElector) extendMaster(path, id string, ttl uint64, res *etcd.
 | 
				
			|||||||
// returns id, nil if the attempt succeeded
 | 
					// returns id, nil if the attempt succeeded
 | 
				
			||||||
// returns "", err if an error occurred
 | 
					// returns "", err if an error occurred
 | 
				
			||||||
func (e *etcdMasterElector) becomeMaster(path, id string, ttl uint64) (string, error) {
 | 
					func (e *etcdMasterElector) becomeMaster(path, id string, ttl uint64) (string, error) {
 | 
				
			||||||
	_, err := e.etcd.Create(path, id, ttl)
 | 
						opts := etcd.SetOptions{
 | 
				
			||||||
 | 
							TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
							PrevExist: etcd.PrevNoExist,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := e.etcd.Set(context.TODO(), path, id, &opts)
 | 
				
			||||||
	if err != nil && !etcdutil.IsEtcdNodeExist(err) {
 | 
						if err != nil && !etcdutil.IsEtcdNodeExist(err) {
 | 
				
			||||||
		// unexpected error
 | 
							// unexpected error
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
@@ -122,7 +134,7 @@ func (e *etcdMasterElector) becomeMaster(path, id string, ttl uint64) (string, e
 | 
				
			|||||||
// in situations where you should try again due to concurrent state changes (e.g. another actor simultaneously acquiring the lock)
 | 
					// in situations where you should try again due to concurrent state changes (e.g. another actor simultaneously acquiring the lock)
 | 
				
			||||||
// it returns "", nil
 | 
					// it returns "", nil
 | 
				
			||||||
func (e *etcdMasterElector) handleMaster(path, id string, ttl uint64) (string, error) {
 | 
					func (e *etcdMasterElector) handleMaster(path, id string, ttl uint64) (string, error) {
 | 
				
			||||||
	res, err := e.etcd.Get(path, false, false)
 | 
						res, err := e.etcd.Get(context.TODO(), path, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Unexpected error, bail out
 | 
						// Unexpected error, bail out
 | 
				
			||||||
	if err != nil && !etcdutil.IsEtcdNotFound(err) {
 | 
						if err != nil && !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,9 @@ package election
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
 | 
						etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -28,7 +31,8 @@ func TestEtcdMasterOther(t *testing.T) {
 | 
				
			|||||||
	defer server.Terminate(t)
 | 
						defer server.Terminate(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	path := "foo"
 | 
						path := "foo"
 | 
				
			||||||
	if _, err := server.Client.Set(path, "baz", 0); err != nil {
 | 
						keysAPI := etcd.NewKeysAPI(server.Client)
 | 
				
			||||||
 | 
						if _, err := keysAPI.Set(context.TODO(), path, "baz", nil); err != nil {
 | 
				
			||||||
		t.Errorf("unexpected error: %v", err)
 | 
							t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	master := NewEtcdMasterElector(server.Client)
 | 
						master := NewEtcdMasterElector(server.Client)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/gogo/protobuf/proto"
 | 
						"github.com/gogo/protobuf/proto"
 | 
				
			||||||
	log "github.com/golang/glog"
 | 
						log "github.com/golang/glog"
 | 
				
			||||||
	"github.com/kardianos/osext"
 | 
						"github.com/kardianos/osext"
 | 
				
			||||||
@@ -102,7 +102,6 @@ type SchedulerServer struct {
 | 
				
			|||||||
	authPath            string
 | 
						authPath            string
 | 
				
			||||||
	apiServerList       []string
 | 
						apiServerList       []string
 | 
				
			||||||
	etcdServerList      []string
 | 
						etcdServerList      []string
 | 
				
			||||||
	etcdConfigFile      string
 | 
					 | 
				
			||||||
	allowPrivileged     bool
 | 
						allowPrivileged     bool
 | 
				
			||||||
	executorPath        string
 | 
						executorPath        string
 | 
				
			||||||
	proxyPath           string
 | 
						proxyPath           string
 | 
				
			||||||
@@ -234,8 +233,7 @@ func (s *SchedulerServer) addCoreFlags(fs *pflag.FlagSet) {
 | 
				
			|||||||
	fs.BoolVar(&s.enableProfiling, "profiling", s.enableProfiling, "Enable profiling via web interface host:port/debug/pprof/")
 | 
						fs.BoolVar(&s.enableProfiling, "profiling", s.enableProfiling, "Enable profiling via web interface host:port/debug/pprof/")
 | 
				
			||||||
	fs.StringSliceVar(&s.apiServerList, "api-servers", s.apiServerList, "List of Kubernetes API servers for publishing events, and reading pods and services. (ip:port), comma separated.")
 | 
						fs.StringSliceVar(&s.apiServerList, "api-servers", s.apiServerList, "List of Kubernetes API servers for publishing events, and reading pods and services. (ip:port), comma separated.")
 | 
				
			||||||
	fs.StringVar(&s.authPath, "auth-path", s.authPath, "Path to .kubernetes_auth file, specifying how to authenticate to API server.")
 | 
						fs.StringVar(&s.authPath, "auth-path", s.authPath, "Path to .kubernetes_auth file, specifying how to authenticate to API server.")
 | 
				
			||||||
	fs.StringSliceVar(&s.etcdServerList, "etcd-servers", s.etcdServerList, "List of etcd servers to watch (http://ip:port), comma separated. Mutually exclusive with --etcd-config")
 | 
						fs.StringSliceVar(&s.etcdServerList, "etcd-servers", s.etcdServerList, "List of etcd servers to watch (http://ip:port), comma separated.")
 | 
				
			||||||
	fs.StringVar(&s.etcdConfigFile, "etcd-config", s.etcdConfigFile, "The config file for the etcd client. Mutually exclusive with --etcd-servers.")
 | 
					 | 
				
			||||||
	fs.BoolVar(&s.allowPrivileged, "allow-privileged", s.allowPrivileged, "Enable privileged containers in the kubelet (compare the same flag in the apiserver).")
 | 
						fs.BoolVar(&s.allowPrivileged, "allow-privileged", s.allowPrivileged, "Enable privileged containers in the kubelet (compare the same flag in the apiserver).")
 | 
				
			||||||
	fs.StringVar(&s.clusterDomain, "cluster-domain", s.clusterDomain, "Domain for this cluster.  If set, kubelet will configure all containers to search this domain in addition to the host's search domains")
 | 
						fs.StringVar(&s.clusterDomain, "cluster-domain", s.clusterDomain, "Domain for this cluster.  If set, kubelet will configure all containers to search this domain in addition to the host's search domains")
 | 
				
			||||||
	fs.IPVar(&s.clusterDNS, "cluster-dns", s.clusterDNS, "IP address for a cluster DNS server. If set, kubelet will configure all containers to use this for DNS resolution in addition to the host's DNS servers")
 | 
						fs.IPVar(&s.clusterDNS, "cluster-dns", s.clusterDNS, "IP address for a cluster DNS server. If set, kubelet will configure all containers to use this for DNS resolution in addition to the host's DNS servers")
 | 
				
			||||||
@@ -640,16 +638,14 @@ func validateLeadershipTransition(desired, current string) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// hacked from https://github.com/GoogleCloudPlatform/kubernetes/blob/release-0.14/cmd/kube-apiserver/app/server.go
 | 
					// hacked from https://github.com/GoogleCloudPlatform/kubernetes/blob/release-0.14/cmd/kube-apiserver/app/server.go
 | 
				
			||||||
func newEtcd(etcdConfigFile string, etcdServerList []string) (client *etcd.Client, err error) {
 | 
					func newEtcd(etcdServerList []string) (etcd.Client, error) {
 | 
				
			||||||
	if etcdConfigFile != "" {
 | 
						cfg := etcd.Config{
 | 
				
			||||||
		client, err = etcd.NewClientFromFile(etcdConfigFile)
 | 
							Endpoints: etcdServerList,
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		client = etcd.NewClient(etcdServerList)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return etcd.New(cfg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config) (*ha.SchedulerProcess, ha.DriverFactory, *etcd.Client, *mesos.ExecutorID) {
 | 
					func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config) (*ha.SchedulerProcess, ha.DriverFactory, etcd.Client, *mesos.ExecutorID) {
 | 
				
			||||||
	s.frameworkName = strings.TrimSpace(s.frameworkName)
 | 
						s.frameworkName = strings.TrimSpace(s.frameworkName)
 | 
				
			||||||
	if s.frameworkName == "" {
 | 
						if s.frameworkName == "" {
 | 
				
			||||||
		log.Fatalf("framework-name must be a non-empty string")
 | 
							log.Fatalf("framework-name must be a non-empty string")
 | 
				
			||||||
@@ -661,8 +657,8 @@ func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config
 | 
				
			|||||||
	s.mux.Handle("/metrics", prometheus.Handler())
 | 
						s.mux.Handle("/metrics", prometheus.Handler())
 | 
				
			||||||
	healthz.InstallHandler(s.mux)
 | 
						healthz.InstallHandler(s.mux)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (s.etcdConfigFile != "" && len(s.etcdServerList) != 0) || (s.etcdConfigFile == "" && len(s.etcdServerList) == 0) {
 | 
						if len(s.etcdServerList) == 0 {
 | 
				
			||||||
		log.Fatalf("specify either --etcd-servers or --etcd-config")
 | 
							log.Fatalf("specify --etcd-servers must be specified")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(s.apiServerList) < 1 {
 | 
						if len(s.apiServerList) < 1 {
 | 
				
			||||||
@@ -689,10 +685,11 @@ func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config
 | 
				
			|||||||
	// (1) the generic config store is available for the FrameworkId storage
 | 
						// (1) the generic config store is available for the FrameworkId storage
 | 
				
			||||||
	// (2) the generic master election is provided by the apiserver
 | 
						// (2) the generic master election is provided by the apiserver
 | 
				
			||||||
	// Compare docs/proposals/high-availability.md
 | 
						// Compare docs/proposals/high-availability.md
 | 
				
			||||||
	etcdClient, err := newEtcd(s.etcdConfigFile, s.etcdServerList)
 | 
						etcdClient, err := newEtcd(s.etcdServerList)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalf("misconfigured etcd: %v", err)
 | 
							log.Fatalf("misconfigured etcd: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						keysAPI := etcd.NewKeysAPI(etcdClient)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// mirror all nodes into the nodeStore
 | 
						// mirror all nodes into the nodeStore
 | 
				
			||||||
	var eiRegistry executorinfo.Registry
 | 
						var eiRegistry executorinfo.Registry
 | 
				
			||||||
@@ -741,7 +738,7 @@ func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config
 | 
				
			|||||||
		LookupNode:        lookupNode,
 | 
							LookupNode:        lookupNode,
 | 
				
			||||||
		StoreFrameworkId: func(id string) {
 | 
							StoreFrameworkId: func(id string) {
 | 
				
			||||||
			// TODO(jdef): port FrameworkId store to generic Kubernetes config store as soon as available
 | 
								// TODO(jdef): port FrameworkId store to generic Kubernetes config store as soon as available
 | 
				
			||||||
			_, err := etcdClient.Set(meta.FrameworkIDKey, id, uint64(s.failoverTimeout))
 | 
								_, err := keysAPI.Set(context.TODO(), meta.FrameworkIDKey, id, &etcd.SetOptions{TTL: time.Duration(s.failoverTimeout) * time.Second})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Errorf("failed to renew frameworkId TTL: %v", err)
 | 
									log.Errorf("failed to renew frameworkId TTL: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -806,7 +803,7 @@ func (s *SchedulerServer) bootstrap(hks hyperkube.Interface, sc *schedcfg.Config
 | 
				
			|||||||
		log.V(1).Infoln("deferred init complete")
 | 
							log.V(1).Infoln("deferred init complete")
 | 
				
			||||||
		// defer obtaining framework ID to prevent multiple schedulers
 | 
							// defer obtaining framework ID to prevent multiple schedulers
 | 
				
			||||||
		// from overwriting each other's framework IDs
 | 
							// from overwriting each other's framework IDs
 | 
				
			||||||
		dconfig.Framework.Id, err = s.fetchFrameworkID(etcdClient)
 | 
							dconfig.Framework.Id, err = s.fetchFrameworkID(keysAPI)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("failed to fetch framework ID from etcd: %v", err)
 | 
								return nil, fmt.Errorf("failed to fetch framework ID from etcd: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -928,9 +925,9 @@ func (s *SchedulerServer) buildFrameworkInfo() (info *mesos.FrameworkInfo, cred
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SchedulerServer) fetchFrameworkID(client *etcd.Client) (*mesos.FrameworkID, error) {
 | 
					func (s *SchedulerServer) fetchFrameworkID(client etcd.KeysAPI) (*mesos.FrameworkID, error) {
 | 
				
			||||||
	if s.failoverTimeout > 0 {
 | 
						if s.failoverTimeout > 0 {
 | 
				
			||||||
		if response, err := client.Get(meta.FrameworkIDKey, false, false); err != nil {
 | 
							if response, err := client.Get(context.TODO(), meta.FrameworkIDKey, nil); err != nil {
 | 
				
			||||||
			if !etcdutil.IsEtcdNotFound(err) {
 | 
								if !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
				return nil, fmt.Errorf("unexpected failure attempting to load framework ID from etcd: %v", err)
 | 
									return nil, fmt.Errorf("unexpected failure attempting to load framework ID from etcd: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -941,7 +938,7 @@ func (s *SchedulerServer) fetchFrameworkID(client *etcd.Client) (*mesos.Framewor
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		//TODO(jdef) this seems like a totally hackish way to clean up the framework ID
 | 
							//TODO(jdef) this seems like a totally hackish way to clean up the framework ID
 | 
				
			||||||
		if _, err := client.Delete(meta.FrameworkIDKey, true); err != nil {
 | 
							if _, err := client.Delete(context.TODO(), meta.FrameworkIDKey, &etcd.DeleteOptions{Recursive: true}); err != nil {
 | 
				
			||||||
			if !etcdutil.IsEtcdNotFound(err) {
 | 
								if !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
				return nil, fmt.Errorf("failed to delete framework ID from etcd: %v", err)
 | 
									return nil, fmt.Errorf("failed to delete framework ID from etcd: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,6 +178,7 @@ func (c *Cacher) startCaching(stopChannel <-chan struct{}) {
 | 
				
			|||||||
	// need to retry it on errors under lock.
 | 
						// need to retry it on errors under lock.
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if err := c.reflector.ListAndWatch(stopChannel); err != nil {
 | 
							if err := c.reflector.ListAndWatch(stopChannel); err != nil {
 | 
				
			||||||
 | 
								// TODO: This can tight loop log.
 | 
				
			||||||
			glog.Errorf("unexpected ListAndWatch error: %v", err)
 | 
								glog.Errorf("unexpected ListAndWatch error: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -196,14 +196,7 @@ func TestWatch(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("Expected 'error too old' error")
 | 
							t.Errorf("Expected 'error too old' error")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Now test watch with initial state.
 | 
						initialWatcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", fooCreated.ResourceVersion, storage.Everything)
 | 
				
			||||||
	// We want to observe fooCreation too, so need to pass smaller resource version.
 | 
					 | 
				
			||||||
	initialVersion, err := strconv.Atoi(fooCreated.ResourceVersion)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Incorrect resourceVersion: %s", fooCreated.ResourceVersion)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	initialVersion--
 | 
					 | 
				
			||||||
	initialWatcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", strconv.Itoa(initialVersion), storage.Everything)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("Unexpected error: %v", err)
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -282,13 +275,7 @@ func TestFiltering(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return selector.Matches(labels.Set(metadata.GetLabels()))
 | 
							return selector.Matches(labels.Set(metadata.GetLabels()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// We want to observe fooCreation too, so need to pass smaller resource version.
 | 
						watcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", fooCreated.ResourceVersion, filter)
 | 
				
			||||||
	initialVersion, err := strconv.Atoi(fooCreated.ResourceVersion)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Incorrect resourceVersion: %s", fooCreated.ResourceVersion)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	initialVersion--
 | 
					 | 
				
			||||||
	watcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", strconv.Itoa(initialVersion), filter)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("Unexpected error: %v", err)
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -299,23 +286,3 @@ func TestFiltering(t *testing.T) {
 | 
				
			|||||||
	verifyWatchEvent(t, watcher, watch.Modified, podFooPrime)
 | 
						verifyWatchEvent(t, watcher, watch.Modified, podFooPrime)
 | 
				
			||||||
	verifyWatchEvent(t, watcher, watch.Deleted, podFooPrime)
 | 
						verifyWatchEvent(t, watcher, watch.Deleted, podFooPrime)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* TODO: So believe it or not... but this test is flakey with the go-etcd client library
 | 
					 | 
				
			||||||
 * which I'm surprised by.  Apprently you can close the client that is performing the watch
 | 
					 | 
				
			||||||
 * and the watch *never returns.*  I would like to still keep this test here and re-enable
 | 
					 | 
				
			||||||
 * with the new 2.2+ client library.
 | 
					 | 
				
			||||||
func TestStorageError(t *testing.T) {
 | 
					 | 
				
			||||||
	server, etcdStorage := newEtcdTestStorage(t, testapi.Default.Codec(), etcdtest.PathPrefix())
 | 
					 | 
				
			||||||
	cacher := newTestCacher(etcdStorage)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	watcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", 1, storage.Everything)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Unexpected error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	server.Terminate(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	got := <-watcher.ResultChan()
 | 
					 | 
				
			||||||
	if got.Type != watch.Error {
 | 
					 | 
				
			||||||
		t.Errorf("Unexpected non-error")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
} */
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,9 +17,9 @@ limitations under the License.
 | 
				
			|||||||
package etcd
 | 
					package etcd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/tls"
 | 
					 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
@@ -36,10 +36,9 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/util"
 | 
						"k8s.io/kubernetes/pkg/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
	forked "k8s.io/kubernetes/third_party/forked/coreos/go-etcd/etcd"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// storage.Config object for etcd.
 | 
					// storage.Config object for etcd.
 | 
				
			||||||
@@ -56,27 +55,32 @@ func (c *EtcdConfig) GetType() string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// implements storage.Config
 | 
					// implements storage.Config
 | 
				
			||||||
func (c *EtcdConfig) NewStorage() (storage.Interface, error) {
 | 
					func (c *EtcdConfig) NewStorage() (storage.Interface, error) {
 | 
				
			||||||
	etcdClient := etcd.NewClient(c.ServerList)
 | 
						cfg := etcd.Config{
 | 
				
			||||||
	if etcdClient == nil {
 | 
							Endpoints: c.ServerList,
 | 
				
			||||||
		return nil, errors.New("Failed to create new etcd client from serverlist")
 | 
							// TODO: Determine if transport needs optimization
 | 
				
			||||||
	}
 | 
							Transport: &http.Transport{
 | 
				
			||||||
	transport := &http.Transport{
 | 
								Proxy: http.ProxyFromEnvironment,
 | 
				
			||||||
		Dial: forked.Dial,
 | 
								Dial: (&net.Dialer{
 | 
				
			||||||
		TLSClientConfig: &tls.Config{
 | 
									Timeout:   30 * time.Second,
 | 
				
			||||||
			InsecureSkipVerify: true,
 | 
									KeepAlive: 30 * time.Second,
 | 
				
			||||||
 | 
								}).Dial,
 | 
				
			||||||
 | 
								TLSHandshakeTimeout: 10 * time.Second,
 | 
				
			||||||
 | 
								MaxIdleConnsPerHost: 500,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		MaxIdleConnsPerHost: 500,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	etcdClient.SetTransport(transport)
 | 
						etcdClient, err := etcd.New(cfg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return NewEtcdStorage(etcdClient, c.Codec, c.Prefix), nil
 | 
						return NewEtcdStorage(etcdClient, c.Codec, c.Prefix), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Creates a new storage interface from the client
 | 
					// Creates a new storage interface from the client
 | 
				
			||||||
// TODO: deprecate in favor of storage.Config abstraction over time
 | 
					// TODO: deprecate in favor of storage.Config abstraction over time
 | 
				
			||||||
func NewEtcdStorage(client *etcd.Client, codec runtime.Codec, prefix string) storage.Interface {
 | 
					func NewEtcdStorage(client etcd.Client, codec runtime.Codec, prefix string) storage.Interface {
 | 
				
			||||||
	return &etcdHelper{
 | 
						return &etcdHelper{
 | 
				
			||||||
		client:     client,
 | 
							etcdclient: client,
 | 
				
			||||||
 | 
							client:     etcd.NewKeysAPI(client),
 | 
				
			||||||
		codec:      codec,
 | 
							codec:      codec,
 | 
				
			||||||
		versioner:  APIObjectVersioner{},
 | 
							versioner:  APIObjectVersioner{},
 | 
				
			||||||
		copier:     api.Scheme,
 | 
							copier:     api.Scheme,
 | 
				
			||||||
@@ -87,9 +91,10 @@ func NewEtcdStorage(client *etcd.Client, codec runtime.Codec, prefix string) sto
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// etcdHelper is the reference implementation of storage.Interface.
 | 
					// etcdHelper is the reference implementation of storage.Interface.
 | 
				
			||||||
type etcdHelper struct {
 | 
					type etcdHelper struct {
 | 
				
			||||||
	client *etcd.Client
 | 
						etcdclient etcd.Client
 | 
				
			||||||
	codec  runtime.Codec
 | 
						client     etcd.KeysAPI
 | 
				
			||||||
	copier runtime.ObjectCopier
 | 
						codec      runtime.Codec
 | 
				
			||||||
 | 
						copier     runtime.ObjectCopier
 | 
				
			||||||
	// optional, has to be set to perform any atomic operations
 | 
						// optional, has to be set to perform any atomic operations
 | 
				
			||||||
	versioner storage.Versioner
 | 
						versioner storage.Versioner
 | 
				
			||||||
	// prefix for all etcd keys
 | 
						// prefix for all etcd keys
 | 
				
			||||||
@@ -119,7 +124,20 @@ func (h *etcdHelper) Backends(ctx context.Context) []string {
 | 
				
			|||||||
	if ctx == nil {
 | 
						if ctx == nil {
 | 
				
			||||||
		glog.Errorf("Context is nil")
 | 
							glog.Errorf("Context is nil")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return h.client.GetCluster()
 | 
						membersAPI := etcd.NewMembersAPI(h.etcdclient)
 | 
				
			||||||
 | 
						members, err := membersAPI.List(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("Error obtaining etcd members list: %q", err)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if 0 == len(members) {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mlist := []string{""}
 | 
				
			||||||
 | 
						for _, member := range members {
 | 
				
			||||||
 | 
							mlist = append(mlist, member.ClientURLs...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mlist
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implements storage.Interface.
 | 
					// Implements storage.Interface.
 | 
				
			||||||
@@ -144,7 +162,11 @@ func (h *etcdHelper) Create(ctx context.Context, key string, obj, out runtime.Ob
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startTime := time.Now()
 | 
						startTime := time.Now()
 | 
				
			||||||
	response, err := h.client.Create(key, string(data), ttl)
 | 
						opts := etcd.SetOptions{
 | 
				
			||||||
 | 
							TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
							PrevExist: etcd.PrevNoExist,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response, err := h.client.Set(ctx, key, string(data), &opts)
 | 
				
			||||||
	metrics.RecordEtcdRequestLatency("create", getTypeName(obj), startTime)
 | 
						metrics.RecordEtcdRequestLatency("create", getTypeName(obj), startTime)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -175,7 +197,11 @@ func (h *etcdHelper) Set(ctx context.Context, key string, obj, out runtime.Objec
 | 
				
			|||||||
		if version, err := h.versioner.ObjectResourceVersion(obj); err == nil && version != 0 {
 | 
							if version, err := h.versioner.ObjectResourceVersion(obj); err == nil && version != 0 {
 | 
				
			||||||
			create = false
 | 
								create = false
 | 
				
			||||||
			startTime := time.Now()
 | 
								startTime := time.Now()
 | 
				
			||||||
			response, err = h.client.CompareAndSwap(key, string(data), ttl, "", version)
 | 
								opts := etcd.SetOptions{
 | 
				
			||||||
 | 
									TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
									PrevIndex: version,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								response, err = h.client.Set(ctx, key, string(data), &opts)
 | 
				
			||||||
			metrics.RecordEtcdRequestLatency("compareAndSwap", getTypeName(obj), startTime)
 | 
								metrics.RecordEtcdRequestLatency("compareAndSwap", getTypeName(obj), startTime)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
@@ -185,7 +211,14 @@ func (h *etcdHelper) Set(ctx context.Context, key string, obj, out runtime.Objec
 | 
				
			|||||||
	if create {
 | 
						if create {
 | 
				
			||||||
		// Create will fail if a key already exists.
 | 
							// Create will fail if a key already exists.
 | 
				
			||||||
		startTime := time.Now()
 | 
							startTime := time.Now()
 | 
				
			||||||
		response, err = h.client.Create(key, string(data), ttl)
 | 
							opts := etcd.SetOptions{
 | 
				
			||||||
 | 
								TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
								PrevExist: etcd.PrevNoExist,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							response, err = h.client.Set(ctx, key, string(data), &opts)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		metrics.RecordEtcdRequestLatency("create", getTypeName(obj), startTime)
 | 
							metrics.RecordEtcdRequestLatency("create", getTypeName(obj), startTime)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -213,7 +246,7 @@ func (h *etcdHelper) Delete(ctx context.Context, key string, out runtime.Object)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startTime := time.Now()
 | 
						startTime := time.Now()
 | 
				
			||||||
	response, err := h.client.Delete(key, false)
 | 
						response, err := h.client.Delete(ctx, key, nil)
 | 
				
			||||||
	metrics.RecordEtcdRequestLatency("delete", getTypeName(out), startTime)
 | 
						metrics.RecordEtcdRequestLatency("delete", getTypeName(out), startTime)
 | 
				
			||||||
	if !etcdutil.IsEtcdNotFound(err) {
 | 
						if !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
		// if the object that existed prior to the delete is returned by etcd, update out.
 | 
							// if the object that existed prior to the delete is returned by etcd, update out.
 | 
				
			||||||
@@ -235,7 +268,7 @@ func (h *etcdHelper) Watch(ctx context.Context, key string, resourceVersion stri
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	key = h.prefixEtcdKey(key)
 | 
						key = h.prefixEtcdKey(key)
 | 
				
			||||||
	w := newEtcdWatcher(false, nil, filter, h.codec, h.versioner, nil, h)
 | 
						w := newEtcdWatcher(false, nil, filter, h.codec, h.versioner, nil, h)
 | 
				
			||||||
	go w.etcdWatch(h.client, key, watchRV)
 | 
						go w.etcdWatch(ctx, h.client, key, watchRV)
 | 
				
			||||||
	return w, nil
 | 
						return w, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -250,7 +283,7 @@ func (h *etcdHelper) WatchList(ctx context.Context, key string, resourceVersion
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	key = h.prefixEtcdKey(key)
 | 
						key = h.prefixEtcdKey(key)
 | 
				
			||||||
	w := newEtcdWatcher(true, exceptKey(key), filter, h.codec, h.versioner, nil, h)
 | 
						w := newEtcdWatcher(true, exceptKey(key), filter, h.codec, h.versioner, nil, h)
 | 
				
			||||||
	go w.etcdWatch(h.client, key, watchRV)
 | 
						go w.etcdWatch(ctx, h.client, key, watchRV)
 | 
				
			||||||
	return w, nil
 | 
						return w, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -271,7 +304,7 @@ func (h *etcdHelper) bodyAndExtractObj(ctx context.Context, key string, objPtr r
 | 
				
			|||||||
		glog.Errorf("Context is nil")
 | 
							glog.Errorf("Context is nil")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	startTime := time.Now()
 | 
						startTime := time.Now()
 | 
				
			||||||
	response, err := h.client.Get(key, false, false)
 | 
						response, err := h.client.Get(ctx, key, nil)
 | 
				
			||||||
	metrics.RecordEtcdRequestLatency("get", getTypeName(objPtr), startTime)
 | 
						metrics.RecordEtcdRequestLatency("get", getTypeName(objPtr), startTime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil && !etcdutil.IsEtcdNotFound(err) {
 | 
						if err != nil && !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
@@ -324,7 +357,7 @@ func (h *etcdHelper) GetToList(ctx context.Context, key string, filter storage.F
 | 
				
			|||||||
	key = h.prefixEtcdKey(key)
 | 
						key = h.prefixEtcdKey(key)
 | 
				
			||||||
	startTime := time.Now()
 | 
						startTime := time.Now()
 | 
				
			||||||
	trace.Step("About to read etcd node")
 | 
						trace.Step("About to read etcd node")
 | 
				
			||||||
	response, err := h.client.Get(key, false, false)
 | 
						response, err := h.client.Get(ctx, key, nil)
 | 
				
			||||||
	metrics.RecordEtcdRequestLatency("get", getTypeName(listPtr), startTime)
 | 
						metrics.RecordEtcdRequestLatency("get", getTypeName(listPtr), startTime)
 | 
				
			||||||
	trace.Step("Etcd node read")
 | 
						trace.Step("Etcd node read")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -342,7 +375,7 @@ func (h *etcdHelper) GetToList(ctx context.Context, key string, filter storage.F
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	trace.Step("Object decoded")
 | 
						trace.Step("Object decoded")
 | 
				
			||||||
	if h.versioner != nil {
 | 
						if h.versioner != nil {
 | 
				
			||||||
		if err := h.versioner.UpdateList(listObj, response.EtcdIndex); err != nil {
 | 
							if err := h.versioner.UpdateList(listObj, response.Index); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -429,10 +462,14 @@ func (h *etcdHelper) listEtcdNode(ctx context.Context, key string) ([]*etcd.Node
 | 
				
			|||||||
	if ctx == nil {
 | 
						if ctx == nil {
 | 
				
			||||||
		glog.Errorf("Context is nil")
 | 
							glog.Errorf("Context is nil")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	result, err := h.client.Get(key, true, true)
 | 
						opts := etcd.GetOptions{
 | 
				
			||||||
 | 
							Recursive: true,
 | 
				
			||||||
 | 
							Sort:      true,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err := h.client.Get(ctx, key, &opts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		var index uint64
 | 
							var index uint64
 | 
				
			||||||
		if etcdError, ok := err.(*etcd.EtcdError); ok {
 | 
							if etcdError, ok := err.(etcd.Error); ok {
 | 
				
			||||||
			index = etcdError.Index
 | 
								index = etcdError.Index
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		nodes := make([]*etcd.Node, 0)
 | 
							nodes := make([]*etcd.Node, 0)
 | 
				
			||||||
@@ -442,7 +479,7 @@ func (h *etcdHelper) listEtcdNode(ctx context.Context, key string) ([]*etcd.Node
 | 
				
			|||||||
			return nodes, index, err
 | 
								return nodes, index, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result.Node.Nodes, result.EtcdIndex, nil
 | 
						return result.Node.Nodes, result.Index, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implements storage.Interface.
 | 
					// Implements storage.Interface.
 | 
				
			||||||
@@ -487,7 +524,7 @@ func (h *etcdHelper) GuaranteedUpdate(ctx context.Context, key string, ptrToType
 | 
				
			|||||||
				ttl = 1
 | 
									ttl = 1
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if res != nil {
 | 
							} else if res != nil {
 | 
				
			||||||
			index = res.EtcdIndex
 | 
								index = res.Index
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if newTTL != nil {
 | 
							if newTTL != nil {
 | 
				
			||||||
@@ -506,7 +543,11 @@ func (h *etcdHelper) GuaranteedUpdate(ctx context.Context, key string, ptrToType
 | 
				
			|||||||
		// First time this key has been used, try creating new value.
 | 
							// First time this key has been used, try creating new value.
 | 
				
			||||||
		if index == 0 {
 | 
							if index == 0 {
 | 
				
			||||||
			startTime := time.Now()
 | 
								startTime := time.Now()
 | 
				
			||||||
			response, err := h.client.Create(key, string(data), ttl)
 | 
								opts := etcd.SetOptions{
 | 
				
			||||||
 | 
									TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
									PrevExist: etcd.PrevNoExist,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								response, err := h.client.Set(ctx, key, string(data), &opts)
 | 
				
			||||||
			metrics.RecordEtcdRequestLatency("create", getTypeName(ptrToType), startTime)
 | 
								metrics.RecordEtcdRequestLatency("create", getTypeName(ptrToType), startTime)
 | 
				
			||||||
			if etcdutil.IsEtcdNodeExist(err) {
 | 
								if etcdutil.IsEtcdNodeExist(err) {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
@@ -521,7 +562,12 @@ func (h *etcdHelper) GuaranteedUpdate(ctx context.Context, key string, ptrToType
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		startTime := time.Now()
 | 
							startTime := time.Now()
 | 
				
			||||||
		// Swap origBody with data, if origBody is the latest etcd data.
 | 
							// Swap origBody with data, if origBody is the latest etcd data.
 | 
				
			||||||
		response, err := h.client.CompareAndSwap(key, string(data), ttl, origBody, index)
 | 
							opts := etcd.SetOptions{
 | 
				
			||||||
 | 
								PrevValue: origBody,
 | 
				
			||||||
 | 
								PrevIndex: index,
 | 
				
			||||||
 | 
								TTL:       time.Duration(ttl) * time.Second,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							response, err := h.client.Set(ctx, key, string(data), &opts)
 | 
				
			||||||
		metrics.RecordEtcdRequestLatency("compareAndSwap", getTypeName(ptrToType), startTime)
 | 
							metrics.RecordEtcdRequestLatency("compareAndSwap", getTypeName(ptrToType), startTime)
 | 
				
			||||||
		if etcdutil.IsEtcdTestFailed(err) {
 | 
							if etcdutil.IsEtcdTestFailed(err) {
 | 
				
			||||||
			// Try again.
 | 
								// Try again.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -55,7 +55,7 @@ func init() {
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newEtcdHelper(client *etcd.Client, codec runtime.Codec, prefix string) etcdHelper {
 | 
					func newEtcdHelper(client etcd.Client, codec runtime.Codec, prefix string) etcdHelper {
 | 
				
			||||||
	return *NewEtcdStorage(client, codec, prefix).(*etcdHelper)
 | 
						return *NewEtcdStorage(client, codec, prefix).(*etcdHelper)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,8 +29,9 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/util"
 | 
						"k8s.io/kubernetes/pkg/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Etcd watch event actions
 | 
					// Etcd watch event actions
 | 
				
			||||||
@@ -85,7 +86,8 @@ type etcdWatcher struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	etcdIncoming  chan *etcd.Response
 | 
						etcdIncoming  chan *etcd.Response
 | 
				
			||||||
	etcdError     chan error
 | 
						etcdError     chan error
 | 
				
			||||||
	etcdStop      chan bool
 | 
						ctx           context.Context
 | 
				
			||||||
 | 
						cancel        context.CancelFunc
 | 
				
			||||||
	etcdCallEnded chan struct{}
 | 
						etcdCallEnded chan struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outgoing chan watch.Event
 | 
						outgoing chan watch.Event
 | 
				
			||||||
@@ -124,10 +126,12 @@ func newEtcdWatcher(list bool, include includeFunc, filter storage.FilterFunc, e
 | 
				
			|||||||
		// monitor how much of this buffer is actually used.
 | 
							// monitor how much of this buffer is actually used.
 | 
				
			||||||
		etcdIncoming: make(chan *etcd.Response, 100),
 | 
							etcdIncoming: make(chan *etcd.Response, 100),
 | 
				
			||||||
		etcdError:    make(chan error, 1),
 | 
							etcdError:    make(chan error, 1),
 | 
				
			||||||
		etcdStop:     make(chan bool),
 | 
					 | 
				
			||||||
		outgoing:     make(chan watch.Event),
 | 
							outgoing:     make(chan watch.Event),
 | 
				
			||||||
		userStop:     make(chan struct{}),
 | 
							userStop:     make(chan struct{}),
 | 
				
			||||||
 | 
							stopped:      false,
 | 
				
			||||||
		cache:        cache,
 | 
							cache:        cache,
 | 
				
			||||||
 | 
							ctx:          nil,
 | 
				
			||||||
 | 
							cancel:       nil,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	w.emit = func(e watch.Event) { w.outgoing <- e }
 | 
						w.emit = func(e watch.Event) { w.outgoing <- e }
 | 
				
			||||||
	go w.translate()
 | 
						go w.translate()
 | 
				
			||||||
@@ -136,37 +140,54 @@ func newEtcdWatcher(list bool, include includeFunc, filter storage.FilterFunc, e
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// etcdWatch calls etcd's Watch function, and handles any errors. Meant to be called
 | 
					// etcdWatch calls etcd's Watch function, and handles any errors. Meant to be called
 | 
				
			||||||
// as a goroutine.
 | 
					// as a goroutine.
 | 
				
			||||||
func (w *etcdWatcher) etcdWatch(client *etcd.Client, key string, resourceVersion uint64) {
 | 
					func (w *etcdWatcher) etcdWatch(ctx context.Context, client etcd.KeysAPI, key string, resourceVersion uint64) {
 | 
				
			||||||
	defer util.HandleCrash()
 | 
						defer util.HandleCrash()
 | 
				
			||||||
	defer close(w.etcdError)
 | 
						defer close(w.etcdError)
 | 
				
			||||||
 | 
						defer close(w.etcdIncoming)
 | 
				
			||||||
	if resourceVersion == 0 {
 | 
						if resourceVersion == 0 {
 | 
				
			||||||
		latest, err := etcdGetInitialWatchState(client, key, w.list, w.etcdIncoming)
 | 
							latest, err := etcdGetInitialWatchState(ctx, client, key, w.list, w.etcdIncoming)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			w.etcdError <- err
 | 
								w.etcdError <- err
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		resourceVersion = latest + 1
 | 
							resourceVersion = latest
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, err := client.Watch(key, resourceVersion, w.list, w.etcdIncoming, w.etcdStop)
 | 
					
 | 
				
			||||||
	if err != nil && err != etcd.ErrWatchStoppedByUser {
 | 
						opts := etcd.WatcherOptions{
 | 
				
			||||||
		w.etcdError <- err
 | 
							Recursive:  w.list,
 | 
				
			||||||
 | 
							AfterIndex: resourceVersion,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						watcher := client.Watcher(key, &opts)
 | 
				
			||||||
 | 
						w.ctx, w.cancel = context.WithCancel(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							resp, err := watcher.Next(w.ctx)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								w.etcdError <- err
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							w.etcdIncoming <- resp
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// etcdGetInitialWatchState turns an etcd Get request into a watch equivalent
 | 
					// etcdGetInitialWatchState turns an etcd Get request into a watch equivalent
 | 
				
			||||||
func etcdGetInitialWatchState(client *etcd.Client, key string, recursive bool, incoming chan<- *etcd.Response) (resourceVersion uint64, err error) {
 | 
					func etcdGetInitialWatchState(ctx context.Context, client etcd.KeysAPI, key string, recursive bool, incoming chan<- *etcd.Response) (resourceVersion uint64, err error) {
 | 
				
			||||||
	resp, err := client.Get(key, false, recursive)
 | 
						opts := etcd.GetOptions{
 | 
				
			||||||
 | 
							Recursive: recursive,
 | 
				
			||||||
 | 
							Sort:      false,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						resp, err := client.Get(ctx, key, &opts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if !etcdutil.IsEtcdNotFound(err) {
 | 
							if !etcdutil.IsEtcdNotFound(err) {
 | 
				
			||||||
			glog.Errorf("watch was unable to retrieve the current index for the provided key (%q): %v", key, err)
 | 
								glog.Errorf("watch was unable to retrieve the current index for the provided key (%q): %v", key, err)
 | 
				
			||||||
			return resourceVersion, err
 | 
								return resourceVersion, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if etcdError, ok := err.(*etcd.EtcdError); ok {
 | 
							if etcdError, ok := err.(etcd.Error); ok {
 | 
				
			||||||
			resourceVersion = etcdError.Index
 | 
								resourceVersion = etcdError.Index
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return resourceVersion, nil
 | 
							return resourceVersion, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resourceVersion = resp.EtcdIndex
 | 
						resourceVersion = resp.Index
 | 
				
			||||||
	convertRecursiveResponse(resp.Node, resp, incoming)
 | 
						convertRecursiveResponse(resp.Node, resp, incoming)
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -228,7 +249,6 @@ func (w *etcdWatcher) translate() {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		case <-w.userStop:
 | 
							case <-w.userStop:
 | 
				
			||||||
			w.etcdStop <- true
 | 
					 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		case res, ok := <-w.etcdIncoming:
 | 
							case res, ok := <-w.etcdIncoming:
 | 
				
			||||||
			if ok {
 | 
								if ok {
 | 
				
			||||||
@@ -407,7 +427,10 @@ func (w *etcdWatcher) ResultChan() <-chan watch.Event {
 | 
				
			|||||||
func (w *etcdWatcher) Stop() {
 | 
					func (w *etcdWatcher) Stop() {
 | 
				
			||||||
	w.stopLock.Lock()
 | 
						w.stopLock.Lock()
 | 
				
			||||||
	defer w.stopLock.Unlock()
 | 
						defer w.stopLock.Unlock()
 | 
				
			||||||
	// Prevent double channel closes.
 | 
						if w.cancel != nil {
 | 
				
			||||||
 | 
							w.cancel()
 | 
				
			||||||
 | 
							w.cancel = nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if !w.stopped {
 | 
						if !w.stopped {
 | 
				
			||||||
		w.stopped = true
 | 
							w.stopped = true
 | 
				
			||||||
		close(w.userStop)
 | 
							close(w.userStop)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
						"k8s.io/kubernetes/pkg/api/testapi"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
@@ -31,6 +30,7 @@ import (
 | 
				
			|||||||
	etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
 | 
						etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,15 +217,11 @@ func TestWatchInterpretation_ResponseBadData(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* TODO: So believe it or not... but this test is flakey with the go-etcd client library
 | 
					 | 
				
			||||||
 * which I'm surprised by.  Apprently you can close the client that is performing the watch
 | 
					 | 
				
			||||||
 * and the watch *never returns.*  I would like to still keep this test here and re-enable
 | 
					 | 
				
			||||||
 * with the new 2.2+ client library.
 | 
					 | 
				
			||||||
func TestWatchEtcdError(t *testing.T) {
 | 
					func TestWatchEtcdError(t *testing.T) {
 | 
				
			||||||
	codec := testapi.Default.Codec()
 | 
						codec := testapi.Default.Codec()
 | 
				
			||||||
	server := etcdtesting.NewEtcdTestClientServer(t)
 | 
						server := etcdtesting.NewEtcdTestClientServer(t)
 | 
				
			||||||
	h := newEtcdHelper(server.Client, codec, etcdtest.PathPrefix())
 | 
						h := newEtcdHelper(server.Client, codec, etcdtest.PathPrefix())
 | 
				
			||||||
	watching, err := h.Watch(context.TODO(), "/some/key", 4, storage.Everything)
 | 
						watching, err := h.Watch(context.TODO(), "/some/key", "4", storage.Everything)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("Unexpected error: %v", err)
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -236,7 +232,7 @@ func TestWatchEtcdError(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Unexpected non-error")
 | 
							t.Fatalf("Unexpected non-error")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	watching.Stop()
 | 
						watching.Stop()
 | 
				
			||||||
} */
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestWatch(t *testing.T) {
 | 
					func TestWatch(t *testing.T) {
 | 
				
			||||||
	codec := testapi.Default.Codec()
 | 
						codec := testapi.Default.Codec()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,19 +26,19 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/coreos/etcd/etcdserver"
 | 
						"github.com/coreos/etcd/etcdserver"
 | 
				
			||||||
	"github.com/coreos/etcd/etcdserver/etcdhttp"
 | 
						"github.com/coreos/etcd/etcdserver/etcdhttp"
 | 
				
			||||||
	"github.com/coreos/etcd/pkg/transport"
 | 
						"github.com/coreos/etcd/pkg/transport"
 | 
				
			||||||
	"github.com/coreos/etcd/pkg/types"
 | 
						"github.com/coreos/etcd/pkg/types"
 | 
				
			||||||
	"github.com/coreos/etcd/rafthttp"
 | 
						"github.com/coreos/etcd/rafthttp"
 | 
				
			||||||
	goetcd "github.com/coreos/go-etcd/etcd"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EtcdTestServer encapsulates the datastructures needed to start local instance for testing
 | 
					// EtcdTestServer encapsulates the datastructures needed to start local instance for testing
 | 
				
			||||||
type EtcdTestServer struct {
 | 
					type EtcdTestServer struct {
 | 
				
			||||||
	etcdserver.ServerConfig
 | 
						etcdserver.ServerConfig
 | 
				
			||||||
	PeerListeners, ClientListeners []net.Listener
 | 
						PeerListeners, ClientListeners []net.Listener
 | 
				
			||||||
	Client                         *goetcd.Client
 | 
						Client                         etcd.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	raftHandler http.Handler
 | 
						raftHandler http.Handler
 | 
				
			||||||
	s           *etcdserver.EtcdServer
 | 
						s           *etcdserver.EtcdServer
 | 
				
			||||||
@@ -126,7 +126,7 @@ func (m *EtcdTestServer) launch(t *testing.T) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Terminate will shutdown the running etcd server
 | 
					// Terminate will shutdown the running etcd server
 | 
				
			||||||
func (m *EtcdTestServer) Terminate(t *testing.T) {
 | 
					func (m *EtcdTestServer) Terminate(t *testing.T) {
 | 
				
			||||||
	m.Client.Close()
 | 
						m.Client = nil
 | 
				
			||||||
	m.s.Stop()
 | 
						m.s.Stop()
 | 
				
			||||||
	for _, hs := range m.hss {
 | 
						for _, hs := range m.hss {
 | 
				
			||||||
		hs.CloseClientConnections()
 | 
							hs.CloseClientConnections()
 | 
				
			||||||
@@ -145,9 +145,12 @@ func NewEtcdTestClientServer(t *testing.T) *EtcdTestServer {
 | 
				
			|||||||
		t.Fatal("Failed to start etcd server error=%v", err)
 | 
							t.Fatal("Failed to start etcd server error=%v", err)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	server.Client = goetcd.NewClient(server.ClientURLs.StringSlice())
 | 
						cfg := etcd.Config{
 | 
				
			||||||
	if server.Client == nil {
 | 
							Endpoints: server.ClientURLs.StringSlice(),
 | 
				
			||||||
		t.Errorf("Failed to connect to local etcd server")
 | 
						}
 | 
				
			||||||
 | 
						server.Client, err = etcd.New(cfg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected Error in NewEtcdTestClientServer (%v)", err)
 | 
				
			||||||
		defer server.Terminate(t)
 | 
							defer server.Terminate(t)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,56 +22,46 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	goetcd "github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	etcdErrorCodeNotFound      = 100
 | 
					 | 
				
			||||||
	etcdErrorCodeTestFailed    = 101
 | 
					 | 
				
			||||||
	etcdErrorCodeNodeExist     = 105
 | 
					 | 
				
			||||||
	etcdErrorCodeValueRequired = 200
 | 
					 | 
				
			||||||
	etcdErrorCodeWatchExpired  = 401
 | 
					 | 
				
			||||||
	etcdErrorCodeUnreachable   = 501
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	etcdErrorNotFound      = &goetcd.EtcdError{ErrorCode: etcdErrorCodeNotFound}
 | 
					 | 
				
			||||||
	etcdErrorTestFailed    = &goetcd.EtcdError{ErrorCode: etcdErrorCodeTestFailed}
 | 
					 | 
				
			||||||
	etcdErrorNodeExist     = &goetcd.EtcdError{ErrorCode: etcdErrorCodeNodeExist}
 | 
					 | 
				
			||||||
	etcdErrorValueRequired = &goetcd.EtcdError{ErrorCode: etcdErrorCodeValueRequired}
 | 
					 | 
				
			||||||
	etcdErrorWatchExpired  = &goetcd.EtcdError{ErrorCode: etcdErrorCodeWatchExpired}
 | 
					 | 
				
			||||||
	etcdErrorUnreachable   = &goetcd.EtcdError{ErrorCode: etcdErrorCodeUnreachable}
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsEtcdNotFound returns true if and only if err is an etcd not found error.
 | 
					// IsEtcdNotFound returns true if and only if err is an etcd not found error.
 | 
				
			||||||
func IsEtcdNotFound(err error) bool {
 | 
					func IsEtcdNotFound(err error) bool {
 | 
				
			||||||
	return isEtcdErrorNum(err, etcdErrorCodeNotFound)
 | 
						return isEtcdErrorNum(err, etcd.ErrorCodeKeyNotFound)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsEtcdNodeExist returns true if and only if err is an etcd node already exist error.
 | 
					// IsEtcdNodeExist returns true if and only if err is an etcd node already exist error.
 | 
				
			||||||
func IsEtcdNodeExist(err error) bool {
 | 
					func IsEtcdNodeExist(err error) bool {
 | 
				
			||||||
	return isEtcdErrorNum(err, etcdErrorCodeNodeExist)
 | 
						return isEtcdErrorNum(err, etcd.ErrorCodeNodeExist)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsEtcdTestFailed returns true if and only if err is an etcd write conflict.
 | 
					// IsEtcdTestFailed returns true if and only if err is an etcd write conflict.
 | 
				
			||||||
func IsEtcdTestFailed(err error) bool {
 | 
					func IsEtcdTestFailed(err error) bool {
 | 
				
			||||||
	return isEtcdErrorNum(err, etcdErrorCodeTestFailed)
 | 
						return isEtcdErrorNum(err, etcd.ErrorCodeTestFailed)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsEtcdWatchExpired returns true if and only if err indicates the watch has expired.
 | 
					// IsEtcdWatchExpired returns true if and only if err indicates the watch has expired.
 | 
				
			||||||
func IsEtcdWatchExpired(err error) bool {
 | 
					func IsEtcdWatchExpired(err error) bool {
 | 
				
			||||||
	return isEtcdErrorNum(err, etcdErrorCodeWatchExpired)
 | 
						// NOTE: This seems weird why it wouldn't be etcd.ErrorCodeWatcherCleared
 | 
				
			||||||
 | 
						//       I'm using the previous matching value
 | 
				
			||||||
 | 
						return isEtcdErrorNum(err, etcd.ErrorCodeEventIndexCleared)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsEtcdUnreachable returns true if and only if err indicates the server could not be reached.
 | 
					// IsEtcdUnreachable returns true if and only if err indicates the server could not be reached.
 | 
				
			||||||
func IsEtcdUnreachable(err error) bool {
 | 
					func IsEtcdUnreachable(err error) bool {
 | 
				
			||||||
	return isEtcdErrorNum(err, etcdErrorCodeUnreachable)
 | 
						// NOTE: The logic has changed previous error code no longer applies
 | 
				
			||||||
 | 
						return err == etcd.ErrClusterUnavailable
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// isEtcdErrorNum returns true if and only if err is an etcd error, whose errorCode matches errorCode
 | 
					// isEtcdErrorNum returns true if and only if err is an etcd error, whose errorCode matches errorCode
 | 
				
			||||||
func isEtcdErrorNum(err error, errorCode int) bool {
 | 
					func isEtcdErrorNum(err error, errorCode int) bool {
 | 
				
			||||||
	etcdError, ok := err.(*goetcd.EtcdError)
 | 
						if err != nil {
 | 
				
			||||||
	return ok && etcdError != nil && etcdError.ErrorCode == errorCode
 | 
							if etcdError, ok := err.(etcd.Error); ok {
 | 
				
			||||||
 | 
								return etcdError.Code == errorCode
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// NOTE: There are other error types returned
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetEtcdVersion performs a version check against the provided Etcd server,
 | 
					// GetEtcdVersion performs a version check against the provided Etcd server,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,8 +38,7 @@ func TestIsEtcdNotFound(t *testing.T) {
 | 
				
			|||||||
			t.Errorf("Expected %#v to return %v, but it did not", err, isNotFound)
 | 
								t.Errorf("Expected %#v to return %v, but it did not", err, isNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	try(etcdErrorNotFound, true)
 | 
						try(&etcd.Error{Code: 101}, false)
 | 
				
			||||||
	try(&etcd.EtcdError{ErrorCode: 101}, false)
 | 
					 | 
				
			||||||
	try(nil, false)
 | 
						try(nil, false)
 | 
				
			||||||
	try(fmt.Errorf("some other kind of error"), false)
 | 
						try(fmt.Errorf("some other kind of error"), false)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,13 +95,15 @@ type Interface interface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Watch begins watching the specified key. Events are decoded into API objects,
 | 
						// Watch begins watching the specified key. Events are decoded into API objects,
 | 
				
			||||||
	// and any items passing 'filter' are sent down to returned watch.Interface.
 | 
						// and any items passing 'filter' are sent down to returned watch.Interface.
 | 
				
			||||||
	// resourceVersion may be used to specify what version to begin watching
 | 
						// resourceVersion may be used to specify what version to begin watching,
 | 
				
			||||||
 | 
						// which should be the current resourceVersion, and no longer rv+1
 | 
				
			||||||
	// (e.g. reconnecting without missing any updates).
 | 
						// (e.g. reconnecting without missing any updates).
 | 
				
			||||||
	Watch(ctx context.Context, key string, resourceVersion string, filter FilterFunc) (watch.Interface, error)
 | 
						Watch(ctx context.Context, key string, resourceVersion string, filter FilterFunc) (watch.Interface, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// WatchList begins watching the specified key's items. Items are decoded into API
 | 
						// WatchList begins watching the specified key's items. Items are decoded into API
 | 
				
			||||||
	// objects and any item passing 'filter' are sent down to returned watch.Interface.
 | 
						// objects and any item passing 'filter' are sent down to returned watch.Interface.
 | 
				
			||||||
	// resourceVersion may be used to specify what version to begin watching
 | 
						// resourceVersion may be used to specify what version to begin watching,
 | 
				
			||||||
 | 
						// which should be the current resourceVersion, and no longer rv+1
 | 
				
			||||||
	// (e.g. reconnecting without missing any updates).
 | 
						// (e.g. reconnecting without missing any updates).
 | 
				
			||||||
	WatchList(ctx context.Context, key string, resourceVersion string, filter FilterFunc) (watch.Interface, error)
 | 
						WatchList(ctx context.Context, key string, resourceVersion string, filter FilterFunc) (watch.Interface, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ func ParseWatchResourceVersion(resourceVersion string) (uint64, error) {
 | 
				
			|||||||
			field.Invalid(field.NewPath("resourceVersion"), resourceVersion, err.Error()),
 | 
								field.Invalid(field.NewPath("resourceVersion"), resourceVersion, err.Error()),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return version + 1, nil
 | 
						return version, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ParseListResourceVersion takes a resource version argument and converts it to
 | 
					// ParseListResourceVersion takes a resource version argument and converts it to
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,8 +31,8 @@ func TestEtcdParseWatchResourceVersion(t *testing.T) {
 | 
				
			|||||||
		{Version: "", ExpectVersion: 0},
 | 
							{Version: "", ExpectVersion: 0},
 | 
				
			||||||
		{Version: "a", Err: true},
 | 
							{Version: "a", Err: true},
 | 
				
			||||||
		{Version: " ", Err: true},
 | 
							{Version: " ", Err: true},
 | 
				
			||||||
		{Version: "1", ExpectVersion: 2},
 | 
							{Version: "1", ExpectVersion: 1},
 | 
				
			||||||
		{Version: "10", ExpectVersion: 11},
 | 
							{Version: "10", ExpectVersion: 10},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, testCase := range testCases {
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
		version, err := ParseWatchResourceVersion(testCase.Version)
 | 
							version, err := ParseWatchResourceVersion(testCase.Version)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,24 +26,26 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
						"k8s.io/kubernetes/pkg/api/testapi"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/storage"
 | 
						"k8s.io/kubernetes/pkg/storage"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/storage/etcd"
 | 
						etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
 | 
						"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/watch"
 | 
						"k8s.io/kubernetes/pkg/watch"
 | 
				
			||||||
	"k8s.io/kubernetes/test/integration/framework"
 | 
						"k8s.io/kubernetes/test/integration/framework"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSet(t *testing.T) {
 | 
					func TestSet(t *testing.T) {
 | 
				
			||||||
	client := framework.NewEtcdClient()
 | 
						client := framework.NewEtcdClient()
 | 
				
			||||||
	etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
						keysAPI := etcd.NewKeysAPI(client)
 | 
				
			||||||
 | 
						etcdStorage := etcdstorage.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
				
			||||||
	ctx := context.TODO()
 | 
						ctx := context.TODO()
 | 
				
			||||||
	framework.WithEtcdKey(func(key string) {
 | 
						framework.WithEtcdKey(func(key string) {
 | 
				
			||||||
		testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
							testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
				
			||||||
		if err := etcdStorage.Set(ctx, key, &testObject, nil, 0); err != nil {
 | 
							if err := etcdStorage.Set(ctx, key, &testObject, nil, 0); err != nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v", err)
 | 
								t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		resp, err := client.Get(key, false, false)
 | 
							resp, err := keysAPI.Get(ctx, key, nil)
 | 
				
			||||||
		if err != nil || resp.Node == nil {
 | 
							if err != nil || resp.Node == nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v %v", err, resp)
 | 
								t.Fatalf("unexpected error: %v %v", err, resp)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -60,7 +62,8 @@ func TestSet(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestGet(t *testing.T) {
 | 
					func TestGet(t *testing.T) {
 | 
				
			||||||
	client := framework.NewEtcdClient()
 | 
						client := framework.NewEtcdClient()
 | 
				
			||||||
	etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
						keysAPI := etcd.NewKeysAPI(client)
 | 
				
			||||||
 | 
						etcdStorage := etcdstorage.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
				
			||||||
	ctx := context.TODO()
 | 
						ctx := context.TODO()
 | 
				
			||||||
	framework.WithEtcdKey(func(key string) {
 | 
						framework.WithEtcdKey(func(key string) {
 | 
				
			||||||
		testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
							testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
				
			||||||
@@ -68,7 +71,7 @@ func TestGet(t *testing.T) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v", err)
 | 
								t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_, err = client.Set(key, string(coded), 0)
 | 
							_, err = keysAPI.Set(ctx, key, string(coded), nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v", err)
 | 
								t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -86,7 +89,8 @@ func TestGet(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestWriteTTL(t *testing.T) {
 | 
					func TestWriteTTL(t *testing.T) {
 | 
				
			||||||
	client := framework.NewEtcdClient()
 | 
						client := framework.NewEtcdClient()
 | 
				
			||||||
	etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
						keysAPI := etcd.NewKeysAPI(client)
 | 
				
			||||||
 | 
						etcdStorage := etcdstorage.NewEtcdStorage(client, testapi.Default.Codec(), "")
 | 
				
			||||||
	ctx := context.TODO()
 | 
						ctx := context.TODO()
 | 
				
			||||||
	framework.WithEtcdKey(func(key string) {
 | 
						framework.WithEtcdKey(func(key string) {
 | 
				
			||||||
		testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
							testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}}
 | 
				
			||||||
@@ -111,7 +115,7 @@ func TestWriteTTL(t *testing.T) {
 | 
				
			|||||||
		if result.Name != "out" {
 | 
							if result.Name != "out" {
 | 
				
			||||||
			t.Errorf("unexpected response: %#v", result)
 | 
								t.Errorf("unexpected response: %#v", result)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if res, err := client.Get(key, false, false); err != nil || res == nil || res.Node.TTL != 10 {
 | 
							if res, err := keysAPI.Get(ctx, key, nil); err != nil || res == nil || res.Node.TTL != 10 {
 | 
				
			||||||
			t.Fatalf("unexpected get: %v %#v", err, res)
 | 
								t.Fatalf("unexpected get: %v %#v", err, res)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,7 +136,7 @@ func TestWriteTTL(t *testing.T) {
 | 
				
			|||||||
		if result.Name != "out2" {
 | 
							if result.Name != "out2" {
 | 
				
			||||||
			t.Errorf("unexpected response: %#v", result)
 | 
								t.Errorf("unexpected response: %#v", result)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if res, err := client.Get(key, false, false); err != nil || res == nil || res.Node.TTL <= 1 {
 | 
							if res, err := keysAPI.Get(ctx, key, nil); err != nil || res == nil || res.Node.TTL <= 1 {
 | 
				
			||||||
			t.Fatalf("unexpected get: %v %#v", err, res)
 | 
								t.Fatalf("unexpected get: %v %#v", err, res)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -140,11 +144,12 @@ func TestWriteTTL(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestWatch(t *testing.T) {
 | 
					func TestWatch(t *testing.T) {
 | 
				
			||||||
	client := framework.NewEtcdClient()
 | 
						client := framework.NewEtcdClient()
 | 
				
			||||||
	etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), etcdtest.PathPrefix())
 | 
						keysAPI := etcd.NewKeysAPI(client)
 | 
				
			||||||
 | 
						etcdStorage := etcdstorage.NewEtcdStorage(client, testapi.Default.Codec(), etcdtest.PathPrefix())
 | 
				
			||||||
	ctx := context.TODO()
 | 
						ctx := context.TODO()
 | 
				
			||||||
	framework.WithEtcdKey(func(key string) {
 | 
						framework.WithEtcdKey(func(key string) {
 | 
				
			||||||
		key = etcdtest.AddPrefix(key)
 | 
							key = etcdtest.AddPrefix(key)
 | 
				
			||||||
		resp, err := client.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0)
 | 
							resp, err := keysAPI.Set(ctx, key, runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}), nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v", err)
 | 
								t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -178,7 +183,7 @@ func TestWatch(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// should return the previously deleted item in the watch, but with the latest index
 | 
							// should return the previously deleted item in the watch, but with the latest index
 | 
				
			||||||
		resp, err = client.Delete(key, false)
 | 
							resp, err = keysAPI.Delete(ctx, key, nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("unexpected error: %v", err)
 | 
								t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,10 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
						"k8s.io/kubernetes/pkg/api/testapi"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/storage"
 | 
						"k8s.io/kubernetes/pkg/storage"
 | 
				
			||||||
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
 | 
						etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
 | 
				
			||||||
@@ -35,15 +37,22 @@ func init() {
 | 
				
			|||||||
	RequireEtcd()
 | 
						RequireEtcd()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewEtcdClient() *etcd.Client {
 | 
					func NewEtcdClient() etcd.Client {
 | 
				
			||||||
	return etcd.NewClient([]string{})
 | 
						cfg := etcd.Config{
 | 
				
			||||||
 | 
							Endpoints: []string{"http://127.0.0.1:4001"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						client, err := etcd.New(cfg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Fatalf("unable to connect to etcd for testing: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewEtcdStorage() storage.Interface {
 | 
					func NewEtcdStorage() storage.Interface {
 | 
				
			||||||
	return etcdstorage.NewEtcdStorage(NewEtcdClient(), testapi.Default.Codec(), etcdtest.PathPrefix())
 | 
						return etcdstorage.NewEtcdStorage(NewEtcdClient(), testapi.Default.Codec(), etcdtest.PathPrefix())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewExtensionsEtcdStorage(client *etcd.Client) storage.Interface {
 | 
					func NewExtensionsEtcdStorage(client etcd.Client) storage.Interface {
 | 
				
			||||||
	if client == nil {
 | 
						if client == nil {
 | 
				
			||||||
		client = NewEtcdClient()
 | 
							client = NewEtcdClient()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -51,14 +60,14 @@ func NewExtensionsEtcdStorage(client *etcd.Client) storage.Interface {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RequireEtcd() {
 | 
					func RequireEtcd() {
 | 
				
			||||||
	if _, err := NewEtcdClient().Get("/", false, false); err != nil {
 | 
						if _, err := etcd.NewKeysAPI(NewEtcdClient()).Get(context.TODO(), "/", nil); err != nil {
 | 
				
			||||||
		glog.Fatalf("unable to connect to etcd for testing: %v", err)
 | 
							glog.Fatalf("unable to connect to etcd for testing: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WithEtcdKey(f func(string)) {
 | 
					func WithEtcdKey(f func(string)) {
 | 
				
			||||||
	prefix := fmt.Sprintf("/test-%d", rand.Int63())
 | 
						prefix := fmt.Sprintf("/test-%d", rand.Int63())
 | 
				
			||||||
	defer NewEtcdClient().Delete(prefix, true)
 | 
						defer etcd.NewKeysAPI(NewEtcdClient()).Delete(context.TODO(), prefix, &etcd.DeleteOptions{Recursive: true})
 | 
				
			||||||
	f(prefix)
 | 
						f(prefix)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,13 +77,13 @@ func WithEtcdKey(f func(string)) {
 | 
				
			|||||||
// of the test run.
 | 
					// of the test run.
 | 
				
			||||||
func DeleteAllEtcdKeys() {
 | 
					func DeleteAllEtcdKeys() {
 | 
				
			||||||
	glog.Infof("Deleting all etcd keys")
 | 
						glog.Infof("Deleting all etcd keys")
 | 
				
			||||||
	client := NewEtcdClient()
 | 
						keysAPI := etcd.NewKeysAPI(NewEtcdClient())
 | 
				
			||||||
	keys, err := client.Get("/", false, false)
 | 
						keys, err := keysAPI.Get(context.TODO(), "/", nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatalf("Unable to list root etcd keys: %v", err)
 | 
							glog.Fatalf("Unable to list root etcd keys: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, node := range keys.Node.Nodes {
 | 
						for _, node := range keys.Node.Nodes {
 | 
				
			||||||
		if _, err := client.Delete(node.Key, true); err != nil {
 | 
							if _, err := keysAPI.Delete(context.TODO(), node.Key, &etcd.DeleteOptions{Recursive: true}); err != nil {
 | 
				
			||||||
			glog.Fatalf("Unable delete key: %v", err)
 | 
								glog.Fatalf("Unable delete key: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,34 +22,42 @@ import (
 | 
				
			|||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/coreos/go-etcd/etcd"
 | 
						etcd "github.com/coreos/etcd/client"
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newEtcdClient() *etcd.Client {
 | 
					func newEtcdClient() etcd.Client {
 | 
				
			||||||
	return etcd.NewClient([]string{})
 | 
						cfg := etcd.Config{
 | 
				
			||||||
 | 
							Endpoints: []string{"http://127.0.0.1:4001"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						client, err := etcd.New(cfg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Fatalf("unable to connect to etcd for testing: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func requireEtcd() {
 | 
					func requireEtcd() {
 | 
				
			||||||
	if _, err := newEtcdClient().Get("/", false, false); err != nil {
 | 
						if _, err := etcd.NewKeysAPI(newEtcdClient()).Get(context.TODO(), "/", nil); err != nil {
 | 
				
			||||||
		glog.Fatalf("unable to connect to etcd for integration testing: %v", err)
 | 
							glog.Fatalf("unable to connect to etcd for integration testing: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func withEtcdKey(f func(string)) {
 | 
					func withEtcdKey(f func(string)) {
 | 
				
			||||||
	prefix := fmt.Sprintf("/test-%d", rand.Int63())
 | 
						prefix := fmt.Sprintf("/test-%d", rand.Int63())
 | 
				
			||||||
	defer newEtcdClient().Delete(prefix, true)
 | 
						defer etcd.NewKeysAPI(newEtcdClient()).Delete(context.TODO(), prefix, &etcd.DeleteOptions{Recursive: true})
 | 
				
			||||||
	f(prefix)
 | 
						f(prefix)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func deleteAllEtcdKeys() {
 | 
					func deleteAllEtcdKeys() {
 | 
				
			||||||
	client := newEtcdClient()
 | 
						keysAPI := etcd.NewKeysAPI(newEtcdClient())
 | 
				
			||||||
	keys, err := client.Get("/", false, false)
 | 
						keys, err := keysAPI.Get(context.TODO(), "/", nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatalf("Unable to list root etcd keys: %v", err)
 | 
							glog.Fatalf("Unable to list root etcd keys: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, node := range keys.Node.Nodes {
 | 
						for _, node := range keys.Node.Nodes {
 | 
				
			||||||
		if _, err := client.Delete(node.Key, true); err != nil {
 | 
							if _, err := keysAPI.Delete(context.TODO(), node.Key, &etcd.DeleteOptions{Recursive: true}); err != nil {
 | 
				
			||||||
			glog.Fatalf("Unable delete key: %v", err)
 | 
								glog.Fatalf("Unable delete key: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user