Browse Source

*: remove unused pkgs

Xiang Li 11 years ago
parent
commit
2ba57ee75d
62 changed files with 10 additions and 9605 deletions
  1. 0 37
      conf/cluster_config.go
  2. 0 426
      conf/config.go
  3. 0 572
      conf/config_test.go
  4. 0 32
      conf/default.go
  5. 0 105
      conf/tls_config.go
  6. 0 133
      etcdserver/discovery.go
  7. 0 220
      etcdserver/etcd.go
  8. 0 207
      etcdserver/etcd_functional_test.go
  9. 0 168
      etcdserver/etcd_start_test.go
  10. 0 656
      etcdserver/etcd_test.go
  11. 3 2
      etcdserver/etcdhttp/http.go
  12. 2 1
      etcdserver/etcdhttp/http_test.go
  13. 0 0
      etcdserver/etcdserverpb/etcdserver.pb.go
  14. 0 0
      etcdserver/etcdserverpb/etcdserver.proto
  15. 0 0
      etcdserver/etcdserverpb/genproto.sh
  16. 0 0
      etcdserver/example_test.go
  17. 0 25
      etcdserver/package_stats.go
  18. 0 522
      etcdserver/participant.go
  19. 0 151
      etcdserver/peer.go
  20. 0 174
      etcdserver/peer_hub.go
  21. 0 77
      etcdserver/raft_follower_stats.go
  22. 0 140
      etcdserver/raft_handler.go
  23. 0 83
      etcdserver/raft_server_stats.go
  24. 1 1
      etcdserver/server.go
  25. 2 1
      etcdserver/server_test.go
  26. 0 137
      etcdserver/standby.go
  27. 0 89
      etcdserver/stats_queue.go
  28. 0 182
      etcdserver/v2_admin.go
  29. 0 99
      etcdserver/v2_apply.go
  30. 0 254
      etcdserver/v2_client.go
  31. 0 174
      etcdserver/v2_http.go
  32. 0 82
      etcdserver/v2_http_delete.go
  33. 0 293
      etcdserver/v2_http_endpoint_test.go
  34. 0 146
      etcdserver/v2_http_get.go
  35. 0 1080
      etcdserver/v2_http_kv_test.go
  36. 0 46
      etcdserver/v2_http_post.go
  37. 0 157
      etcdserver/v2_http_put.go
  38. 0 63
      etcdserver/v2_raft.go
  39. 0 103
      etcdserver/v2_store.go
  40. 0 454
      etcdserver/v2_store_cmd.pb.go
  41. 0 21
      etcdserver/v2_store_cmd.proto
  42. 0 82
      etcdserver/v2_usage.go
  43. 0 14
      etcdserver/version.go
  44. 0 94
      etcdserver/z_last_test.go
  45. 2 2
      main.go
  46. 0 93
      tests/functional/discovery_test.go
  47. 0 36
      tests/functional/etcd_direct_call.go
  48. 0 270
      tests/functional/etcd_tls_test.go
  49. 0 19
      tests/functional/init.go
  50. 0 65
      tests/functional/internal_version_test.go
  51. 0 103
      tests/functional/kill_leader_test.go
  52. 0 248
      tests/functional/multi_node_kill_all_and_recovery_test.go
  53. 0 195
      tests/functional/rejoin_test.go
  54. 0 200
      tests/functional/remove_node_test.go
  55. 0 67
      tests/functional/simple_multi_node_test.go
  56. 0 151
      tests/functional/simple_snapshot_test.go
  57. 0 342
      tests/functional/standby_test.go
  58. 0 258
      tests/functional/util.go
  59. 0 80
      tests/http_utils.go
  60. 0 69
      tests/mock/mock_store.go
  61. 0 62
      tests/mock/server_v2.go
  62. 0 42
      tests/server_utils.go

+ 0 - 37
conf/cluster_config.go

@@ -1,37 +0,0 @@
-package conf
-
-// ClusterConfig represents cluster-wide configuration settings.
-type ClusterConfig struct {
-	// ActiveSize is the maximum number of node that can join as Raft followers.
-	// Nodes that join the cluster after the limit is reached are standbys.
-	ActiveSize int `json:"activeSize"`
-
-	// RemoveDelay is the amount of time, in seconds, after a node is
-	// unreachable that it will be swapped out as a standby node.
-	RemoveDelay float64 `json:"removeDelay"`
-
-	// SyncInterval is the amount of time, in seconds, between
-	// cluster sync when it runs in standby mode.
-	SyncInterval float64 `json:"syncInterval"`
-}
-
-// NewClusterConfig returns a cluster configuration with default settings.
-func NewClusterConfig() *ClusterConfig {
-	return &ClusterConfig{
-		ActiveSize:   DefaultActiveSize,
-		RemoveDelay:  DefaultRemoveDelay,
-		SyncInterval: DefaultSyncInterval,
-	}
-}
-
-func (c *ClusterConfig) Sanitize() {
-	if c.ActiveSize < MinActiveSize {
-		c.ActiveSize = MinActiveSize
-	}
-	if c.RemoveDelay < MinRemoveDelay {
-		c.RemoveDelay = MinRemoveDelay
-	}
-	if c.SyncInterval < MinSyncInterval {
-		c.SyncInterval = MinSyncInterval
-	}
-}

+ 0 - 426
conf/config.go

@@ -1,426 +0,0 @@
-package conf
-
-import (
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"math/rand"
-	"net"
-	"net/url"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// The default location for the etcd configuration file.
-const DefaultSystemConfigPath = "/etc/etcd/etcd.conf"
-
-// Config represents the server configuration.
-type Config struct {
-	SystemPath string
-
-	Addr             string `env:"ETCD_ADDR"`
-	BindAddr         string `env:"ETCD_BIND_ADDR"`
-	CAFile           string `env:"ETCD_CA_FILE"`
-	CertFile         string `env:"ETCD_CERT_FILE"`
-	CPUProfileFile   string
-	CorsOrigins      []string `env:"ETCD_CORS"`
-	DataDir          string   `env:"ETCD_DATA_DIR"`
-	Discovery        string   `env:"ETCD_DISCOVERY"`
-	Force            bool
-	KeyFile          string   `env:"ETCD_KEY_FILE"`
-	HTTPReadTimeout  float64  `env:"ETCD_HTTP_READ_TIMEOUT"`
-	HTTPWriteTimeout float64  `env:"ETCD_HTTP_WRITE_TIMEOUT"`
-	Peers            []string `env:"ETCD_PEERS"`
-	PeersFile        string   `env:"ETCD_PEERS_FILE"`
-	MaxResultBuffer  int      `env:"ETCD_MAX_RESULT_BUFFER"`
-	MaxRetryAttempts int      `env:"ETCD_MAX_RETRY_ATTEMPTS"`
-	RetryInterval    float64  `env:"ETCD_RETRY_INTERVAL"`
-	Name             string   `env:"ETCD_NAME"`
-	Snapshot         bool     `env:"ETCD_SNAPSHOT"`
-	SnapshotCount    int      `env:"ETCD_SNAPSHOTCOUNT"`
-	ShowHelp         bool
-	ShowVersion      bool
-	Verbose          bool `env:"ETCD_VERBOSE"`
-	VeryVerbose      bool `env:"ETCD_VERY_VERBOSE"`
-	VeryVeryVerbose  bool `env:"ETCD_VERY_VERY_VERBOSE"`
-	Peer             struct {
-		Addr              string `env:"ETCD_PEER_ADDR"`
-		BindAddr          string `env:"ETCD_PEER_BIND_ADDR"`
-		CAFile            string `env:"ETCD_PEER_CA_FILE"`
-		CertFile          string `env:"ETCD_PEER_CERT_FILE"`
-		KeyFile           string `env:"ETCD_PEER_KEY_FILE"`
-		HeartbeatInterval int    `env:"ETCD_PEER_HEARTBEAT_INTERVAL"`
-		ElectionTimeout   int    `env:"ETCD_PEER_ELECTION_TIMEOUT"`
-	}
-	strTrace     string `env:"ETCD_TRACE"`
-	GraphiteHost string `env:"ETCD_GRAPHITE_HOST"`
-	Cluster      struct {
-		ActiveSize   int     `env:"ETCD_CLUSTER_ACTIVE_SIZE"`
-		RemoveDelay  float64 `env:"ETCD_CLUSTER_REMOVE_DELAY"`
-		SyncInterval float64 `env:"ETCD_CLUSTER_SYNC_INTERVAL"`
-	}
-}
-
-// New returns a Config initialized with default values.
-func New() *Config {
-	c := new(Config)
-	c.SystemPath = DefaultSystemConfigPath
-	c.Addr = "127.0.0.1:4001"
-	c.HTTPReadTimeout = DefaultReadTimeout
-	c.HTTPWriteTimeout = DefaultWriteTimeout
-	c.MaxResultBuffer = 1024
-	c.MaxRetryAttempts = 3
-	c.RetryInterval = 10.0
-	c.Snapshot = true
-	c.SnapshotCount = 10000
-	c.Peer.Addr = "127.0.0.1:7001"
-	c.Peer.HeartbeatInterval = DefaultHeartbeatInterval
-	c.Peer.ElectionTimeout = DefaultElectionTimeout
-	rand.Seed(time.Now().UTC().UnixNano())
-	// Make maximum twice as minimum.
-	c.RetryInterval = float64(50+rand.Int()%50) * DefaultHeartbeatInterval / 1000
-	c.Cluster.ActiveSize = DefaultActiveSize
-	c.Cluster.RemoveDelay = DefaultRemoveDelay
-	c.Cluster.SyncInterval = DefaultSyncInterval
-	return c
-}
-
-// Loads the configuration from the system config, command line config,
-// environment variables, and finally command line arguments.
-func (c *Config) Load(arguments []string) error {
-	var path string
-	f := flag.NewFlagSet("etcd", -1)
-	f.SetOutput(ioutil.Discard)
-	f.StringVar(&path, "config", "", "path to config file")
-	f.Parse(arguments)
-
-	// Load from the environment variables next.
-	if err := c.LoadEnv(); err != nil {
-		return err
-	}
-
-	// Load from command line flags.
-	if err := c.LoadFlags(arguments); err != nil {
-		return err
-	}
-
-	// Loads peers if a peer file was specified.
-	if err := c.LoadPeersFile(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// LoadEnv loads the configuration via environment variables.
-func (c *Config) LoadEnv() error {
-	if err := c.loadEnv(c); err != nil {
-		return err
-	}
-	if err := c.loadEnv(&c.Peer); err != nil {
-		return err
-	}
-	if err := c.loadEnv(&c.Cluster); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (c *Config) loadEnv(target interface{}) error {
-	value := reflect.Indirect(reflect.ValueOf(target))
-	typ := value.Type()
-	for i := 0; i < typ.NumField(); i++ {
-		field := typ.Field(i)
-
-		// Retrieve environment variable.
-		v := strings.TrimSpace(os.Getenv(field.Tag.Get("env")))
-		if v == "" {
-			continue
-		}
-
-		// Set the appropriate type.
-		switch field.Type.Kind() {
-		case reflect.Bool:
-			value.Field(i).SetBool(v != "0" && v != "false")
-		case reflect.Int:
-			newValue, err := strconv.ParseInt(v, 10, 0)
-			if err != nil {
-				return fmt.Errorf("Parse error: %s: %s", field.Tag.Get("env"), err)
-			}
-			value.Field(i).SetInt(newValue)
-		case reflect.String:
-			value.Field(i).SetString(v)
-		case reflect.Slice:
-			value.Field(i).Set(reflect.ValueOf(trimSplit(v, ",")))
-		case reflect.Float64:
-			newValue, err := strconv.ParseFloat(v, 64)
-			if err != nil {
-				return fmt.Errorf("Parse error: %s: %s", field.Tag.Get("env"), err)
-			}
-			value.Field(i).SetFloat(newValue)
-		}
-	}
-	return nil
-}
-
-// Loads configuration from command line flags.
-func (c *Config) LoadFlags(arguments []string) error {
-	var peers, cors, path string
-
-	f := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
-	f.SetOutput(ioutil.Discard)
-
-	f.BoolVar(&c.ShowHelp, "h", false, "")
-	f.BoolVar(&c.ShowHelp, "help", false, "")
-	f.BoolVar(&c.ShowVersion, "version", false, "")
-
-	f.BoolVar(&c.Force, "f", false, "")
-	f.BoolVar(&c.Force, "force", false, "")
-
-	f.BoolVar(&c.Verbose, "v", c.Verbose, "")
-	f.BoolVar(&c.VeryVerbose, "vv", c.VeryVerbose, "")
-	f.BoolVar(&c.VeryVeryVerbose, "vvv", c.VeryVeryVerbose, "")
-
-	f.StringVar(&peers, "peers", "", "")
-	f.StringVar(&c.PeersFile, "peers-file", c.PeersFile, "")
-
-	f.StringVar(&c.Name, "name", c.Name, "")
-	f.StringVar(&c.Addr, "addr", c.Addr, "")
-	f.StringVar(&c.Discovery, "discovery", c.Discovery, "")
-	f.StringVar(&c.BindAddr, "bind-addr", c.BindAddr, "")
-	f.StringVar(&c.Peer.Addr, "peer-addr", c.Peer.Addr, "")
-	f.StringVar(&c.Peer.BindAddr, "peer-bind-addr", c.Peer.BindAddr, "")
-
-	f.StringVar(&c.CAFile, "ca-file", c.CAFile, "")
-	f.StringVar(&c.CertFile, "cert-file", c.CertFile, "")
-	f.StringVar(&c.KeyFile, "key-file", c.KeyFile, "")
-
-	f.StringVar(&c.Peer.CAFile, "peer-ca-file", c.Peer.CAFile, "")
-	f.StringVar(&c.Peer.CertFile, "peer-cert-file", c.Peer.CertFile, "")
-	f.StringVar(&c.Peer.KeyFile, "peer-key-file", c.Peer.KeyFile, "")
-
-	f.Float64Var(&c.HTTPReadTimeout, "http-read-timeout", c.HTTPReadTimeout, "")
-	f.Float64Var(&c.HTTPWriteTimeout, "http-write-timeout", c.HTTPReadTimeout, "")
-
-	f.StringVar(&c.DataDir, "data-dir", c.DataDir, "")
-	f.IntVar(&c.MaxResultBuffer, "max-result-buffer", c.MaxResultBuffer, "")
-	f.IntVar(&c.MaxRetryAttempts, "max-retry-attempts", c.MaxRetryAttempts, "")
-	f.Float64Var(&c.RetryInterval, "retry-interval", c.RetryInterval, "")
-	f.IntVar(&c.Peer.HeartbeatInterval, "peer-heartbeat-interval", c.Peer.HeartbeatInterval, "")
-	f.IntVar(&c.Peer.ElectionTimeout, "peer-election-timeout", c.Peer.ElectionTimeout, "")
-
-	f.StringVar(&cors, "cors", "", "")
-
-	f.BoolVar(&c.Snapshot, "snapshot", c.Snapshot, "")
-	f.IntVar(&c.SnapshotCount, "snapshot-count", c.SnapshotCount, "")
-	f.StringVar(&c.CPUProfileFile, "cpuprofile", "", "")
-
-	f.StringVar(&c.strTrace, "trace", "", "")
-	f.StringVar(&c.GraphiteHost, "graphite-host", "", "")
-
-	f.IntVar(&c.Cluster.ActiveSize, "cluster-active-size", c.Cluster.ActiveSize, "")
-	f.Float64Var(&c.Cluster.RemoveDelay, "cluster-remove-delay", c.Cluster.RemoveDelay, "")
-	f.Float64Var(&c.Cluster.SyncInterval, "cluster-sync-interval", c.Cluster.SyncInterval, "")
-
-	// BEGIN IGNORED FLAGS
-	f.StringVar(&path, "config", "", "")
-	// BEGIN IGNORED FLAGS
-
-	if err := f.Parse(arguments); err != nil {
-		return err
-	}
-
-	// Convert some parameters to lists.
-	if peers != "" {
-		c.Peers = trimSplit(peers, ",")
-	}
-	if cors != "" {
-		c.CorsOrigins = trimSplit(cors, ",")
-	}
-
-	return nil
-}
-
-// LoadPeersFile loads the peers listed in the peers file.
-func (c *Config) LoadPeersFile() error {
-	if c.PeersFile == "" {
-		return nil
-	}
-
-	b, err := ioutil.ReadFile(c.PeersFile)
-	if err != nil {
-		return fmt.Errorf("Peers file error: %s", err)
-	}
-	c.Peers = trimSplit(string(b), ",")
-
-	return nil
-}
-
-// DataDirFromName sets the data dir from a machine name and issue a warning
-// that etcd is guessing.
-func (c *Config) DataDirFromName() {
-	c.DataDir = c.Name + ".etcd"
-	log.Printf("Using the directory %s as the etcd curation directory because a directory was not specified. ", c.DataDir)
-
-	return
-}
-
-// NameFromHostname sets the machine name from the hostname. This is to help
-// people get started without thinking up a name.
-func (c *Config) NameFromHostname() {
-	host, err := os.Hostname()
-	if err != nil && host == "" {
-		log.Fatal("Node name required and hostname not set. e.g. '-name=name'")
-	}
-	c.Name = host
-}
-
-// Reset removes all server configuration files.
-func (c *Config) Reset() error {
-	if err := os.RemoveAll(filepath.Join(c.DataDir, "log")); err != nil {
-		return err
-	}
-	if err := os.RemoveAll(filepath.Join(c.DataDir, "conf")); err != nil {
-		return err
-	}
-	if err := os.RemoveAll(filepath.Join(c.DataDir, "snapshot")); err != nil {
-		return err
-	}
-	if err := os.RemoveAll(filepath.Join(c.DataDir, "standby_info")); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Sanitize cleans the input fields.
-func (c *Config) Sanitize() error {
-	var err error
-	var url *url.URL
-
-	// Sanitize the URLs first.
-	if c.Addr, url, err = sanitizeURL(c.Addr, c.EtcdTLSInfo().Scheme()); err != nil {
-		return fmt.Errorf("Advertised URL: %s", err)
-	}
-	if c.BindAddr, err = sanitizeBindAddr(c.BindAddr, url); err != nil {
-		return fmt.Errorf("Listen Host: %s", err)
-	}
-	if c.Peer.Addr, url, err = sanitizeURL(c.Peer.Addr, c.PeerTLSInfo().Scheme()); err != nil {
-		return fmt.Errorf("Peer Advertised URL: %s", err)
-	}
-	if c.Peer.BindAddr, err = sanitizeBindAddr(c.Peer.BindAddr, url); err != nil {
-		return fmt.Errorf("Peer Listen Host: %s", err)
-	}
-
-	// Only guess the machine name if there is no data dir specified
-	// because the info file should have our name
-	if c.Name == "" && c.DataDir == "" {
-		c.NameFromHostname()
-	}
-
-	if c.DataDir == "" && c.Name != "" && !c.ShowVersion && !c.ShowHelp {
-		c.DataDirFromName()
-	}
-
-	return nil
-}
-
-// EtcdTLSInfo retrieves a TLSInfo object for the etcd server
-func (c *Config) EtcdTLSInfo() *TLSInfo {
-	return &TLSInfo{
-		CAFile:   c.CAFile,
-		CertFile: c.CertFile,
-		KeyFile:  c.KeyFile,
-	}
-}
-
-// PeerRaftInfo retrieves a TLSInfo object for the peer server.
-func (c *Config) PeerTLSInfo() *TLSInfo {
-	return &TLSInfo{
-		CAFile:   c.Peer.CAFile,
-		CertFile: c.Peer.CertFile,
-		KeyFile:  c.Peer.KeyFile,
-	}
-}
-
-// MetricsBucketName generates the name that should be used for a
-// corresponding MetricsBucket object
-func (c *Config) MetricsBucketName() string {
-	return fmt.Sprintf("etcd.%s", c.Name)
-}
-
-// Trace determines if any trace-level information should be emitted
-func (c *Config) Trace() bool {
-	return c.strTrace == "*"
-}
-
-func (c *Config) ClusterConfig() *ClusterConfig {
-	return &ClusterConfig{
-		ActiveSize:   c.Cluster.ActiveSize,
-		RemoveDelay:  c.Cluster.RemoveDelay,
-		SyncInterval: c.Cluster.SyncInterval,
-	}
-}
-
-// sanitizeURL will cleanup a host string in the format hostname[:port] and
-// attach a schema.
-func sanitizeURL(host string, defaultScheme string) (string, *url.URL, error) {
-	// Blank URLs are fine input, just return it
-	if len(host) == 0 {
-		return host, &url.URL{}, nil
-	}
-
-	p, err := url.Parse(host)
-	if err != nil {
-		return "", nil, err
-	}
-
-	// Make sure the host is in Host:Port format
-	_, _, err = net.SplitHostPort(host)
-	if err != nil {
-		return "", nil, err
-	}
-
-	p = &url.URL{Host: host, Scheme: defaultScheme}
-	return p.String(), p, nil
-}
-
-// sanitizeBindAddr cleans up the BindAddr parameter and appends a port
-// if necessary based on the advertised port.
-func sanitizeBindAddr(bindAddr string, aurl *url.URL) (string, error) {
-	// If it is a valid host:port simply return with no further checks.
-	bhost, bport, err := net.SplitHostPort(bindAddr)
-	if err == nil && bhost != "" {
-		return bindAddr, nil
-	}
-
-	// SplitHostPort makes the host optional, but we don't want that.
-	if bhost == "" && bport != "" {
-		return "", fmt.Errorf("IP required can't use a port only")
-	}
-
-	// bindAddr doesn't have a port if we reach here so take the port from the
-	// advertised URL.
-	_, aport, err := net.SplitHostPort(aurl.Host)
-	if err != nil {
-		return "", err
-	}
-
-	return net.JoinHostPort(bindAddr, aport), nil
-}
-
-// trimSplit slices s into all substrings separated by sep and returns a
-// slice of the substrings between the separator with all leading and trailing
-// white space removed, as defined by Unicode.
-func trimSplit(s, sep string) []string {
-	trimmed := strings.Split(s, sep)
-	for i := range trimmed {
-		trimmed[i] = strings.TrimSpace(trimmed[i])
-	}
-	return trimmed
-}

+ 0 - 572
conf/config_test.go

@@ -1,572 +0,0 @@
-package conf
-
-import (
-	"io/ioutil"
-	"os"
-	"testing"
-
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Ensures that a configuration can be retrieved from environment variables.
-func TestConfigEnv(t *testing.T) {
-	os.Setenv("ETCD_CA_FILE", "/tmp/file.ca")
-	os.Setenv("ETCD_CERT_FILE", "/tmp/file.cert")
-	os.Setenv("ETCD_CPU_PROFILE_FILE", "XXX")
-	os.Setenv("ETCD_CORS", "localhost:4001,localhost:4002")
-	os.Setenv("ETCD_DATA_DIR", "/tmp/data")
-	os.Setenv("ETCD_DISCOVERY", "http://example.com/foobar")
-	os.Setenv("ETCD_HTTP_READ_TIMEOUT", "2.34")
-	os.Setenv("ETCD_HTTP_WRITE_TIMEOUT", "1.23")
-	os.Setenv("ETCD_KEY_FILE", "/tmp/file.key")
-	os.Setenv("ETCD_BIND_ADDR", "127.0.0.1:4003")
-	os.Setenv("ETCD_PEERS", "coreos.com:4001,coreos.com:4002")
-	os.Setenv("ETCD_PEERS_FILE", "/tmp/peers")
-	os.Setenv("ETCD_MAX_CLUSTER_SIZE", "10")
-	os.Setenv("ETCD_MAX_RESULT_BUFFER", "512")
-	os.Setenv("ETCD_MAX_RETRY_ATTEMPTS", "5")
-	os.Setenv("ETCD_NAME", "test-name")
-	os.Setenv("ETCD_SNAPSHOT", "true")
-	os.Setenv("ETCD_VERBOSE", "1")
-	os.Setenv("ETCD_VERY_VERBOSE", "yes")
-	os.Setenv("ETCD_PEER_ADDR", "127.0.0.1:7002")
-	os.Setenv("ETCD_PEER_CA_FILE", "/tmp/peer/file.ca")
-	os.Setenv("ETCD_PEER_CERT_FILE", "/tmp/peer/file.cert")
-	os.Setenv("ETCD_PEER_KEY_FILE", "/tmp/peer/file.key")
-	os.Setenv("ETCD_PEER_BIND_ADDR", "127.0.0.1:7003")
-	os.Setenv("ETCD_CLUSTER_ACTIVE_SIZE", "5")
-	os.Setenv("ETCD_CLUSTER_REMOVE_DELAY", "100")
-	os.Setenv("ETCD_CLUSTER_SYNC_INTERVAL", "10")
-
-	c := New()
-	c.LoadEnv()
-	assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
-	assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
-	assert.Equal(t, c.CorsOrigins, []string{"localhost:4001", "localhost:4002"}, "")
-	assert.Equal(t, c.DataDir, "/tmp/data", "")
-	assert.Equal(t, c.Discovery, "http://example.com/foobar", "")
-	assert.Equal(t, c.HTTPReadTimeout, 2.34, "")
-	assert.Equal(t, c.HTTPWriteTimeout, 1.23, "")
-	assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
-	assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
-	assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
-	assert.Equal(t, c.PeersFile, "/tmp/peers", "")
-	assert.Equal(t, c.MaxResultBuffer, 512, "")
-	assert.Equal(t, c.MaxRetryAttempts, 5, "")
-	assert.Equal(t, c.Name, "test-name", "")
-	assert.Equal(t, c.Snapshot, true, "")
-	assert.Equal(t, c.Verbose, true, "")
-	assert.Equal(t, c.VeryVerbose, true, "")
-	assert.Equal(t, c.Peer.Addr, "127.0.0.1:7002", "")
-	assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
-	assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
-	assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
-	assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:7003", "")
-	assert.Equal(t, c.Cluster.ActiveSize, 5, "")
-	assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
-	assert.Equal(t, c.Cluster.SyncInterval, 10.0, "")
-
-	// Clear this as it will mess up other tests
-	os.Setenv("ETCD_DISCOVERY", "")
-}
-
-// Ensures that the "help" flag can be parsed.
-func TestConfigHelpFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-help"}), "")
-	assert.True(t, c.ShowHelp)
-}
-
-// Ensures that the abbreviated "help" flag can be parsed.
-func TestConfigAbbreviatedHelpFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-h"}), "")
-	assert.True(t, c.ShowHelp)
-}
-
-// Ensures that the "version" flag can be parsed.
-func TestConfigVersionFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-version"}), "")
-	assert.True(t, c.ShowVersion)
-}
-
-// Ensures that the "force config" flag can be parsed.
-func TestConfigForceFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-force"}), "")
-	assert.True(t, c.Force)
-}
-
-// Ensures that the abbreviated "force config" flag can be parsed.
-func TestConfigAbbreviatedForceFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-f"}), "")
-	assert.True(t, c.Force)
-}
-
-// Ensures that the advertised url can be parsed from the environment.
-func TestConfigAddrEnv(t *testing.T) {
-	withEnv("ETCD_ADDR", "127.0.0.1:4002", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Addr, "127.0.0.1:4002", "")
-	})
-}
-
-// Ensures that the advertised flag can be parsed.
-func TestConfigAddrFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4002"}), "")
-	assert.Equal(t, c.Addr, "127.0.0.1:4002", "")
-}
-
-// Ensures that the CA file can be parsed from the environment.
-func TestConfigCAFileEnv(t *testing.T) {
-	withEnv("ETCD_CA_FILE", "/tmp/file.ca", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
-	})
-}
-
-// Ensures that the CA file flag can be parsed.
-func TestConfigCAFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-ca-file", "/tmp/file.ca"}), "")
-	assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
-}
-
-// Ensures that the CA file can be parsed from the environment.
-func TestConfigCertFileEnv(t *testing.T) {
-	withEnv("ETCD_CERT_FILE", "/tmp/file.cert", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
-	})
-}
-
-// Ensures that the Cert file flag can be parsed.
-func TestConfigCertFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-cert-file", "/tmp/file.cert"}), "")
-	assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
-}
-
-// Ensures that the Key file can be parsed from the environment.
-func TestConfigKeyFileEnv(t *testing.T) {
-	withEnv("ETCD_KEY_FILE", "/tmp/file.key", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
-	})
-}
-
-// Ensures that the Key file flag can be parsed.
-func TestConfigKeyFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-key-file", "/tmp/file.key"}), "")
-	assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
-}
-
-// Ensures that the Listen Host can be parsed from the environment.
-func TestConfigBindAddrEnv(t *testing.T) {
-	withEnv("ETCD_BIND_ADDR", "127.0.0.1:4003", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
-	})
-}
-
-// Ensures that the Listen Host file flag can be parsed.
-func TestConfigBindAddrFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-bind-addr", "127.0.0.1:4003"}), "")
-	assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
-}
-
-// Ensures that the Listen Host port overrides the advertised port
-func TestConfigBindAddrOverride(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", "127.0.0.1:4010"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "127.0.0.1:4010", "")
-}
-
-// Ensures that the Listen Host port overrides the advertised port
-func TestConfigBindIPv6AddrOverride(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1]:4009", "-bind-addr", "[::1]:4010"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "[::1]:4010", "")
-}
-
-// Ensures that the Listen Host port overrides the advertised port
-func TestConfigBindIPv6WithZoneAddrOverride(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%25lo]:4009", "-bind-addr", "[::1%25lo]:4010"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "[::1%25lo]:4010", "")
-}
-
-// Ensures that the Listen Host inherits its port from the advertised addr
-func TestConfigBindAddrInheritPort(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", "127.0.0.1"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "127.0.0.1:4009", "")
-}
-
-// Ensures that the Listen Host inherits its port from the advertised addr
-func TestConfigBindIPv6AddrInheritPort(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1]:4009", "-bind-addr", "::1"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "[::1]:4009", "")
-}
-
-// Ensures that the Listen Host inherits its port from the advertised addr
-func TestConfigBindIPv6WithZoneAddrInheritPort(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%25lo]:4009", "-bind-addr", "::1%25lo"}), "")
-	assert.Nil(t, c.Sanitize())
-	assert.Equal(t, c.BindAddr, "[::1%25lo]:4009", "")
-}
-
-// Ensures that a port only argument errors out
-func TestConfigBindAddrErrorOnNoHost(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", ":4010"}), "")
-	assert.Error(t, c.Sanitize())
-}
-
-// Ensures that a bad IPv6 address will raise an error
-func TestConfigBindAddrErrorOnBadIPv6Addr(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%lo]:4009"}), "")
-	assert.Error(t, c.Sanitize())
-}
-
-// Ensures that the peers can be parsed from the environment.
-func TestConfigPeersEnv(t *testing.T) {
-	withEnv("ETCD_PEERS", "coreos.com:4001,coreos.com:4002", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
-	})
-}
-
-// Ensures that the Peers flag can be parsed.
-func TestConfigPeersFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peers", "coreos.com:4001,coreos.com:4002"}), "")
-	assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
-}
-
-// Ensures that the Peers File can be parsed from the environment.
-func TestConfigPeersFileEnv(t *testing.T) {
-	withEnv("ETCD_PEERS_FILE", "/tmp/peers", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.PeersFile, "/tmp/peers", "")
-	})
-}
-
-// Ensures that the Peers File flag can be parsed.
-func TestConfigPeersFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peers-file", "/tmp/peers"}), "")
-	assert.Equal(t, c.PeersFile, "/tmp/peers", "")
-}
-
-// Ensures that the Max Result Buffer can be parsed from the environment.
-func TestConfigMaxResultBufferEnv(t *testing.T) {
-	withEnv("ETCD_MAX_RESULT_BUFFER", "512", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.MaxResultBuffer, 512, "")
-	})
-}
-
-// Ensures that the Max Result Buffer flag can be parsed.
-func TestConfigMaxResultBufferFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-max-result-buffer", "512"}), "")
-	assert.Equal(t, c.MaxResultBuffer, 512, "")
-}
-
-// Ensures that the Max Retry Attempts can be parsed from the environment.
-func TestConfigMaxRetryAttemptsEnv(t *testing.T) {
-	withEnv("ETCD_MAX_RETRY_ATTEMPTS", "10", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.MaxRetryAttempts, 10, "")
-	})
-}
-
-// Ensures that the Max Retry Attempts flag can be parsed.
-func TestConfigMaxRetryAttemptsFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-max-retry-attempts", "10"}), "")
-	assert.Equal(t, c.MaxRetryAttempts, 10, "")
-}
-
-// Ensures that the Name can be parsed from the environment.
-func TestConfigNameEnv(t *testing.T) {
-	withEnv("ETCD_NAME", "test-name", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Name, "test-name", "")
-	})
-}
-
-// Ensures that the Name flag can be parsed.
-func TestConfigNameFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-name", "test-name"}), "")
-	assert.Equal(t, c.Name, "test-name", "")
-}
-
-// Ensures that a Name gets guessed if not specified
-func TestConfigNameGuess(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{}), "")
-	assert.Nil(t, c.Sanitize())
-	name, _ := os.Hostname()
-	assert.Equal(t, c.Name, name, "")
-}
-
-// Ensures that a DataDir gets guessed if not specified
-func TestConfigDataDirGuess(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{}), "")
-	assert.Nil(t, c.Sanitize())
-	name, _ := os.Hostname()
-	assert.Equal(t, c.DataDir, name+".etcd", "")
-}
-
-// Ensures that Snapshot can be parsed from the environment.
-func TestConfigSnapshotEnv(t *testing.T) {
-	withEnv("ETCD_SNAPSHOT", "1", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Snapshot, true, "")
-	})
-}
-
-// Ensures that the Snapshot flag can be parsed.
-func TestConfigSnapshotFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-snapshot"}), "")
-	assert.Equal(t, c.Snapshot, true, "")
-}
-
-// Ensures that Verbose can be parsed from the environment.
-func TestConfigVerboseEnv(t *testing.T) {
-	withEnv("ETCD_VERBOSE", "true", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Verbose, true, "")
-	})
-}
-
-// Ensures that the Verbose flag can be parsed.
-func TestConfigVerboseFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-v"}), "")
-	assert.Equal(t, c.Verbose, true, "")
-}
-
-// Ensures that Very Verbose can be parsed from the environment.
-func TestConfigVeryVerboseEnv(t *testing.T) {
-	withEnv("ETCD_VERY_VERBOSE", "true", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.VeryVerbose, true, "")
-	})
-}
-
-// Ensures that the Very Verbose flag can be parsed.
-func TestConfigVeryVerboseFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-vv"}), "")
-	assert.Equal(t, c.VeryVerbose, true, "")
-}
-
-// Ensures that the Peer Advertised URL can be parsed from the environment.
-func TestConfigPeerAddrEnv(t *testing.T) {
-	withEnv("ETCD_PEER_ADDR", "localhost:7002", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peer.Addr, "localhost:7002", "")
-	})
-}
-
-// Ensures that the Peer Advertised URL flag can be parsed.
-func TestConfigPeerAddrFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peer-addr", "localhost:7002"}), "")
-	assert.Equal(t, c.Peer.Addr, "localhost:7002", "")
-}
-
-// Ensures that the Peer CA File can be parsed from the environment.
-func TestConfigPeerCAFileEnv(t *testing.T) {
-	withEnv("ETCD_PEER_CA_FILE", "/tmp/peer/file.ca", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
-	})
-}
-
-// Ensures that the Peer CA file flag can be parsed.
-func TestConfigPeerCAFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peer-ca-file", "/tmp/peer/file.ca"}), "")
-	assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
-}
-
-// Ensures that the Peer Cert File can be parsed from the environment.
-func TestConfigPeerCertFileEnv(t *testing.T) {
-	withEnv("ETCD_PEER_CERT_FILE", "/tmp/peer/file.cert", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
-	})
-}
-
-// Ensures that the Cert file flag can be parsed.
-func TestConfigPeerCertFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peer-cert-file", "/tmp/peer/file.cert"}), "")
-	assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
-}
-
-// Ensures that the Peer Key File can be parsed from the environment.
-func TestConfigPeerKeyFileEnv(t *testing.T) {
-	withEnv("ETCD_PEER_KEY_FILE", "/tmp/peer/file.key", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
-	})
-}
-
-// Ensures that the Peer Key file flag can be parsed.
-func TestConfigPeerKeyFileFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peer-key-file", "/tmp/peer/file.key"}), "")
-	assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
-}
-
-// Ensures that the Peer Listen Host can be parsed from the environment.
-func TestConfigPeerBindAddrEnv(t *testing.T) {
-	withEnv("ETCD_PEER_BIND_ADDR", "localhost:7004", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Peer.BindAddr, "localhost:7004", "")
-	})
-}
-
-// Ensures that a bad flag returns an error.
-func TestConfigBadFlag(t *testing.T) {
-	c := New()
-	err := c.LoadFlags([]string{"-no-such-flag"})
-	assert.Error(t, err)
-	assert.Equal(t, err.Error(), `flag provided but not defined: -no-such-flag`)
-}
-
-// Ensures that the Peer Listen Host file flag can be parsed.
-func TestConfigPeerBindAddrFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-peer-bind-addr", "127.0.0.1:4003"}), "")
-	assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:4003", "")
-}
-
-// Ensures that the cluster active size can be parsed from the environment.
-func TestConfigClusterActiveSizeEnv(t *testing.T) {
-	withEnv("ETCD_CLUSTER_ACTIVE_SIZE", "5", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Cluster.ActiveSize, 5, "")
-	})
-}
-
-// Ensures that the cluster active size flag can be parsed.
-func TestConfigClusterActiveSizeFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-cluster-active-size", "5"}), "")
-	assert.Equal(t, c.Cluster.ActiveSize, 5, "")
-}
-
-// Ensures that the cluster remove delay can be parsed from the environment.
-func TestConfigClusterRemoveDelayEnv(t *testing.T) {
-	withEnv("ETCD_CLUSTER_REMOVE_DELAY", "100", func(c *Config) {
-		assert.Nil(t, c.LoadEnv(), "")
-		assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
-	})
-}
-
-// Ensures that the cluster remove delay flag can be parsed.
-func TestConfigClusterRemoveDelayFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-cluster-remove-delay", "100"}), "")
-	assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
-}
-
-func TestConfigClusterSyncIntervalFlag(t *testing.T) {
-	c := New()
-	assert.Nil(t, c.LoadFlags([]string{"-http-read-timeout", "2.34"}), "")
-	assert.Equal(t, c.HTTPReadTimeout, 2.34, "")
-	assert.Nil(t, c.LoadFlags([]string{"-http-write-timeout", "1.23"}), "")
-	assert.Equal(t, c.HTTPWriteTimeout, 1.23, "")
-}
-
-// Ensures that a custom config field is overridden by an environment variable.
-func TestConfigEnvVarOverrideCustomConfig(t *testing.T) {
-	os.Setenv("ETCD_PEER_ADDR", "127.0.0.1:8000")
-	defer os.Setenv("ETCD_PEER_ADDR", "")
-
-	custom := `[peer]` + "\n" + `advertised_url = "127.0.0.1:9000"`
-	withTempFile(custom, func(path string) {
-		c := New()
-		c.SystemPath = ""
-		assert.Nil(t, c.Load([]string{"-config", path}), "")
-		assert.Equal(t, c.Peer.Addr, "127.0.0.1:8000", "")
-	})
-}
-
-// Ensures that an environment variable field is overridden by a command line argument.
-func TestConfigCLIArgsOverrideEnvVar(t *testing.T) {
-	os.Setenv("ETCD_ADDR", "127.0.0.1:1000")
-	defer os.Setenv("ETCD_ADDR", "")
-
-	c := New()
-	c.SystemPath = ""
-	assert.Nil(t, c.Load([]string{"-addr", "127.0.0.1:2000"}), "")
-	assert.Equal(t, c.Addr, "127.0.0.1:2000", "")
-}
-
-//--------------------------------------
-// Helpers
-//--------------------------------------
-
-// Sets up the environment with a given environment variable set.
-func withEnv(key, value string, f func(c *Config)) {
-	os.Setenv(key, value)
-	defer os.Setenv(key, "")
-	c := New()
-	f(c)
-}
-
-// Creates a temp file and calls a function with the context.
-func withTempFile(content string, fn func(string)) {
-	f, _ := ioutil.TempFile("", "")
-	f.WriteString(content)
-	f.Close()
-	defer os.Remove(f.Name())
-	fn(f.Name())
-}
-
-// Captures STDOUT & STDERR and returns the output as strings.
-func capture(fn func()) (string, string) {
-	// Create temp files.
-	tmpout, _ := ioutil.TempFile("", "")
-	defer os.Remove(tmpout.Name())
-	tmperr, _ := ioutil.TempFile("", "")
-	defer os.Remove(tmperr.Name())
-
-	stdout, stderr := os.Stdout, os.Stderr
-	os.Stdout, os.Stderr = tmpout, tmperr
-
-	// Execute function argument and then reassign stdout/stderr.
-	fn()
-	os.Stdout, os.Stderr = stdout, stderr
-
-	// Close temp files and read them.
-	tmpout.Close()
-	bout, _ := ioutil.ReadFile(tmpout.Name())
-	tmperr.Close()
-	berr, _ := ioutil.ReadFile(tmperr.Name())
-
-	return string(bout), string(berr)
-}

+ 0 - 32
conf/default.go

@@ -1,32 +0,0 @@
-package conf
-
-import "time"
-
-const (
-	// The amount of time (in ms) to elapse without a heartbeat before becoming a candidate
-	DefaultElectionTimeout = 200
-
-	// The frequency (in ms) by which heartbeats are sent to followers.
-	DefaultHeartbeatInterval = 50
-
-	// DefaultActiveSize is the default number of active followers allowed.
-	DefaultActiveSize = 9
-
-	// MinActiveSize is the minimum active size allowed.
-	MinActiveSize = 3
-
-	// DefaultRemoveDelay is the default elapsed time before removal.
-	DefaultRemoveDelay = float64((30 * time.Minute) / time.Second)
-
-	// MinRemoveDelay is the minimum remove delay allowed.
-	MinRemoveDelay = float64((2 * time.Second) / time.Second)
-
-	// DefaultSyncInterval is the default interval for cluster sync.
-	DefaultSyncInterval = float64((5 * time.Second) / time.Second)
-
-	// MinSyncInterval is the minimum sync interval allowed.
-	MinSyncInterval = float64((1 * time.Second) / time.Second)
-
-	DefaultReadTimeout  = float64((5 * time.Minute) / time.Second)
-	DefaultWriteTimeout = float64((5 * time.Minute) / time.Second)
-)

+ 0 - 105
conf/tls_config.go

@@ -1,105 +0,0 @@
-package conf
-
-import (
-	"crypto/tls"
-	"crypto/x509"
-	"encoding/pem"
-	"fmt"
-	"io/ioutil"
-)
-
-// TLSInfo holds the SSL certificates paths.
-type TLSInfo struct {
-	CertFile string `json:"CertFile"`
-	KeyFile  string `json:"KeyFile"`
-	CAFile   string `json:"CAFile"`
-}
-
-func (info TLSInfo) Scheme() string {
-	if info.KeyFile != "" && info.CertFile != "" {
-		return "https"
-	} else {
-		return "http"
-	}
-}
-
-// Generates a tls.Config object for a server from the given files.
-func (info TLSInfo) ServerConfig() (*tls.Config, error) {
-	// Both the key and cert must be present.
-	if info.KeyFile == "" || info.CertFile == "" {
-		return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
-	}
-
-	var cfg tls.Config
-
-	tlsCert, err := tls.LoadX509KeyPair(info.CertFile, info.KeyFile)
-	if err != nil {
-		return nil, err
-	}
-
-	cfg.Certificates = []tls.Certificate{tlsCert}
-
-	if info.CAFile != "" {
-		cfg.ClientAuth = tls.RequireAndVerifyClientCert
-		cp, err := newCertPool(info.CAFile)
-		if err != nil {
-			return nil, err
-		}
-
-		cfg.RootCAs = cp
-		cfg.ClientCAs = cp
-	} else {
-		cfg.ClientAuth = tls.NoClientCert
-	}
-
-	return &cfg, nil
-}
-
-// Generates a tls.Config object for a client from the given files.
-func (info TLSInfo) ClientConfig() (*tls.Config, error) {
-	var cfg tls.Config
-
-	if info.KeyFile == "" || info.CertFile == "" {
-		return &cfg, nil
-	}
-
-	tlsCert, err := tls.LoadX509KeyPair(info.CertFile, info.KeyFile)
-	if err != nil {
-		return nil, err
-	}
-
-	cfg.Certificates = []tls.Certificate{tlsCert}
-
-	if info.CAFile != "" {
-		cp, err := newCertPool(info.CAFile)
-		if err != nil {
-			return nil, err
-		}
-
-		cfg.RootCAs = cp
-	}
-
-	return &cfg, nil
-}
-
-// newCertPool creates x509 certPool with provided CA file
-func newCertPool(CAFile string) (*x509.CertPool, error) {
-	certPool := x509.NewCertPool()
-	pemByte, err := ioutil.ReadFile(CAFile)
-	if err != nil {
-		return nil, err
-	}
-
-	for {
-		var block *pem.Block
-		block, pemByte = pem.Decode(pemByte)
-		if block == nil {
-			return certPool, nil
-		}
-		cert, err := x509.ParseCertificate(block.Bytes)
-		if err != nil {
-			return nil, err
-		}
-		certPool.AddCert(cert)
-	}
-}

+ 0 - 133
etcdserver/discovery.go

@@ -1,133 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"errors"
-	"fmt"
-	"log"
-	"net/url"
-	"path"
-	"strings"
-	"time"
-
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-const (
-	stateKey     = "_state"
-	startedState = "started"
-	defaultTTL   = 604800 // One week TTL
-)
-
-type discoverer struct {
-	client *etcd.Client
-	name   string
-	addr   string
-	prefix string
-}
-
-func newDiscoverer(u *url.URL, name, raftPubAddr string) *discoverer {
-	d := &discoverer{name: name, addr: raftPubAddr}
-
-	// prefix is prepended to all keys for this discovery
-	d.prefix = strings.TrimPrefix(u.Path, "/v2/keys/")
-
-	// keep the old path in case we need to set the KeyPrefix below
-	oldPath := u.Path
-	u.Path = ""
-
-	// Connect to a scheme://host not a full URL with path
-	d.client = etcd.NewClient([]string{u.String()})
-
-	if !strings.HasPrefix(oldPath, "/v2/keys") {
-		d.client.SetKeyPrefix("")
-	}
-	return d
-}
-
-func (d *discoverer) discover() ([]string, error) {
-	log.Printf("discoverer name=%s target=\"%q\" prefix=%s\n", d.name, d.client.GetCluster(), d.prefix)
-
-	if _, err := d.client.Set(path.Join(d.prefix, d.name), d.addr, defaultTTL); err != nil {
-		return nil, fmt.Errorf("discovery service error: %v", err)
-	}
-
-	// Attempt to take the leadership role, if there is no error we are it!
-	resp, err := d.client.Create(path.Join(d.prefix, stateKey), startedState, 0)
-	// Bail out on unexpected errors
-	if err != nil {
-		if clientErr, ok := err.(*etcd.EtcdError); !ok || clientErr.ErrorCode != etcdErr.EcodeNodeExist {
-			return nil, fmt.Errorf("discovery service error: %v", err)
-		}
-	}
-
-	// If we got a response then the CAS was successful, we are leader
-	if resp != nil && resp.Node.Value == startedState {
-		// We are the leader, we have no peers
-		return nil, nil
-	}
-
-	// Fall through to finding the other discovery peers
-	return d.findPeers()
-}
-
-func (d *discoverer) findPeers() (peers []string, err error) {
-	resp, err := d.client.Get(path.Join(d.prefix), false, true)
-	if err != nil {
-		return nil, fmt.Errorf("discovery service error: %v", err)
-	}
-
-	node := resp.Node
-
-	if node == nil {
-		return nil, fmt.Errorf("%s key doesn't exist.", d.prefix)
-	}
-
-	for _, n := range node.Nodes {
-		// Skip our own entry in the list, there is no point
-		if strings.HasSuffix(n.Key, "/"+d.name) {
-			continue
-		}
-		peers = append(peers, n.Value)
-	}
-
-	if len(peers) == 0 {
-		return nil, errors.New("Discovery found an initialized cluster but no reachable peers are registered.")
-	}
-
-	return
-}
-
-func (d *discoverer) heartbeat(stopc <-chan struct{}) {
-	// In case of errors we should attempt to heartbeat fairly frequently
-	heartbeatInterval := defaultTTL / 8
-	ticker := time.NewTicker(time.Second * time.Duration(heartbeatInterval))
-	defer ticker.Stop()
-	for {
-		if _, err := d.client.Set(path.Join(d.prefix, d.name), d.addr, defaultTTL); err != nil {
-			log.Println("discoverer heartbeatErr=\"%v\"", err)
-		}
-
-		select {
-		case <-ticker.C:
-		case <-stopc:
-			return
-		}
-	}
-}

+ 0 - 220
etcdserver/etcd.go

@@ -1,220 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"crypto/tls"
-	"fmt"
-	"log"
-	"net"
-	"net/http"
-	"net/url"
-	"os"
-	"time"
-
-	"github.com/coreos/etcd/conf"
-)
-
-const (
-	participantMode int64 = iota
-	standbyMode
-	stopMode
-)
-
-type Server struct {
-	cfg          *conf.Config
-	name         string
-	pubAddr      string
-	raftPubAddr  string
-	tickDuration time.Duration
-
-	mode atomicInt
-	p    *participant
-	s    *standby
-
-	client  *v2client
-	peerHub *peerHub
-
-	exited      chan error
-	stopNotifyc chan struct{}
-	log         *log.Logger
-	http.Handler
-}
-
-func New(c *conf.Config) (*Server, error) {
-	if err := c.Sanitize(); err != nil {
-		log.Fatalf("server.new sanitizeErr=\"%v\"\n", err)
-	}
-
-	tc := &tls.Config{
-		InsecureSkipVerify: true,
-	}
-	var err error
-	if c.PeerTLSInfo().Scheme() == "https" {
-		tc, err = c.PeerTLSInfo().ClientConfig()
-		if err != nil {
-			log.Fatalf("server.new ClientConfigErr=\"%v\"\n", err)
-		}
-	}
-
-	tr := new(http.Transport)
-	tr.TLSClientConfig = tc
-	tr.Dial = (&net.Dialer{Timeout: 200 * time.Millisecond}).Dial
-	tr.TLSHandshakeTimeout = 10 * time.Second
-	tr.ResponseHeaderTimeout = defaultTickDuration * defaultHeartbeat
-	client := &http.Client{Transport: tr}
-
-	s := &Server{
-		cfg:          c,
-		name:         c.Name,
-		pubAddr:      c.Addr,
-		raftPubAddr:  c.Peer.Addr,
-		tickDuration: defaultTickDuration,
-
-		mode: atomicInt(stopMode),
-
-		client: newClient(tc),
-
-		exited:      make(chan error, 1),
-		stopNotifyc: make(chan struct{}),
-	}
-	followersStats := NewRaftFollowersStats(s.name)
-	s.peerHub = newPeerHub(client, followersStats)
-	m := http.NewServeMux()
-	m.HandleFunc("/", s.requestHandler)
-	m.HandleFunc("/version", versionHandler)
-	s.Handler = m
-
-	log.Printf("name=%s server.new raftPubAddr=%s\n", s.name, s.raftPubAddr)
-	if err = os.MkdirAll(s.cfg.DataDir, 0700); err != nil {
-		if !os.IsExist(err) {
-			return nil, err
-		}
-	}
-	return s, nil
-}
-
-func (s *Server) SetTick(tick time.Duration) {
-	s.tickDuration = tick
-	log.Printf("name=%s server.setTick tick=%q\n", s.name, s.tickDuration)
-}
-
-// Stop stops the server elegently.
-func (s *Server) Stop() error {
-	s.mode.Set(stopMode)
-	close(s.stopNotifyc)
-	err := <-s.exited
-	s.client.CloseConnections()
-	log.Printf("name=%s server.stop\n", s.name)
-	return err
-}
-
-func (s *Server) requestHandler(w http.ResponseWriter, r *http.Request) {
-	switch s.mode.Get() {
-	case participantMode:
-		s.p.ServeHTTP(w, r)
-	case standbyMode:
-		s.s.ServeHTTP(w, r)
-	default:
-		http.NotFound(w, r)
-	}
-}
-
-func (s *Server) RaftHandler() http.Handler {
-	return http.HandlerFunc(s.ServeRaftHTTP)
-}
-
-func (s *Server) ServeRaftHTTP(w http.ResponseWriter, r *http.Request) {
-	switch s.mode.Get() {
-	case participantMode:
-		s.p.raftHandler().ServeHTTP(w, r)
-	default:
-		http.NotFound(w, r)
-	}
-}
-
-func (s *Server) Run() error {
-	var d *discoverer
-	var seeds []string
-	var exit error
-	defer func() { s.exited <- exit }()
-
-	durl := s.cfg.Discovery
-	if durl != "" {
-		u, err := url.Parse(durl)
-		if err != nil {
-			exit = err
-			return fmt.Errorf("bad discovery URL error: %v", err)
-		}
-		d = newDiscoverer(u, s.name, s.raftPubAddr)
-		if seeds, err = d.discover(); err != nil {
-			exit = err
-			return err
-		}
-		log.Printf("name=%s server.run source=-discovery seeds=%q", s.name, seeds)
-	} else {
-		for _, p := range s.cfg.Peers {
-			u, err := url.Parse(p)
-			if err != nil {
-				log.Printf("name=%s server.run err=%q", s.name, err)
-				continue
-			}
-			if u.Scheme == "" {
-				u.Scheme = s.cfg.PeerTLSInfo().Scheme()
-			}
-			seeds = append(seeds, u.String())
-		}
-		log.Printf("name=%s server.run source=-peers seeds=%q", s.name, seeds)
-	}
-	s.peerHub.setSeeds(seeds)
-
-	next := participantMode
-	for {
-		switch next {
-		case participantMode:
-			p, err := newParticipant(s.cfg, s.client, s.peerHub, s.tickDuration)
-			if err != nil {
-				log.Printf("name=%s server.run newParicipanteErr=\"%v\"\n", s.name, err)
-				exit = err
-				return err
-			}
-			s.p = p
-			s.mode.Set(participantMode)
-			log.Printf("name=%s server.run mode=participantMode\n", s.name)
-			dStopc := make(chan struct{})
-			if d != nil {
-				go d.heartbeat(dStopc)
-			}
-			s.p.run(s.stopNotifyc)
-			if d != nil {
-				close(dStopc)
-			}
-			next = standbyMode
-		case standbyMode:
-			s.s = newStandby(s.client, s.peerHub)
-			s.mode.Set(standbyMode)
-			log.Printf("name=%s server.run mode=standbyMode\n", s.name)
-			s.s.run(s.stopNotifyc)
-			next = participantMode
-		default:
-			panic("unsupport mode")
-		}
-		if s.mode.Get() == stopMode {
-			return nil
-		}
-	}
-}

+ 0 - 207
etcdserver/etcd_functional_test.go

@@ -1,207 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"math/rand"
-	"net/url"
-	"reflect"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/conf"
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-func TestKillLeader(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{3, 5, 9}
-
-	for i, tt := range tests {
-		cl := testCluster{Size: tt}
-		cl.Start()
-		for j := 0; j < tt; j++ {
-			lead, _ := cl.Leader()
-			cl.Node(lead).Stop()
-			// wait for leader election timeout
-			time.Sleep(cl.Node(0).e.tickDuration * defaultElection * 2)
-			if g, _ := cl.Leader(); g == lead {
-				t.Errorf("#%d.%d: lead = %d, want not %d", i, j, g, lead)
-			}
-			cl.Node(lead).Start()
-			cl.Node(lead).WaitMode(participantMode)
-		}
-		cl.Destroy()
-	}
-}
-
-func TestKillRandom(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{3, 5, 9}
-
-	for _, tt := range tests {
-		cl := testCluster{Size: tt}
-		cl.Start()
-		for j := 0; j < tt; j++ {
-			// we cannot kill the majority
-			// wait for the majority
-			cl.Leader()
-			toKill := make(map[int64]struct{})
-			for len(toKill) != tt/2-1 {
-				toKill[rand.Int63n(int64(tt))] = struct{}{}
-			}
-			for k := range toKill {
-				cl.Node(int(k)).Stop()
-			}
-
-			// wait for leader election timeout
-			time.Sleep(cl.Node(0).e.tickDuration * defaultElection * 2)
-			cl.Leader()
-			for k := range toKill {
-				cl.Node(int(k)).Start()
-				cl.Node(int(k)).WaitMode(participantMode)
-			}
-		}
-		cl.Destroy()
-	}
-}
-
-func TestJoinThroughFollower(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{3, 5, 7}
-
-	for _, tt := range tests {
-		bt := &testServer{}
-		bt.Start()
-		cl := testCluster{nodes: []*testServer{bt}}
-		seed := bt.URL
-
-		for i := 1; i < tt; i++ {
-			c := newTestConfig()
-			c.Name = fmt.Sprint(i)
-			c.Peers = []string{seed}
-			ts := &testServer{Config: c}
-			ts.Start()
-			ts.WaitMode(participantMode)
-			cl.nodes = append(cl.nodes, ts)
-			cl.Leader()
-			seed = ts.URL
-		}
-		cl.Destroy()
-	}
-}
-
-func TestJoinWithoutHTTPScheme(t *testing.T) {
-	bt := &testServer{}
-	bt.Start()
-
-	cl := testCluster{nodes: []*testServer{bt}}
-	seed := bt.URL
-	u, err := url.Parse(seed)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// remove HTTP scheme
-	seed = u.Host + u.Path
-
-	for i := 1; i < 3; i++ {
-		c := newTestConfig()
-		c.Name = "server-" + fmt.Sprint(i)
-		c.Peers = []string{seed}
-		ts := &testServer{Config: c}
-		ts.Start()
-		ts.WaitMode(participantMode)
-		cl.nodes = append(cl.nodes, ts)
-		cl.Leader()
-	}
-	cl.Destroy()
-}
-
-func TestClusterConfigReload(t *testing.T) {
-	defer afterTest(t)
-
-	cl := &testCluster{Size: 5}
-	cl.Start()
-	defer cl.Destroy()
-
-	lead, _ := cl.Leader()
-	cc := conf.NewClusterConfig()
-	cc.ActiveSize = 15
-	cc.RemoveDelay = 60
-	if err := cl.Participant(lead).setClusterConfig(cc); err != nil {
-		t.Fatalf("setClusterConfig err = %v", err)
-	}
-
-	cl.Stop()
-	cl.Restart()
-
-	lead, _ = cl.Leader()
-	// wait for msgAppResp to commit all entries
-	time.Sleep(2 * defaultHeartbeat * cl.Participant(0).tickDuration)
-	if g := cl.Participant(lead).clusterConfig(); !reflect.DeepEqual(g, cc) {
-		t.Errorf("clusterConfig = %+v, want %+v", g, cc)
-	}
-}
-
-func TestFiveNodeKillOneAndRecover(t *testing.T) {
-	defer afterTest(t)
-	cl := testCluster{Size: 5}
-	cl.Start()
-	for n := 0; n < 5; n++ {
-		i := rand.Int() % 5
-		cl.Node(i).Stop()
-		cl.Leader()
-		cl.Node(i).Start()
-		cl.Node(i).WaitMode(participantMode)
-		cl.Leader()
-	}
-	cl.Destroy()
-}
-
-func TestFiveNodeKillAllAndRecover(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 5}
-	cl.Start()
-	defer cl.Destroy()
-
-	cl.Leader()
-	c := etcd.NewClient([]string{cl.URL(0)})
-	for i := 0; i < 10; i++ {
-		if _, err := c.Set("foo", "bar", 0); err != nil {
-			panic(err)
-		}
-	}
-
-	cl.Stop()
-
-	cl.Restart()
-	cl.Leader()
-	res, err := c.Set("foo", "bar", 0)
-	if err != nil {
-		t.Fatalf("set err after recovery: %v", err)
-	}
-	if g := res.Node.ModifiedIndex; g != 16 {
-		t.Errorf("modifiedIndex = %d, want %d", g, 16)
-	}
-}
-
-// TestModeSwitch tests switch mode between standby and peer.
-func TestModeSwitch(t *testing.T) {
-	t.Skip("not implemented")
-}

+ 0 - 168
etcdserver/etcd_start_test.go

@@ -1,168 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"net/http"
-	"net/http/httptest"
-	"net/url"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-)
-
-const (
-	bootstrapName = "BEEF"
-)
-
-type garbageHandler struct {
-	t       *testing.T
-	success bool
-	sync.Mutex
-}
-
-func (g *garbageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintln(w, "Hello, client")
-	wp := fmt.Sprint("/v2/keys/_etcd/registry/1/", bootstrapName)
-	if gp := r.URL.String(); gp != wp {
-		g.t.Fatalf("url = %s, want %s", gp, wp)
-	}
-	g.Lock()
-	defer g.Unlock()
-
-	g.success = true
-}
-
-func TestBadDiscoveryService(t *testing.T) {
-	defer afterTest(t)
-	g := garbageHandler{t: t}
-	httpts := httptest.NewServer(&g)
-	defer httpts.Close()
-
-	c := newTestConfig()
-	c.Name = bootstrapName
-	c.Discovery = httpts.URL + "/v2/keys/_etcd/registry/1"
-	ts := testServer{Config: c}
-	ts.Start()
-
-	err := ts.Destroy()
-	w := `discovery service error`
-	if err == nil || !strings.HasPrefix(err.Error(), w) {
-		t.Errorf("err = %v, want %s prefix", err, w)
-	}
-
-	g.Lock()
-	defer g.Unlock()
-	if !g.success {
-		t.Fatal("Discovery server never called")
-	}
-}
-
-func TestBadDiscoveryServiceWithAdvisedPeers(t *testing.T) {
-	defer afterTest(t)
-	g := garbageHandler{t: t}
-	httpts := httptest.NewServer(&g)
-	defer httpts.Close()
-
-	c := newTestConfig()
-	c.Name = bootstrapName
-	c.Discovery = httpts.URL + "/v2/keys/_etcd/registry/1"
-	c.Peers = []string{"a peer"}
-	ts := testServer{Config: c}
-	ts.Start()
-
-	err := ts.Destroy()
-	w := `discovery service error`
-	if err == nil || !strings.HasPrefix(err.Error(), w) {
-		t.Errorf("err = %v, want %s prefix", err, w)
-	}
-}
-
-func TestBootstrapByEmptyPeers(t *testing.T) {
-	defer afterTest(t)
-	ts := testServer{}
-	ts.Start()
-	defer ts.Destroy()
-	ts.WaitMode(participantMode)
-	if ts.Participant().node.Leader() != ts.Participant().id {
-		t.Errorf("leader = %x, want %x", ts.Participant().node.Leader(), ts.Participant().id)
-	}
-}
-
-func TestBootstrapByDiscoveryService(t *testing.T) {
-	defer afterTest(t)
-	discoverService := testCluster{Size: 1}
-	discoverService.Start()
-	defer discoverService.Destroy()
-
-	c := newTestConfig()
-	c.Name = bootstrapName
-	c.Discovery = discoverService.URL(0) + "/v2/keys/_etcd/registry/1"
-	ts := testServer{Config: c}
-	ts.Start()
-	ts.WaitMode(participantMode)
-	err := ts.Destroy()
-	if err != nil {
-		t.Fatalf("server stop err = %v, want nil", err)
-	}
-}
-
-func TestRunByAdvisedPeers(t *testing.T) {
-	t.Skip("test covered by TestMultipleNodes")
-}
-
-func TestRunByDiscoveryService(t *testing.T) {
-	ds := testCluster{Size: 1}
-	ds.Start()
-	defer ds.Destroy()
-
-	tc := NewTestClient()
-	v := url.Values{}
-	v.Set("value", "started")
-	resp, _ := tc.PutForm(fmt.Sprintf("%s%s", ds.URL(0), "/v2/keys/_etcd/registry/1/_state"), v)
-	if g := resp.StatusCode; g != http.StatusCreated {
-		t.Fatalf("put status = %d, want %d", g, http.StatusCreated)
-	}
-	resp.Body.Close()
-
-	v.Set("value", ds.URL(0))
-	resp, _ = tc.PutForm(fmt.Sprintf("%s%s%d", ds.URL(0), "/v2/keys/_etcd/registry/1/", ds.Participant(0).id), v)
-	if g := resp.StatusCode; g != http.StatusCreated {
-		t.Fatalf("put status = %d, want %d", g, http.StatusCreated)
-	}
-	resp.Body.Close()
-
-	c := newTestConfig()
-	c.Name = bootstrapName
-	c.Discovery = ds.URL(0) + "/v2/keys/_etcd/registry/1"
-	ts := &testServer{Config: c}
-	ds.Add(ts)
-
-	// wait for the leader to do a heartbeat
-	// it will update the lead field of the follower
-	time.Sleep(ds.Node(0).e.tickDuration * defaultHeartbeat * 2)
-	w := ds.Participant(0).id
-	if g := ts.Lead().lead; g != w {
-		t.Errorf("leader = %d, want %d", g, w)
-	}
-}
-
-func TestRunByDataDir(t *testing.T) {
-	t.Skip("test covered by TestSingleNodeRecovery")
-}

+ 0 - 656
etcdserver/etcd_test.go

@@ -1,656 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"net/http/httptest"
-	"net/url"
-	"os"
-	"path"
-	"reflect"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/conf"
-	"github.com/coreos/etcd/store"
-)
-
-func TestMultipleNodes(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{1, 3, 5, 9, 11}
-
-	for _, tt := range tests {
-		c := &testCluster{Size: tt}
-		c.Start()
-		c.Destroy()
-	}
-}
-
-func TestMultipleTLSNodes(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{1, 3, 5}
-
-	for _, tt := range tests {
-		c := &testCluster{Size: tt, TLS: true}
-		c.Start()
-		c.Destroy()
-	}
-}
-
-func TestV2Redirect(t *testing.T) {
-	defer afterTest(t)
-
-	c := &testCluster{Size: 3}
-	c.Start()
-	defer c.Destroy()
-
-	u := c.URL(1)
-	ru := fmt.Sprintf("%s%s", c.URL(0), "/v2/keys/foo")
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo"), v)
-	if resp.StatusCode != http.StatusTemporaryRedirect {
-		t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusTemporaryRedirect)
-	}
-	location, err := resp.Location()
-	if err != nil {
-		t.Errorf("want err = %, want nil", err)
-	}
-
-	if location.String() != ru {
-		t.Errorf("location = %v, want %v", location.String(), ru)
-	}
-	resp.Body.Close()
-}
-
-func TestRemove(t *testing.T) {
-	defer afterTest(t)
-	tests := []int{3, 4, 5, 6}
-	for aa := 0; aa < 1; aa++ {
-		for k, tt := range tests {
-			cl := testCluster{Size: tt}
-			cl.Start()
-
-			lead, _ := cl.Leader()
-			config := conf.NewClusterConfig()
-			config.ActiveSize = 0
-			if err := cl.Participant(lead).setClusterConfig(config); err != nil {
-				t.Fatalf("#%d: setClusterConfig err = %v", k, err)
-			}
-
-			// we don't remove the machine from 2-node cluster because it is
-			// not 100 percent safe in our raft.
-			// TODO(yichengq): improve it later.
-			for i := 0; i < tt-2; i++ {
-				id := cl.Id(i)
-				for {
-					n := cl.Node(i)
-					if n.e.mode.Get() == standbyMode {
-						break
-					}
-					err := n.Participant().remove(id)
-					if err == nil {
-						break
-					}
-					switch err {
-					case tmpErr:
-						time.Sleep(defaultElection * 5 * time.Millisecond)
-					case raftStopErr, stopErr:
-					default:
-						t.Fatal(err)
-					}
-				}
-				cl.Node(i).WaitMode(standbyMode)
-			}
-			cl.Destroy()
-		}
-	}
-}
-
-// TODO(yicheng) Add test for becoming standby
-// maxSize -> standby
-// auto-demote -> standby
-// remove -> standby
-
-func TestReleaseVersion(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	resp, err := http.Get(cl.URL(0) + "/version")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer resp.Body.Close()
-	g, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		t.Error(err)
-	}
-	gs := string(g)
-	w := fmt.Sprintf("etcd %s", releaseVersion)
-	if gs != w {
-		t.Errorf("version = %v, want %v", gs, w)
-	}
-}
-
-func TestVersionCheck(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-
-	currentVersion := 2
-	tests := []struct {
-		version int
-		wStatus int
-	}{
-		{currentVersion - 1, http.StatusForbidden},
-		{currentVersion, http.StatusOK},
-		{currentVersion + 1, http.StatusForbidden},
-	}
-
-	for i, tt := range tests {
-		resp, err := http.Get(fmt.Sprintf("%s/raft/version/%d/check", u, tt.version))
-		if err != nil {
-			t.Fatal(err)
-		}
-		resp.Body.Close()
-		if resp.StatusCode != tt.wStatus {
-			t.Fatal("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-	}
-}
-
-func TestSingleNodeRecovery(t *testing.T) {
-	defer afterTest(t)
-	c := newTestConfig()
-	ts := testServer{Config: c}
-	ts.Start()
-	defer ts.Destroy()
-
-	ts.WaitMode(participantMode)
-
-	key := "/foo"
-	ev, err := ts.Participant().Set(key, false, "bar", time.Now().Add(time.Second*100))
-	if err != nil {
-		t.Fatal(err)
-	}
-	ts.Stop()
-
-	ts = testServer{Config: c}
-	ts.Start()
-	ts.WaitMode(participantMode)
-	w, err := ts.Participant().Store.Watch(key, false, false, ev.Index())
-	if err != nil {
-		t.Fatal(err)
-	}
-	// give testing server time to load the previous WAL file
-	select {
-	case <-w.EventChan:
-	case <-time.After(time.Second):
-		t.Fatal("watch timeout")
-	}
-}
-
-func TestTakingSnapshot(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	// TODO(xiangli): tunable compact; reduce testing time
-	for i := 0; i < defaultCompact; i++ {
-		cl.Participant(0).Set("/foo", false, "bar", store.Permanent)
-	}
-	snap := cl.Participant(0).node.GetSnap()
-	if snap.Index != int64(defaultCompact) {
-		t.Errorf("snap.Index = %d, want %d", snap.Index, defaultCompact)
-	}
-}
-
-func TestRestoreSnapshotFromLeader(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	// let leader do snapshot
-	for i := 0; i < defaultCompact; i++ {
-		cl.Participant(0).Set(fmt.Sprint("/foo", i), false, fmt.Sprint("bar", i), store.Permanent)
-	}
-
-	// create one to join the cluster
-	c := newTestConfig()
-	c.Name = "1"
-	c.Peers = []string{cl.URL(0)}
-	ts := &testServer{Config: c}
-	cl.Add(ts)
-
-	// check new proposal could be submitted
-	if _, err := cl.Participant(0).Set("/foo", false, "bar", store.Permanent); err != nil {
-		t.Fatal(err)
-	}
-
-	// check store is recovered
-	for i := 0; i < defaultCompact; i++ {
-		ev, err := ts.Participant().Store.Get(fmt.Sprint("/foo", i), false, false)
-		if err != nil {
-			t.Errorf("get err = %v", err)
-			continue
-		}
-		w := fmt.Sprint("bar", i)
-		if g := *ev.Node.Value; g != w {
-			t.Errorf("value = %v, want %v", g, w)
-		}
-	}
-
-	// check new proposal could be committed in the new machine
-	wch, err := ts.Participant().Watch("/foo", false, false, uint64(defaultCompact))
-	if err != nil {
-		t.Errorf("watch err = %v", err)
-	}
-	<-wch.EventChan
-
-	// check node map of two machines are the same
-	g := ts.Participant().node.Nodes()
-	w := cl.Participant(0).node.Nodes()
-	if !reflect.DeepEqual(g, w) {
-		t.Errorf("nodes = %v, want %v", g, w)
-	}
-}
-
-func TestSaveSnapshot(t *testing.T) {
-	defer afterTest(t)
-
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	n := cl.Node(0)
-	// TODO(xiangli): tunable compact; reduce testing time
-	for i := 0; i < defaultCompact; i++ {
-		n.Participant().Set("/foo", false, "bar", store.Permanent)
-	}
-	snapname := fmt.Sprintf("%016x-%016x-%016x.snap", n.Participant().clusterId, 1, defaultCompact)
-	snappath := path.Join(n.Config.DataDir, "snap", snapname)
-	if _, err := os.Stat(snappath); err != nil {
-		t.Errorf("err = %v, want nil", err)
-	}
-	walname := fmt.Sprintf("%016x-%016x.wal", 1, defaultCompact)
-	walpath := path.Join(n.Config.DataDir, "wal", walname)
-	if _, err := os.Stat(walpath); err != nil {
-		t.Errorf("err = %v, want nil", err)
-	}
-}
-
-func TestRestoreSnapshotFromDisk(t *testing.T) {
-	defer afterTest(t)
-
-	tests := []int{1, 3, 5}
-
-	// TODO(xiangli): tunable compact; reduce testing time
-	oldDefaultCompact := defaultCompact
-	defaultCompact = 10
-	defer func() { defaultCompact = oldDefaultCompact }()
-
-	for _, tt := range tests {
-		cl := testCluster{Size: tt}
-		cl.Start()
-		defer cl.Destroy()
-
-		lead, _ := cl.Leader()
-		for i := 0; i < defaultCompact+10; i++ {
-			cl.Participant(lead).Set(fmt.Sprint("/foo", i), false, fmt.Sprint("bar", i), store.Permanent)
-		}
-
-		cl.Stop()
-		cl.Restart()
-
-		lead, _ = cl.Leader()
-		// check store is recovered
-		for i := 0; i < defaultCompact+10; i++ {
-			ev, err := cl.Participant(lead).Store.Get(fmt.Sprint("/foo", i), false, false)
-			if err != nil {
-				t.Errorf("get err = %v", err)
-				continue
-			}
-			w := fmt.Sprint("bar", i)
-			if g := *ev.Node.Value; g != w {
-				t.Errorf("value = %v, want %v", g, w)
-			}
-		}
-		// check new proposal could be submitted
-		if _, err := cl.Participant(lead).Set("/foo", false, "bar", store.Permanent); err != nil {
-			t.Fatal(err)
-		}
-	}
-}
-
-type testCluster struct {
-	Size int
-	TLS  bool
-
-	nodes []*testServer
-}
-
-func (c *testCluster) Start() {
-	if c.Size <= 0 {
-		panic("cluster size <= 0")
-	}
-
-	nodes := make([]*testServer, c.Size)
-	c.nodes = nodes
-	cfg := newTestConfig()
-	cfg.Name = "testServer-0"
-	nodes[0] = &testServer{Config: cfg, TLS: c.TLS}
-	nodes[0].Start()
-	nodes[0].WaitMode(participantMode)
-
-	seed := nodes[0].URL
-	for i := 1; i < c.Size; i++ {
-		cfg := newTestConfig()
-		cfg.Name = "testServer-" + fmt.Sprint(i)
-		cfg.Peers = []string{seed}
-		s := &testServer{Config: cfg, TLS: c.TLS}
-		s.Start()
-		nodes[i] = s
-
-		// Wait for the previous configuration change to be committed
-		// or this configuration request might be dropped.
-		// Or it could be a slow join because it needs to retry.
-		// TODO: this might not be true if we add param for retry interval.
-		s.WaitMode(participantMode)
-		w, err := s.Participant().Watch(v2machineKVPrefix, true, false, uint64(i))
-		if err != nil {
-			panic(err)
-		}
-		<-w.EventChan
-	}
-	c.wait()
-}
-
-func (c *testCluster) wait() {
-	size := c.Size
-	for i := 0; i < size; i++ {
-		for k := 0; k < size; k++ {
-			s := c.Node(i)
-			wp := v2machineKVPrefix + fmt.Sprintf("/%d", c.Id(k))
-			w, err := s.Participant().Watch(wp, false, false, 1)
-			if err != nil {
-				panic(err)
-			}
-			<-w.EventChan
-		}
-	}
-
-	clusterId := c.Participant(0).node.ClusterId()
-	for i := 0; i < size; i++ {
-		if g := c.Participant(i).node.ClusterId(); g != clusterId {
-			panic(fmt.Sprintf("#%d: clusterId = %x, want %x", i, g, clusterId))
-		}
-	}
-}
-
-func (c *testCluster) Add(s *testServer) {
-	lead, _ := c.Leader()
-	// wait for the node to join the cluster
-	// TODO(yichengq): remove this when we get rid of all timeouts
-	wch, err := c.Participant(int(lead)).Watch(v2machineKVPrefix, true, false, 0)
-	if err != nil {
-		panic(err)
-	}
-	s.Start()
-	<-wch.EventChan
-	c.Size++
-	c.nodes = append(c.nodes, s)
-}
-
-func (c *testCluster) Node(i int) *testServer {
-	return c.nodes[i]
-}
-
-func (c *testCluster) Participant(i int) *participant {
-	return c.Node(i).Participant()
-}
-
-func (c *testCluster) Standby(i int) *standby {
-	return c.Node(i).Standby()
-}
-
-func (c *testCluster) URL(i int) string {
-	return c.nodes[i].h.URL
-}
-
-func (c *testCluster) Id(i int) int64 {
-	return c.Participant(i).id
-}
-
-func (c *testCluster) Restart() {
-	for _, s := range c.nodes {
-		s.Start()
-	}
-}
-
-func (c *testCluster) Stop() {
-	for _, s := range c.nodes {
-		s.Stop()
-	}
-}
-
-func (c *testCluster) Destroy() {
-	for _, s := range c.nodes {
-		s.Destroy()
-	}
-}
-
-// Leader returns the index of leader in the cluster and its leader term.
-func (c *testCluster) Leader() (leadIdx int, term int64) {
-	ids := make(map[int64]int)
-	for {
-		ls := make([]leadterm, 0, c.Size)
-		for i := range c.nodes {
-			switch c.Node(i).e.mode.Get() {
-			case participantMode:
-				ls = append(ls, c.Node(i).Lead())
-				ids[c.Id(i)] = i
-			case standbyMode:
-				//TODO(xiangli) add standby support
-			case stopMode:
-			}
-		}
-		if isSameLead(ls) {
-			return ids[ls[0].lead], ls[0].term
-		}
-		time.Sleep(c.Node(0).e.tickDuration * defaultElection)
-	}
-}
-
-type leadterm struct {
-	lead int64
-	term int64
-}
-
-func isSameLead(ls []leadterm) bool {
-	m := make(map[leadterm]int)
-	for i := range ls {
-		m[ls[i]] = m[ls[i]] + 1
-	}
-	if len(m) == 1 {
-		if ls[0].lead == -1 {
-			return false
-		}
-		return true
-	}
-	// todo(xiangli): printout the current cluster status for debugging....
-	return false
-}
-
-type testServer struct {
-	Config *conf.Config
-	TLS    bool
-
-	// base URL of form http://ipaddr:port with no trailing slash
-	URL string
-
-	e *Server
-	h *httptest.Server
-}
-
-func (s *testServer) Start() {
-	if s.Config == nil {
-		s.Config = newTestConfig()
-	}
-	c := s.Config
-	if !strings.HasPrefix(c.DataDir, os.TempDir()) {
-		panic("dataDir may pollute file system")
-	}
-	if c.Peer.CAFile != "" || c.Peer.CertFile != "" || c.Peer.KeyFile != "" {
-		panic("use TLS field instead")
-	}
-
-	nc := *c
-	e, err := New(&nc)
-	if err != nil {
-		panic(err)
-	}
-	s.e = e
-	tick := time.Duration(c.Peer.HeartbeatInterval) * time.Millisecond
-	e.SetTick(tick)
-
-	m := http.NewServeMux()
-	m.Handle("/", e)
-	m.Handle("/raft", e.RaftHandler())
-	m.Handle("/raft/", e.RaftHandler())
-	m.Handle("/v2/admin/", e.RaftHandler())
-
-	addr := c.Addr
-	if s.URL != "" {
-		addr = urlHost(s.URL)
-	}
-	s.h = startServingAddr(addr, m, s.TLS)
-	s.URL = s.h.URL
-
-	e.pubAddr = s.URL
-	e.raftPubAddr = s.URL
-	e.cfg.Addr = s.URL
-	e.cfg.Peer.Addr = s.URL
-	go e.Run()
-}
-
-func (s *testServer) WaitMode(mode int64) {
-	for i := 0; i < 30; i++ {
-		if s.e.mode.Get() == mode {
-			return
-		}
-		time.Sleep(time.Millisecond)
-	}
-	panic("waitMode should never take more than 30ms.")
-}
-
-func (s *testServer) Participant() *participant {
-	if s.e.mode.Get() != participantMode {
-		return nil
-	}
-	return s.e.p
-}
-
-func (s *testServer) Standby() *standby {
-	return s.e.s
-}
-
-func (s *testServer) Lead() leadterm {
-	return leadterm{s.Participant().node.Leader(), s.Participant().node.Term()}
-}
-
-func (s *testServer) Stop() error {
-	err := s.e.Stop()
-	s.h.Close()
-	return err
-}
-
-func (s *testServer) Destroy() error {
-	err := s.Stop()
-	if err := os.RemoveAll(s.Config.DataDir); err != nil {
-		panic(err)
-	}
-	return err
-}
-
-func startServingAddr(addr string, h http.Handler, tls bool) *httptest.Server {
-	var l net.Listener
-	var err error
-	for i := 0; i < 4; i++ {
-		l, err = net.Listen("tcp", addr)
-		if err == nil {
-			break
-		}
-		if !strings.Contains(err.Error(), "address already in use") {
-			panic(err)
-		}
-		time.Sleep(500 * time.Millisecond)
-	}
-	if l == nil {
-		panic("cannot listen on " + addr)
-	}
-	hs := &httptest.Server{
-		Listener: l,
-		Config:   &http.Server{Handler: h},
-	}
-	if tls {
-		hs.StartTLS()
-	} else {
-		hs.Start()
-	}
-	return hs
-}
-
-func newTestConfig() *conf.Config {
-	c := conf.New()
-	c.Addr = "127.0.0.1:0"
-	c.Peer.Addr = "127.0.0.1:0"
-	c.Peer.HeartbeatInterval = 5
-	c.Peer.ElectionTimeout = 25
-	c.RetryInterval = 1 / 10.0
-	dataDir, err := ioutil.TempDir(os.TempDir(), "etcd")
-	if err != nil {
-		panic(err)
-	}
-	c.DataDir = dataDir
-	return c
-}
-
-func urlHost(urlStr string) string {
-	u, err := url.Parse(urlStr)
-	if err != nil {
-		panic(err)
-	}
-	return u.Host
-}

+ 3 - 2
etcdserver2/etcdhttp/http.go → etcdserver/etcdhttp/http.go

@@ -17,11 +17,12 @@ import (
 
 	crand "crypto/rand"
 	"math/rand"
+
 	"code.google.com/p/go.net/context"
 	"github.com/coreos/etcd/elog"
 	etcderrors "github.com/coreos/etcd/error"
-	etcdserver "github.com/coreos/etcd/etcdserver2"
-	"github.com/coreos/etcd/etcdserver2/etcdserverpb"
+	"github.com/coreos/etcd/etcdserver"
+	"github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/store"
 )

+ 2 - 1
etcdserver2/etcdhttp/http_test.go → etcdserver/etcdhttp/http_test.go

@@ -8,9 +8,10 @@ import (
 	"reflect"
 	"testing"
 	"time"
+
 	"code.google.com/p/go.net/context"
 
-	etcdserver "github.com/coreos/etcd/etcdserver2"
+	"github.com/coreos/etcd/etcdserver"
 	"github.com/coreos/etcd/raft"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/store"

+ 0 - 0
etcdserver2/etcdserverpb/etcdserver.pb.go → etcdserver/etcdserverpb/etcdserver.pb.go


+ 0 - 0
etcdserver2/etcdserverpb/etcdserver.proto → etcdserver/etcdserverpb/etcdserver.proto


+ 0 - 0
etcdserver2/etcdserverpb/genproto.sh → etcdserver/etcdserverpb/genproto.sh


+ 0 - 0
etcdserver2/example_test.go → etcdserver/example_test.go


+ 0 - 25
etcdserver/package_stats.go

@@ -1,25 +0,0 @@
-package etcdserver
-
-import (
-	"time"
-)
-
-// packageStats represent the stats we need for a package.
-// It has sending time and the size of the package.
-type packageStats struct {
-	sendingTime time.Time
-	size        int
-}
-
-// NewPackageStats creates a pacakgeStats and return the pointer to it.
-func NewPackageStats(now time.Time, size int) *packageStats {
-	return &packageStats{
-		sendingTime: now,
-		size:        size,
-	}
-}
-
-// Time return the sending time of the package.
-func (ps *packageStats) Time() time.Time {
-	return ps.sendingTime
-}

+ 0 - 522
etcdserver/participant.go

@@ -1,522 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"log"
-	"math/rand"
-	"net/http"
-	"net/url"
-	"os"
-	"path"
-	"time"
-
-	"github.com/coreos/etcd/conf"
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/raft"
-	"github.com/coreos/etcd/snap"
-	"github.com/coreos/etcd/store"
-	"github.com/coreos/etcd/wal"
-)
-
-const (
-	defaultHeartbeat = 1
-	defaultElection  = 5
-
-	maxBufferedProposal = 128
-
-	defaultTickDuration = time.Millisecond * 100
-
-	v2machineKVPrefix = "/_etcd/machines"
-	v2configKVPrefix  = "/_etcd/config"
-
-	v2Prefix              = "/v2/keys"
-	v2machinePrefix       = "/v2/machines"
-	v2peersPrefix         = "/v2/peers"
-	v2LeaderPrefix        = "/v2/leader"
-	v2SelfStatsPrefix     = "/v2/stats/self"
-	v2LeaderStatsPrefix   = "/v2/stats/leader"
-	v2StoreStatsPrefix    = "/v2/stats/store"
-	v2adminConfigPrefix   = "/v2/admin/config"
-	v2adminMachinesPrefix = "/v2/admin/machines/"
-)
-
-var (
-	defaultCompact = 10000
-
-	tmpErr      = fmt.Errorf("try again")
-	stopErr     = fmt.Errorf("server is stopped")
-	raftStopErr = fmt.Errorf("raft is stopped")
-)
-
-type participant struct {
-	id           int64
-	clusterId    int64
-	cfg          *conf.Config
-	pubAddr      string
-	raftPubAddr  string
-	tickDuration time.Duration
-
-	client  *v2client
-	peerHub *peerHub
-
-	proposal    chan v2Proposal
-	addNodeC    chan raft.Config
-	removeNodeC chan raft.Config
-	node        *v2Raft
-	store.Store
-	rh          *raftHandler
-	w           *wal.WAL
-	snapshotter *snap.Snapshotter
-	serverStats *raftServerStats
-
-	stopNotifyc chan struct{}
-
-	*http.ServeMux
-}
-
-func newParticipant(c *conf.Config, client *v2client, peerHub *peerHub, tickDuration time.Duration) (*participant, error) {
-	p := &participant{
-		clusterId:    -1,
-		cfg:          c,
-		tickDuration: tickDuration,
-
-		client:  client,
-		peerHub: peerHub,
-
-		proposal:    make(chan v2Proposal, maxBufferedProposal),
-		addNodeC:    make(chan raft.Config, 1),
-		removeNodeC: make(chan raft.Config, 1),
-		node: &v2Raft{
-			result: make(map[wait]chan interface{}),
-		},
-		Store:       store.New(),
-		serverStats: NewRaftServerStats(c.Name),
-
-		stopNotifyc: make(chan struct{}),
-
-		ServeMux: http.NewServeMux(),
-	}
-	p.rh = newRaftHandler(peerHub, p.Store.Version(), p.serverStats)
-	p.peerHub.setServerStats(p.serverStats)
-
-	snapDir := path.Join(p.cfg.DataDir, "snap")
-	if err := os.Mkdir(snapDir, 0700); err != nil {
-		if !os.IsExist(err) {
-			log.Printf("id=%x participant.new.mkdir err=%v", p.id, err)
-			return nil, err
-		}
-	}
-	p.snapshotter = snap.New(snapDir)
-
-	walDir := path.Join(p.cfg.DataDir, "wal")
-	if err := os.Mkdir(walDir, 0700); err != nil {
-		if !os.IsExist(err) {
-			log.Printf("id=%x participant.new.mkdir err=%v", p.id, err)
-			return nil, err
-		}
-	}
-
-	var w *wal.WAL
-	var err error
-	if !wal.Exist(walDir) {
-		p.id = genId()
-		p.pubAddr = c.Addr
-		p.raftPubAddr = c.Peer.Addr
-		if w, err = wal.Create(walDir); err != nil {
-			return nil, err
-		}
-		p.node.Node = raft.New(p.id, defaultHeartbeat, defaultElection)
-		info := p.node.Info()
-		if err = w.SaveInfo(&info); err != nil {
-			return nil, err
-		}
-		log.Printf("id=%x participant.new path=%s\n", p.id, walDir)
-	} else {
-		s, err := p.snapshotter.Load()
-		if err != nil && err != snap.ErrNoSnapshot {
-			log.Printf("participant.snapload err=%s\n", err)
-			return nil, err
-		}
-		var snapIndex int64
-		if s != nil {
-			if err := p.Recovery(s.Data); err != nil {
-				log.Printf("store.recover err=%v", err)
-				return nil, err
-			}
-			log.Printf("participant.store.recovered index=%d\n", s.Index)
-
-			for _, node := range s.Nodes {
-				pp := path.Join(v2machineKVPrefix, fmt.Sprint(node))
-				ev, err := p.Store.Get(pp, false, false)
-				if err != nil {
-					log.Printf("store.get err=%v", err)
-					return nil, err
-				}
-				q, err := url.ParseQuery(*ev.Node.Value)
-				if err != nil {
-					log.Printf("url.parse err=%v", err)
-					return nil, err
-				}
-				peer, err := p.peerHub.add(node, q["raft"][0])
-				if err != nil {
-					log.Printf("peerHub.add err=%v", err)
-					return nil, err
-				}
-				peer.participate()
-			}
-
-			snapIndex = s.Index
-		}
-		n, err := wal.Read(walDir, snapIndex)
-		if err != nil {
-			return nil, err
-		}
-		p.id = n.Id
-		p.node.Node = raft.Recover(n.Id, s, n.Ents, n.State, defaultHeartbeat, defaultElection)
-		p.apply(p.node.Next())
-		log.Printf("id=%x participant.load path=%s snapIndex=%d state=\"%+v\" len(ents)=%d", p.id, p.cfg.DataDir, snapIndex, n.State, len(n.Ents))
-		if w, err = wal.Open(walDir); err != nil {
-			return nil, err
-		}
-	}
-	p.w = w
-
-	p.Handle(v2Prefix+"/", handlerErr(p.serveValue))
-	p.Handle(v2machinePrefix, handlerErr(p.serveMachines))
-	p.Handle(v2peersPrefix, handlerErr(p.serveMachines))
-	p.Handle(v2LeaderPrefix, handlerErr(p.serveLeader))
-	p.Handle(v2SelfStatsPrefix, handlerErr(p.serveSelfStats))
-	p.Handle(v2LeaderStatsPrefix, handlerErr(p.serveLeaderStats))
-	p.Handle(v2StoreStatsPrefix, handlerErr(p.serveStoreStats))
-	p.rh.Handle(v2adminConfigPrefix, handlerErr(p.serveAdminConfig))
-	p.rh.Handle(v2adminMachinesPrefix, handlerErr(p.serveAdminMachines))
-
-	// TODO: remind to set application/json for /v2/stats endpoint
-
-	return p, nil
-}
-
-func (p *participant) run(stop chan struct{}) error {
-	defer p.cleanup()
-
-	if p.node.IsEmpty() {
-		seeds := p.peerHub.getSeeds()
-		if len(seeds) == 0 {
-			log.Printf("id=%x participant.run action=bootstrap\n", p.id)
-			p.node.Campaign()
-			p.node.InitCluster(genId())
-			p.node.Add(p.id, p.raftPubAddr, []byte(p.pubAddr))
-			p.apply(p.node.Next())
-		} else {
-			log.Printf("id=%x participant.run action=join seeds=\"%v\"\n", p.id, seeds)
-			if err := p.join(); err != nil {
-				log.Printf("id=%x participant.join err=%q", p.id, err)
-				return err
-			}
-		}
-	}
-
-	p.rh.start()
-	defer p.rh.stop()
-
-	node := p.node
-	recv := p.rh.recv
-
-	ticker := time.NewTicker(p.tickDuration)
-	defer ticker.Stop()
-	v2SyncTicker := time.NewTicker(time.Millisecond * 500)
-	defer v2SyncTicker.Stop()
-
-	var proposal chan v2Proposal
-	var addNodeC, removeNodeC chan raft.Config
-	for {
-		if node.HasLeader() {
-			proposal = p.proposal
-			addNodeC = p.addNodeC
-			removeNodeC = p.removeNodeC
-		} else {
-			proposal = nil
-			addNodeC = nil
-			removeNodeC = nil
-		}
-		select {
-		case p := <-proposal:
-			node.Propose(p)
-		case c := <-addNodeC:
-			node.UpdateConf(raft.AddNode, &c)
-		case c := <-removeNodeC:
-			node.UpdateConf(raft.RemoveNode, &c)
-		case msg := <-recv:
-			node.Step(*msg)
-		case <-ticker.C:
-			node.Tick()
-		case <-v2SyncTicker.C:
-			node.Sync()
-		case <-stop:
-			log.Printf("id=%x participant.stop\n", p.id)
-			return nil
-		}
-		if s := node.UnstableSnapshot(); !s.IsEmpty() {
-			if err := p.Recovery(s.Data); err != nil {
-				log.Printf("id=%x participant.recover err=%q", p.id, err)
-				return err
-			}
-			log.Printf("id=%x participant.recovered index=%d", p.id, s.Index)
-		}
-		p.apply(node.Next())
-		if err := p.save(node.UnstableEnts(), node.UnstableState()); err != nil {
-			return err
-		}
-		p.send(node.Msgs())
-		if node.IsRemoved() {
-			log.Printf("id=%x participant.end\n", p.id)
-			return nil
-		}
-		if p.node.EntsLen() > defaultCompact {
-			d, err := p.Save()
-			if err != nil {
-				log.Printf("id=%x participant.compact err=%q", p.id, err)
-				return err
-			}
-			p.node.Compact(d)
-			snap := p.node.GetSnap()
-			log.Printf("id=%x compacted index=%d", p.id, snap.Index)
-			if err := p.snapshotter.Save(&snap); err != nil {
-				log.Printf("id=%x snapshot.save err=%v", p.id, err)
-				return err
-			}
-			if err := p.w.Cut(p.node.Index()); err != nil {
-				log.Printf("id=%x wal.cut err=%v", p.id, err)
-				return err
-			}
-			info := p.node.Info()
-			if err = p.w.SaveInfo(&info); err != nil {
-				log.Printf("id=%x wal.saveInfo err=%v", p.id, err)
-				return err
-			}
-		}
-	}
-}
-
-func (p *participant) cleanup() {
-	p.w.Close()
-	close(p.stopNotifyc)
-	p.peerHub.stop()
-}
-
-func (p *participant) raftHandler() http.Handler {
-	return p.rh
-}
-
-func (p *participant) add(id int64, raftPubAddr string, pubAddr string) error {
-	log.Printf("id=%x participant.add nodeId=%x raftPubAddr=%s pubAddr=%s\n", p.id, id, raftPubAddr, pubAddr)
-	pp := path.Join(v2machineKVPrefix, fmt.Sprint(id))
-
-	_, err := p.Store.Get(pp, false, false)
-	if err == nil {
-		return nil
-	}
-	if v, ok := err.(*etcdErr.Error); !ok || v.ErrorCode != etcdErr.EcodeKeyNotFound {
-		log.Printf("id=%x participant.add getErr=\"%v\"\n", p.id, err)
-		return err
-	}
-
-	w, err := p.Watch(pp, true, false, 0)
-	if err != nil {
-		log.Printf("id=%x participant.add watchErr=\"%v\"\n", p.id, err)
-		return tmpErr
-	}
-
-	select {
-	case p.addNodeC <- raft.Config{NodeId: id, Addr: raftPubAddr, Context: []byte(pubAddr)}:
-	default:
-		w.Remove()
-		log.Printf("id=%x participant.add proposeErr=\"unable to send out addNode proposal\"\n", p.id)
-		return tmpErr
-	}
-
-	select {
-	case v := <-w.EventChan:
-		if v.Action == store.Set {
-			return nil
-		}
-		log.Printf("id=%x participant.add watchErr=\"unexpected action\" action=%s\n", p.id, v.Action)
-		return tmpErr
-	case <-time.After(6 * defaultHeartbeat * p.tickDuration):
-		w.Remove()
-		log.Printf("id=%x participant.add watchErr=timeout\n", p.id)
-		return tmpErr
-	case <-p.stopNotifyc:
-		return stopErr
-	}
-}
-
-func (p *participant) remove(id int64) error {
-	log.Printf("id=%x participant.remove nodeId=%x\n", p.id, id)
-	pp := path.Join(v2machineKVPrefix, fmt.Sprint(id))
-
-	v, err := p.Store.Get(pp, false, false)
-	if err != nil {
-		return nil
-	}
-
-	select {
-	case p.removeNodeC <- raft.Config{NodeId: id}:
-	default:
-		log.Printf("id=%x participant.remove proposeErr=\"unable to send out removeNode proposal\"\n", p.id)
-		return tmpErr
-	}
-
-	// TODO(xiangli): do not need to watch if the
-	// removal target is self
-	w, err := p.Watch(pp, true, false, v.Index()+1)
-	if err != nil {
-		log.Printf("id=%x participant.remove watchErr=\"%v\"\n", p.id, err)
-		return tmpErr
-	}
-
-	select {
-	case v := <-w.EventChan:
-		if v.Action == store.Delete {
-			return nil
-		}
-		log.Printf("id=%x participant.remove watchErr=\"unexpected action\" action=%s\n", p.id, v.Action)
-		return tmpErr
-	case <-time.After(6 * defaultHeartbeat * p.tickDuration):
-		w.Remove()
-		log.Printf("id=%x participant.remove watchErr=timeout\n", p.id)
-		return tmpErr
-	case <-p.stopNotifyc:
-		return stopErr
-	}
-}
-
-func (p *participant) apply(ents []raft.Entry) {
-	offset := p.node.Applied() - int64(len(ents)) + 1
-	for i, ent := range ents {
-		switch ent.Type {
-		// expose raft entry type
-		case raft.Normal:
-			if len(ent.Data) == 0 {
-				continue
-			}
-			p.v2apply(offset+int64(i), ent)
-		case raft.ClusterInit:
-			p.clusterId = p.node.ClusterId()
-			log.Printf("id=%x participant.cluster.setId clusterId=%x\n", p.id, p.clusterId)
-		case raft.AddNode:
-			cfg := new(raft.Config)
-			if err := json.Unmarshal(ent.Data, cfg); err != nil {
-				log.Printf("id=%x participant.cluster.addNode unmarshalErr=\"%v\"\n", p.id, err)
-				break
-			}
-			pp := path.Join(v2machineKVPrefix, fmt.Sprint(cfg.NodeId))
-			if ev, _ := p.Store.Get(pp, false, false); ev != nil {
-				log.Printf("id=%x participant.cluster.addNode err=existed value=%q", p.id, *ev.Node.Value)
-				break
-			}
-			peer, err := p.peerHub.add(cfg.NodeId, cfg.Addr)
-			if err != nil {
-				log.Printf("id=%x participant.cluster.addNode peerAddErr=\"%v\"\n", p.id, err)
-				break
-			}
-			peer.participate()
-			p.Store.Set(pp, false, fmt.Sprintf("raft=%v&etcd=%v", cfg.Addr, string(cfg.Context)), store.Permanent)
-			if p.id == cfg.NodeId {
-				p.raftPubAddr = cfg.Addr
-				p.pubAddr = string(cfg.Context)
-			}
-			log.Printf("id=%x participant.cluster.addNode nodeId=%x addr=%s context=%s\n", p.id, cfg.NodeId, cfg.Addr, cfg.Context)
-		case raft.RemoveNode:
-			cfg := new(raft.Config)
-			if err := json.Unmarshal(ent.Data, cfg); err != nil {
-				log.Printf("id=%x participant.cluster.removeNode unmarshalErr=\"%v\"\n", p.id, err)
-				break
-			}
-			peer, err := p.peerHub.peer(cfg.NodeId)
-			if err != nil {
-				log.Fatal("id=%x participant.apply getPeerErr=\"%v\"", p.id, err)
-			}
-			peer.idle()
-			pp := path.Join(v2machineKVPrefix, fmt.Sprint(cfg.NodeId))
-			p.Store.Delete(pp, false, false)
-			log.Printf("id=%x participant.cluster.removeNode nodeId=%x\n", p.id, cfg.NodeId)
-		default:
-			panic("unimplemented")
-		}
-	}
-}
-
-func (p *participant) save(ents []raft.Entry, state raft.State) error {
-	for _, ent := range ents {
-		if err := p.w.SaveEntry(&ent); err != nil {
-			log.Printf("id=%x participant.save saveEntryErr=%q", p.id, err)
-			return err
-		}
-	}
-	if !state.IsEmpty() {
-		if err := p.w.SaveState(&state); err != nil {
-			log.Printf("id=%x participant.save saveStateErr=%q", p.id, err)
-			return err
-		}
-	}
-	if err := p.w.Sync(); err != nil {
-		log.Printf("id=%x participant.save syncErr=%q", p.id, err)
-		return err
-	}
-	return nil
-}
-
-func (p *participant) send(msgs []raft.Message) {
-	for i := range msgs {
-		if err := p.peerHub.send(msgs[i]); err != nil {
-			log.Printf("id=%x participant.send err=\"%v\"\n", p.id, err)
-		}
-	}
-}
-
-func (p *participant) join() error {
-	info := &context{
-		MinVersion: store.MinVersion(),
-		MaxVersion: store.MaxVersion(),
-		ClientURL:  p.pubAddr,
-		PeerURL:    p.raftPubAddr,
-	}
-
-	max := p.cfg.MaxRetryAttempts
-	for attempt := 0; ; attempt++ {
-		for seed := range p.peerHub.getSeeds() {
-			if err := p.client.AddMachine(seed, fmt.Sprint(p.id), info); err == nil {
-				return nil
-			} else {
-				log.Printf("id=%x participant.join addMachineErr=\"%v\"\n", p.id, err)
-			}
-		}
-		if attempt == max {
-			return fmt.Errorf("etcd: cannot join cluster after %d attempts", max)
-		}
-		time.Sleep(time.Millisecond * time.Duration(p.cfg.RetryInterval*1000))
-	}
-}
-
-func genId() int64 {
-	r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
-	return r.Int63()
-}

+ 0 - 151
etcdserver/peer.go

@@ -1,151 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"bytes"
-	"fmt"
-	"log"
-	"net/http"
-	"sync"
-	"sync/atomic"
-	"time"
-)
-
-const (
-	maxInflight = 4
-)
-
-const (
-	participantPeer = iota
-	idlePeer
-	stoppedPeer
-)
-
-type peer struct {
-	url           string
-	queue         chan []byte
-	status        int
-	inflight      atomicInt
-	c             *http.Client
-	followerStats *raftFollowerStats
-	mu            sync.RWMutex
-	wg            sync.WaitGroup
-}
-
-func newPeer(url string, c *http.Client, followerStats *raftFollowerStats) *peer {
-	return &peer{
-		url:           url,
-		status:        idlePeer,
-		c:             c,
-		followerStats: followerStats,
-	}
-}
-
-func (p *peer) participate() {
-	p.mu.Lock()
-	defer p.mu.Unlock()
-	p.queue = make(chan []byte)
-	p.status = participantPeer
-	for i := 0; i < maxInflight; i++ {
-		p.wg.Add(1)
-		go p.handle(p.queue)
-	}
-}
-
-func (p *peer) idle() {
-	p.mu.Lock()
-	defer p.mu.Unlock()
-	if p.status == participantPeer {
-		close(p.queue)
-	}
-	p.status = idlePeer
-}
-
-func (p *peer) stop() {
-	p.mu.Lock()
-	if p.status == participantPeer {
-		close(p.queue)
-	}
-	p.status = stoppedPeer
-	p.mu.Unlock()
-	p.wg.Wait()
-}
-
-func (p *peer) handle(queue chan []byte) {
-	defer p.wg.Done()
-	for d := range queue {
-		p.post(d)
-	}
-}
-
-func (p *peer) send(d []byte) error {
-	p.mu.Lock()
-	defer p.mu.Unlock()
-
-	switch p.status {
-	case participantPeer:
-		select {
-		case p.queue <- d:
-		default:
-			return fmt.Errorf("reach max serving")
-		}
-	case idlePeer:
-		if p.inflight.Get() > maxInflight {
-			return fmt.Errorf("reach max idle")
-		}
-		p.wg.Add(1)
-		go func() {
-			p.post(d)
-			p.wg.Done()
-		}()
-	case stoppedPeer:
-		return fmt.Errorf("sender stopped")
-	}
-	return nil
-}
-
-func (p *peer) post(d []byte) {
-	p.inflight.Add(1)
-	defer p.inflight.Add(-1)
-	buf := bytes.NewBuffer(d)
-	start := time.Now()
-	resp, err := p.c.Post(p.url, "application/octet-stream", buf)
-	end := time.Now()
-	// TODO: Have no way to detect RPC success or failure now
-	p.followerStats.Succ(end.Sub(start))
-	if err != nil {
-		log.Printf("peer.post url=%s err=\"%v\"", p.url, err)
-		return
-	}
-	resp.Body.Close()
-}
-
-// An AtomicInt is an int64 to be accessed atomically.
-type atomicInt int64
-
-func (i *atomicInt) Add(d int64) {
-	atomic.AddInt64((*int64)(i), d)
-}
-
-func (i *atomicInt) Get() int64 {
-	return atomic.LoadInt64((*int64)(i))
-}
-
-func (i *atomicInt) Set(n int64) {
-	atomic.StoreInt64((*int64)(i), n)
-}

+ 0 - 174
etcdserver/peer_hub.go

@@ -1,174 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"net/url"
-	"path"
-	"sync"
-	"time"
-
-	"github.com/coreos/etcd/raft"
-)
-
-var (
-	errUnknownPeer = errors.New("unknown peer")
-)
-
-type peerGetter interface {
-	peer(id int64) (*peer, error)
-}
-
-type peerHub struct {
-	mu             sync.RWMutex
-	stopped        bool
-	seeds          map[string]bool
-	peers          map[int64]*peer
-	c              *http.Client
-	followersStats *raftFollowersStats
-	serverStats    *raftServerStats
-}
-
-func newPeerHub(c *http.Client, followersStats *raftFollowersStats) *peerHub {
-	h := &peerHub{
-		peers:          make(map[int64]*peer),
-		seeds:          make(map[string]bool),
-		c:              c,
-		followersStats: followersStats,
-	}
-	return h
-}
-
-func (h *peerHub) setServerStats(serverStats *raftServerStats) {
-	h.serverStats = serverStats
-}
-
-func (h *peerHub) setSeeds(seeds []string) {
-	for _, seed := range seeds {
-		h.seeds[seed] = true
-	}
-}
-
-func (h *peerHub) getSeeds() map[string]bool {
-	h.mu.RLock()
-	defer h.mu.RUnlock()
-	s := make(map[string]bool)
-	for k, v := range h.seeds {
-		s[k] = v
-	}
-	return s
-}
-
-func (h *peerHub) stop() {
-	h.mu.Lock()
-	defer h.mu.Unlock()
-	h.stopped = true
-	for _, p := range h.peers {
-		p.stop()
-	}
-	h.followersStats.Reset()
-	// http.Transport needs some time to put used connections
-	// into idle queues.
-	time.Sleep(time.Millisecond)
-	tr := h.c.Transport.(*http.Transport)
-	tr.CloseIdleConnections()
-}
-
-func (h *peerHub) peer(id int64) (*peer, error) {
-	h.mu.Lock()
-	defer h.mu.Unlock()
-	if h.stopped {
-		return nil, fmt.Errorf("peerHub stopped")
-	}
-	if p, ok := h.peers[id]; ok {
-		return p, nil
-	}
-	return nil, fmt.Errorf("peer %d not found", id)
-}
-
-func (h *peerHub) add(id int64, rawurl string) (*peer, error) {
-	u, err := url.Parse(rawurl)
-	if err != nil {
-		return nil, err
-	}
-	u.Path = raftPrefix
-
-	h.mu.Lock()
-	defer h.mu.Unlock()
-	if h.stopped {
-		return nil, fmt.Errorf("peerHub stopped")
-	}
-	h.peers[id] = newPeer(u.String(), h.c, h.followersStats.Follower(fmt.Sprint(id)))
-	return h.peers[id], nil
-}
-
-func (h *peerHub) send(msg raft.Message) error {
-	if p, err := h.fetch(msg.To); err == nil {
-		data, err := json.Marshal(msg)
-		if err != nil {
-			return err
-		}
-		if msg.IsMsgApp() {
-			h.serverStats.SendAppendReq(len(data))
-		}
-		p.send(data)
-		return nil
-	}
-	return errUnknownPeer
-}
-
-func (h *peerHub) fetch(nodeId int64) (*peer, error) {
-	if p, err := h.peer(nodeId); err == nil {
-		return p, nil
-	}
-	for seed := range h.seeds {
-		if p, err := h.seedFetch(seed, nodeId); err == nil {
-			return p, nil
-		}
-	}
-	return nil, fmt.Errorf("cannot fetch the address of node %d", nodeId)
-}
-
-func (h *peerHub) seedFetch(seedurl string, id int64) (*peer, error) {
-	u, err := url.Parse(seedurl)
-	if err != nil {
-		return nil, fmt.Errorf("cannot parse the url of the given seed")
-	}
-
-	u.Path = path.Join("/raft/cfg", fmt.Sprint(id))
-	resp, err := h.c.Get(u.String())
-	if err != nil {
-		return nil, fmt.Errorf("cannot reach %v", u)
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("cannot find node %d via %s", id, seedurl)
-	}
-
-	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, fmt.Errorf("cannot reach %v", u)
-	}
-
-	return h.add(id, string(b))
-}

+ 0 - 77
etcdserver/raft_follower_stats.go

@@ -1,77 +0,0 @@
-package etcdserver
-
-import (
-	"math"
-	"time"
-)
-
-type raftFollowersStats struct {
-	Leader    string                        `json:"leader"`
-	Followers map[string]*raftFollowerStats `json:"followers"`
-}
-
-func NewRaftFollowersStats(name string) *raftFollowersStats {
-	return &raftFollowersStats{
-		Leader:    name,
-		Followers: make(map[string]*raftFollowerStats),
-	}
-}
-
-func (fs *raftFollowersStats) Follower(name string) *raftFollowerStats {
-	follower, ok := fs.Followers[name]
-	if !ok {
-		follower = &raftFollowerStats{}
-		follower.Latency.Minimum = 1 << 63
-		fs.Followers[name] = follower
-	}
-	return follower
-}
-
-func (fs *raftFollowersStats) Reset() {
-	fs.Followers = make(map[string]*raftFollowerStats)
-}
-
-type raftFollowerStats struct {
-	Latency struct {
-		Current           float64 `json:"current"`
-		Average           float64 `json:"average"`
-		averageSquare     float64
-		StandardDeviation float64 `json:"standardDeviation"`
-		Minimum           float64 `json:"minimum"`
-		Maximum           float64 `json:"maximum"`
-	} `json:"latency"`
-
-	Counts struct {
-		Fail    uint64 `json:"fail"`
-		Success uint64 `json:"success"`
-	} `json:"counts"`
-}
-
-// Succ function update the raftFollowerStats with a successful send
-func (ps *raftFollowerStats) Succ(d time.Duration) {
-	total := float64(ps.Counts.Success) * ps.Latency.Average
-	totalSquare := float64(ps.Counts.Success) * ps.Latency.averageSquare
-
-	ps.Counts.Success++
-
-	ps.Latency.Current = float64(d) / (1000000.0)
-
-	if ps.Latency.Current > ps.Latency.Maximum {
-		ps.Latency.Maximum = ps.Latency.Current
-	}
-
-	if ps.Latency.Current < ps.Latency.Minimum {
-		ps.Latency.Minimum = ps.Latency.Current
-	}
-
-	ps.Latency.Average = (total + ps.Latency.Current) / float64(ps.Counts.Success)
-	ps.Latency.averageSquare = (totalSquare + ps.Latency.Current*ps.Latency.Current) / float64(ps.Counts.Success)
-
-	// sdv = sqrt(avg(x^2) - avg(x)^2)
-	ps.Latency.StandardDeviation = math.Sqrt(ps.Latency.averageSquare - ps.Latency.Average*ps.Latency.Average)
-}
-
-// Fail function update the raftFollowerStats with a unsuccessful send
-func (ps *raftFollowerStats) Fail() {
-	ps.Counts.Fail++
-}

+ 0 - 140
etcdserver/raft_handler.go

@@ -1,140 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"log"
-	"net/http"
-	"strconv"
-	"sync"
-
-	"github.com/coreos/etcd/raft"
-	"github.com/coreos/etcd/store"
-)
-
-const (
-	raftPrefix = "/raft"
-)
-
-type raftHandler struct {
-	mu      sync.RWMutex
-	serving bool
-
-	peerGetter   peerGetter
-	storeVersion int
-	serverStats  *raftServerStats
-
-	recv chan *raft.Message
-	*http.ServeMux
-}
-
-func newRaftHandler(p peerGetter, version int, serverStats *raftServerStats) *raftHandler {
-	h := &raftHandler{
-		recv:         make(chan *raft.Message, 512),
-		peerGetter:   p,
-		storeVersion: version,
-		serverStats:  serverStats,
-	}
-	h.ServeMux = http.NewServeMux()
-	h.ServeMux.HandleFunc(raftPrefix+"/cfg/", h.serveCfg)
-	h.ServeMux.HandleFunc(raftPrefix, h.serveRaft)
-	h.ServeMux.HandleFunc(raftPrefix+"/version", h.serveVersion)
-	h.ServeMux.HandleFunc(raftPrefix+"/version/", h.serveVersionCheck)
-	return h
-}
-
-func (h *raftHandler) start() {
-	h.mu.Lock()
-	h.serving = true
-	h.mu.Unlock()
-}
-
-func (h *raftHandler) stop() {
-	h.mu.Lock()
-	h.serving = false
-	h.mu.Unlock()
-}
-
-func (h *raftHandler) serveRaft(w http.ResponseWriter, r *http.Request) {
-	h.mu.RLock()
-	serving := h.serving
-	h.mu.RUnlock()
-	if !serving {
-		http.Error(w, "404 page not found", http.StatusNotFound)
-		return
-	}
-
-	msg := new(raft.Message)
-	if err := json.NewDecoder(r.Body).Decode(msg); err != nil {
-		log.Printf("raftHandler.serve decodeErr=\"%v\"\n", err)
-		return
-	}
-	if msg.IsMsgApp() {
-		h.serverStats.RecvAppendReq(fmt.Sprint(msg.From), int(r.ContentLength))
-	}
-
-	select {
-	case h.recv <- msg:
-	default:
-		log.Printf("raftHandler.serve pushErr=\"recv channel is full\"\n")
-		// drop the incoming package at network layer if the upper layer
-		// cannot consume them in time.
-		// TODO(xiangli): not return 200.
-	}
-	return
-}
-
-func (h *raftHandler) serveCfg(w http.ResponseWriter, r *http.Request) {
-	h.mu.RLock()
-	serving := h.serving
-	h.mu.RUnlock()
-	if !serving {
-		http.Error(w, "404 page not found", http.StatusNotFound)
-		return
-	}
-
-	id, err := strconv.ParseInt(r.URL.Path[len("/raft/cfg/"):], 10, 64)
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusBadRequest)
-		return
-	}
-	p, err := h.peerGetter.peer(id)
-	if err == nil {
-		w.Write([]byte(p.url))
-		return
-	}
-	http.Error(w, err.Error(), http.StatusNotFound)
-}
-
-func (h *raftHandler) serveVersion(w http.ResponseWriter, req *http.Request) {
-	w.Write([]byte(strconv.Itoa(h.storeVersion)))
-}
-
-func (h *raftHandler) serveVersionCheck(w http.ResponseWriter, req *http.Request) {
-	var version int
-	n, err := fmt.Sscanf(req.URL.Path, raftPrefix+"/version/%d/check", &version)
-	if err != nil || n != 1 {
-		http.Error(w, "error version check format: "+req.URL.Path, http.StatusBadRequest)
-		return
-	}
-	if version < store.MinVersion() || version > store.MaxVersion() {
-		w.WriteHeader(http.StatusForbidden)
-		return
-	}
-}

+ 0 - 83
etcdserver/raft_server_stats.go

@@ -1,83 +0,0 @@
-package etcdserver
-
-import (
-	"sync"
-	"time"
-)
-
-type raftServerStats struct {
-	Name      string    `json:"name"`
-	State     string    `json:"state"`
-	StartTime time.Time `json:"startTime"`
-
-	LeaderInfo struct {
-		Name      string    `json:"leader"`
-		Uptime    string    `json:"uptime"`
-		StartTime time.Time `json:"startTime"`
-	} `json:"leaderInfo"`
-
-	RecvAppendRequestCnt uint64  `json:"recvAppendRequestCnt,"`
-	RecvingPkgRate       float64 `json:"recvPkgRate,omitempty"`
-	RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"`
-
-	SendAppendRequestCnt uint64  `json:"sendAppendRequestCnt"`
-	SendingPkgRate       float64 `json:"sendPkgRate,omitempty"`
-	SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`
-
-	sendRateQueue *statsQueue
-	recvRateQueue *statsQueue
-
-	sync.Mutex
-}
-
-func NewRaftServerStats(name string) *raftServerStats {
-	stats := &raftServerStats{
-		Name:      name,
-		StartTime: time.Now(),
-		sendRateQueue: &statsQueue{
-			back: -1,
-		},
-		recvRateQueue: &statsQueue{
-			back: -1,
-		},
-	}
-	stats.LeaderInfo.StartTime = time.Now()
-	return stats
-}
-
-func (ss *raftServerStats) Reset() {
-	name := ss.Name
-	ss = NewRaftServerStats(name)
-	return
-}
-
-func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) {
-	ss.Lock()
-	defer ss.Unlock()
-
-	ss.State = stateFollower
-	if leaderName != ss.LeaderInfo.Name {
-		ss.LeaderInfo.Name = leaderName
-		ss.LeaderInfo.StartTime = time.Now()
-	}
-
-	ss.recvRateQueue.Insert(NewPackageStats(time.Now(), pkgSize))
-	ss.RecvAppendRequestCnt++
-}
-
-func (ss *raftServerStats) SendAppendReq(pkgSize int) {
-	ss.Lock()
-	defer ss.Unlock()
-
-	now := time.Now()
-
-	if ss.State != stateLeader {
-		ss.State = stateLeader
-		ss.LeaderInfo.Name = ss.Name
-		ss.LeaderInfo.StartTime = now
-	}
-
-	ss.sendRateQueue.Insert(NewPackageStats(now, pkgSize))
-
-	ss.SendAppendRequestCnt++
-}

+ 1 - 1
etcdserver2/server.go → etcdserver/server.go

@@ -5,7 +5,7 @@ import (
 	"time"
 
 	"code.google.com/p/go.net/context"
-	pb "github.com/coreos/etcd/etcdserver2/etcdserverpb"
+	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/raft"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/store"

+ 2 - 1
etcdserver2/server_test.go → etcdserver/server_test.go

@@ -5,9 +5,10 @@ import (
 	"reflect"
 	"testing"
 	"time"
+
 	"code.google.com/p/go.net/context"
 
-	pb "github.com/coreos/etcd/etcdserver2/etcdserverpb"
+	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/raft"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/store"

+ 0 - 137
etcdserver/standby.go

@@ -1,137 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-	"strconv"
-	"sync"
-	"time"
-
-	"github.com/coreos/etcd/conf"
-)
-
-var (
-	noneId int64 = -1
-)
-
-type standby struct {
-	client  *v2client
-	peerHub *peerHub
-
-	leader      int64
-	leaderAddr  string
-	mu          sync.RWMutex
-	clusterConf *conf.ClusterConfig
-
-	*http.ServeMux
-}
-
-func newStandby(client *v2client, peerHub *peerHub) *standby {
-	s := &standby{
-		client:  client,
-		peerHub: peerHub,
-
-		leader:      noneId,
-		leaderAddr:  "",
-		clusterConf: conf.NewClusterConfig(),
-
-		ServeMux: http.NewServeMux(),
-	}
-	s.Handle("/", handlerErr(s.serveRedirect))
-	return s
-}
-
-func (s *standby) run(stop chan struct{}) {
-	syncDuration := time.Millisecond * 100
-	nodes := s.peerHub.getSeeds()
-	for {
-		select {
-		case <-time.After(syncDuration):
-		case <-stop:
-			log.Printf("standby.stop\n")
-			return
-		}
-
-		if update, err := s.syncCluster(nodes); err != nil {
-			log.Printf("standby.run syncErr=\"%v\"", err)
-			continue
-		} else {
-			nodes = update
-		}
-		syncDuration = time.Duration(s.clusterConf.SyncInterval * float64(time.Second))
-		if s.clusterConf.ActiveSize <= len(nodes) {
-			continue
-		}
-		log.Printf("standby.end\n")
-		return
-	}
-}
-
-func (s *standby) leaderInfo() (int64, string) {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-	return s.leader, s.leaderAddr
-}
-
-func (s *standby) setLeaderInfo(leader int64, leaderAddr string) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	s.leader, s.leaderAddr = leader, leaderAddr
-}
-
-func (s *standby) serveRedirect(w http.ResponseWriter, r *http.Request) error {
-	leader, leaderAddr := s.leaderInfo()
-	if leader == noneId {
-		return fmt.Errorf("no leader in the cluster")
-	}
-	redirectAddr, err := buildRedirectURL(leaderAddr, r.URL)
-	if err != nil {
-		return err
-	}
-	http.Redirect(w, r, redirectAddr, http.StatusTemporaryRedirect)
-	return nil
-}
-
-func (s *standby) syncCluster(nodes map[string]bool) (map[string]bool, error) {
-	for node := range nodes {
-		machines, err := s.client.GetMachines(node)
-		if err != nil {
-			continue
-		}
-		cfg, err := s.client.GetClusterConfig(node)
-		if err != nil {
-			continue
-		}
-		nn := make(map[string]bool)
-		for _, machine := range machines {
-			nn[machine.PeerURL] = true
-			if machine.State == stateLeader {
-				id, err := strconv.ParseInt(machine.Name, 0, 64)
-				if err != nil {
-					return nil, err
-				}
-				s.setLeaderInfo(id, machine.PeerURL)
-			}
-		}
-		s.clusterConf = cfg
-		return nn, nil
-	}
-	return nil, fmt.Errorf("unreachable cluster")
-}

+ 0 - 89
etcdserver/stats_queue.go

@@ -1,89 +0,0 @@
-package etcdserver
-
-import (
-	"sync"
-	"time"
-)
-
-const (
-	queueCapacity = 200
-)
-
-type statsQueue struct {
-	items        [queueCapacity]*packageStats
-	size         int
-	front        int
-	back         int
-	totalPkgSize int
-	rwl          sync.RWMutex
-}
-
-func (q *statsQueue) Len() int {
-	return q.size
-}
-
-func (q *statsQueue) PkgSize() int {
-	return q.totalPkgSize
-}
-
-// FrontAndBack gets the front and back elements in the queue
-// We must grab front and back together with the protection of the lock
-func (q *statsQueue) frontAndBack() (*packageStats, *packageStats) {
-	q.rwl.RLock()
-	defer q.rwl.RUnlock()
-	if q.size != 0 {
-		return q.items[q.front], q.items[q.back]
-	}
-	return nil, nil
-}
-
-// Insert function insert a packageStats into the queue and update the records
-func (q *statsQueue) Insert(p *packageStats) {
-	q.rwl.Lock()
-	defer q.rwl.Unlock()
-
-	q.back = (q.back + 1) % queueCapacity
-
-	if q.size == queueCapacity { //dequeue
-		q.totalPkgSize -= q.items[q.front].size
-		q.front = (q.back + 1) % queueCapacity
-	} else {
-		q.size++
-	}
-
-	q.items[q.back] = p
-	q.totalPkgSize += q.items[q.back].size
-
-}
-
-// Rate function returns the package rate and byte rate
-func (q *statsQueue) Rate() (float64, float64) {
-	front, back := q.frontAndBack()
-
-	if front == nil || back == nil {
-		return 0, 0
-	}
-
-	if time.Now().Sub(back.Time()) > time.Second {
-		q.Clear()
-		return 0, 0
-	}
-
-	sampleDuration := back.Time().Sub(front.Time())
-
-	pr := float64(q.Len()) / float64(sampleDuration) * float64(time.Second)
-
-	br := float64(q.PkgSize()) / float64(sampleDuration) * float64(time.Second)
-
-	return pr, br
-}
-
-// Clear function clear up the statsQueue
-func (q *statsQueue) Clear() {
-	q.rwl.Lock()
-	defer q.rwl.Unlock()
-	q.back = -1
-	q.front = 0
-	q.size = 0
-	q.totalPkgSize = 0
-}

+ 0 - 182
etcdserver/v2_admin.go

@@ -1,182 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"net/url"
-	"path/filepath"
-	"strconv"
-	"strings"
-
-	"github.com/coreos/etcd/conf"
-	"github.com/coreos/etcd/store"
-)
-
-const (
-	stateFollower  = "follower"
-	stateCandidate = "candidate"
-	stateLeader    = "leader"
-)
-
-// machineMessage represents information about a peer or standby in the registry.
-type machineMessage struct {
-	Name      string `json:"name"`
-	State     string `json:"state"`
-	ClientURL string `json:"clientURL"`
-	PeerURL   string `json:"peerURL"`
-}
-
-type context struct {
-	MinVersion int    `json:"minVersion"`
-	MaxVersion int    `json:"maxVersion"`
-	ClientURL  string `json:"clientURL"`
-	PeerURL    string `json:"peerURL"`
-}
-
-func (p *participant) serveAdminConfig(w http.ResponseWriter, r *http.Request) error {
-	switch r.Method {
-	case "GET":
-	case "PUT":
-		if !p.node.IsLeader() {
-			return p.redirect(w, r, p.node.Leader())
-		}
-		c := p.clusterConfig()
-		if err := json.NewDecoder(r.Body).Decode(c); err != nil {
-			return err
-		}
-		c.Sanitize()
-		if err := p.setClusterConfig(c); err != nil {
-			return err
-		}
-	default:
-		return allow(w, "GET", "PUT")
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-	json.NewEncoder(w).Encode(p.clusterConfig())
-	return nil
-}
-
-func (p *participant) serveAdminMachines(w http.ResponseWriter, r *http.Request) error {
-	name := strings.TrimPrefix(r.URL.Path, v2adminMachinesPrefix)
-	switch r.Method {
-	case "GET":
-		var info interface{}
-		var err error
-		if name != "" {
-			info, err = p.machineMessage(name)
-		} else {
-			info, err = p.allMachineMessages()
-		}
-		if err != nil {
-			return err
-		}
-		w.Header().Set("Content-Type", "application/json")
-		json.NewEncoder(w).Encode(info)
-	case "PUT":
-		if !p.node.IsLeader() {
-			return p.redirect(w, r, p.node.Leader())
-		}
-		id, err := strconv.ParseInt(name, 0, 64)
-		if err != nil {
-			return err
-		}
-		info := &context{}
-		if err := json.NewDecoder(r.Body).Decode(info); err != nil {
-			return err
-		}
-		return p.add(id, info.PeerURL, info.ClientURL)
-	case "DELETE":
-		if !p.node.IsLeader() {
-			return p.redirect(w, r, p.node.Leader())
-		}
-		id, err := strconv.ParseInt(name, 0, 64)
-		if err != nil {
-			return err
-		}
-		return p.remove(id)
-	default:
-		return allow(w, "GET", "PUT", "DELETE")
-	}
-	return nil
-}
-
-func (p *participant) clusterConfig() *conf.ClusterConfig {
-	c := conf.NewClusterConfig()
-	// This is used for backward compatibility because it doesn't
-	// set cluster config in older version.
-	if e, err := p.Store.Get(v2configKVPrefix, false, false); err == nil {
-		json.Unmarshal([]byte(*e.Node.Value), c)
-	}
-	return c
-}
-
-func (p *participant) setClusterConfig(c *conf.ClusterConfig) error {
-	b, err := json.Marshal(c)
-	if err != nil {
-		return err
-	}
-	if _, err := p.Set(v2configKVPrefix, false, string(b), store.Permanent); err != nil {
-		return err
-	}
-	return nil
-}
-
-// machineMessage returns the machineMessage of the given name
-func (p *participant) machineMessage(name string) (*machineMessage, error) {
-	pp := filepath.Join(v2machineKVPrefix, name)
-	e, err := p.Store.Get(pp, false, false)
-	if err != nil {
-		return nil, err
-	}
-	lead := fmt.Sprint(p.node.Leader())
-	return newMachineMessage(e.Node, lead), nil
-}
-
-func (p *participant) allMachineMessages() ([]*machineMessage, error) {
-	e, err := p.Store.Get(v2machineKVPrefix, false, false)
-	if err != nil {
-		return nil, err
-	}
-	lead := fmt.Sprint(p.node.Leader())
-	ms := make([]*machineMessage, len(e.Node.Nodes))
-	for i, n := range e.Node.Nodes {
-		ms[i] = newMachineMessage(n, lead)
-	}
-	return ms, nil
-}
-
-func newMachineMessage(n *store.NodeExtern, lead string) *machineMessage {
-	_, name := filepath.Split(n.Key)
-	q, err := url.ParseQuery(*n.Value)
-	if err != nil {
-		panic("fail to parse the info for machine " + name)
-	}
-	m := &machineMessage{
-		Name:      name,
-		State:     stateFollower,
-		ClientURL: q["etcd"][0],
-		PeerURL:   q["raft"][0],
-	}
-	if name == lead {
-		m.State = stateLeader
-	}
-	return m
-}

+ 0 - 99
etcdserver/v2_apply.go

@@ -1,99 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"log"
-	"time"
-
-	"github.com/coreos/etcd/raft"
-	"github.com/coreos/etcd/store"
-)
-
-func (p *participant) v2apply(index int64, ent raft.Entry) {
-	var ret interface{}
-	var e *store.Event
-	var err error
-
-	var cmd Cmd
-	if err := cmd.Unmarshal(ent.Data); err != nil {
-		log.Printf("id=%x participant.store.apply decodeErr=\"%v\"\n", p.id, err)
-		return
-	}
-
-	switch cmd.Type {
-	case stset:
-		e, err = p.Store.Set(cmd.Key, *cmd.Dir, *cmd.Value, mustUnmarshalTime(cmd.Time))
-	case stupdate:
-		e, err = p.Store.Update(cmd.Key, *cmd.Value, mustUnmarshalTime(cmd.Time))
-	case stcreate:
-		e, err = p.Store.Create(cmd.Key, *cmd.Dir, *cmd.Value, *cmd.Unique, mustUnmarshalTime(cmd.Time))
-	case stdelete:
-		e, err = p.Store.Delete(cmd.Key, *cmd.Dir, *cmd.Recursive)
-	case stcad:
-		e, err = p.Store.CompareAndDelete(cmd.Key, *cmd.PrevValue, *cmd.PrevIndex)
-	case stcas:
-		e, err = p.Store.CompareAndSwap(cmd.Key, *cmd.PrevValue, *cmd.PrevIndex, *cmd.Value, mustUnmarshalTime(cmd.Time))
-	case stqget:
-		e, err = p.Store.Get(cmd.Key, *cmd.Recursive, *cmd.Sorted)
-	case stsync:
-		p.Store.DeleteExpiredKeys(mustUnmarshalTime(cmd.Time))
-		return
-	default:
-		log.Printf("id=%x participant.store.apply err=\"unexpected command type %s\"\n", p.id, cmd.Type)
-	}
-
-	if ent.Term > p.node.term {
-		p.node.term = ent.Term
-		for k, v := range p.node.result {
-			if k.term < p.node.term {
-				v <- fmt.Errorf("proposal lost due to leader election")
-				delete(p.node.result, k)
-			}
-		}
-	}
-
-	w := wait{index, ent.Term}
-	if p.node.result[w] == nil {
-		return
-	}
-
-	if err != nil {
-		ret = err
-	} else {
-		ret = e
-	}
-	p.node.result[w] <- ret
-	delete(p.node.result, w)
-}
-
-func mustMarshalTime(t *time.Time) []byte {
-	b, err := t.MarshalBinary()
-	if err != nil {
-		panic(err)
-	}
-	return b
-}
-
-func mustUnmarshalTime(b []byte) time.Time {
-	var time time.Time
-	if err := time.UnmarshalBinary(b); err != nil {
-		panic(err)
-	}
-	return time
-}

+ 0 - 254
etcdserver/v2_client.go

@@ -1,254 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"bytes"
-	"crypto/tls"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"strconv"
-	"strings"
-	"sync"
-
-	"github.com/coreos/etcd/conf"
-	etcdErr "github.com/coreos/etcd/error"
-)
-
-// v2client sends various requests using HTTP API.
-// It is different from raft communication, and doesn't record anything in the log.
-// The argument url is required to contain scheme and host only, and
-// there is no trailing slash in it.
-// Public functions return "etcd/error".Error intentionally to figure out
-// etcd error code easily.
-type v2client struct {
-	stopped bool
-	mu      sync.RWMutex
-
-	http.Client
-	wg sync.WaitGroup
-}
-
-func newClient(tc *tls.Config) *v2client {
-	tr := new(http.Transport)
-	tr.TLSClientConfig = tc
-	return &v2client{Client: http.Client{Transport: tr}}
-}
-
-func (c *v2client) CloseConnections() {
-	c.stop()
-	c.wg.Wait()
-	tr := c.Transport.(*http.Transport)
-	tr.CloseIdleConnections()
-}
-
-// CheckVersion returns true when the version check on the server returns 200.
-func (c *v2client) CheckVersion(url string, version int) (bool, *etcdErr.Error) {
-	if c.runOne() == false {
-		return false, clientError(errors.New("v2_client is stopped"))
-	}
-	defer c.finishOne()
-
-	resp, err := c.Get(url + fmt.Sprintf("/version/%d/check", version))
-	if err != nil {
-		return false, clientError(err)
-	}
-	c.readBody(resp.Body)
-
-	return resp.StatusCode == 200, nil
-}
-
-// GetVersion fetches the peer version of a cluster.
-func (c *v2client) GetVersion(url string) (int, *etcdErr.Error) {
-	if c.runOne() == false {
-		return 0, clientError(errors.New("v2_client is stopped"))
-	}
-	defer c.finishOne()
-
-	resp, err := c.Get(url + "/version")
-	if err != nil {
-		return 0, clientError(err)
-	}
-
-	body, err := c.readBody(resp.Body)
-	if err != nil {
-		return 0, clientError(err)
-	}
-
-	// Parse version number.
-	version, err := strconv.Atoi(string(body))
-	if err != nil {
-		return 0, clientError(err)
-	}
-	return version, nil
-}
-
-func (c *v2client) GetMachines(url string) ([]*machineMessage, *etcdErr.Error) {
-	if c.runOne() == false {
-		return nil, clientError(errors.New("v2_client is stopped"))
-	}
-	defer c.finishOne()
-
-	resp, err := c.Get(url + "/v2/admin/machines/")
-	if err != nil {
-		return nil, clientError(err)
-	}
-	if resp.StatusCode != http.StatusOK {
-		return nil, c.readErrorBody(resp.Body)
-	}
-
-	msgs := new([]*machineMessage)
-	if uerr := c.readJSONBody(resp.Body, msgs); uerr != nil {
-		return nil, uerr
-	}
-	return *msgs, nil
-}
-
-func (c *v2client) GetClusterConfig(url string) (*conf.ClusterConfig, *etcdErr.Error) {
-	if c.runOne() == false {
-		return nil, clientError(errors.New("v2_client is stopped"))
-	}
-	defer c.finishOne()
-
-	resp, err := c.Get(url + "/v2/admin/config")
-	if err != nil {
-		return nil, clientError(err)
-	}
-	if resp.StatusCode != http.StatusOK {
-		return nil, c.readErrorBody(resp.Body)
-	}
-
-	cfg := new(conf.ClusterConfig)
-	if uerr := c.readJSONBody(resp.Body, cfg); uerr != nil {
-		return nil, uerr
-	}
-	return cfg, nil
-}
-
-// AddMachine adds machine to the cluster.
-// The first return value is the commit index of join command.
-func (c *v2client) AddMachine(url string, name string, info *context) *etcdErr.Error {
-	if c.runOne() == false {
-		return clientError(errors.New("v2_client is stopped"))
-	}
-	defer c.finishOne()
-
-	b, _ := json.Marshal(info)
-	url = url + "/v2/admin/machines/" + name
-
-	resp, err := c.put(url, b)
-	if err != nil {
-		return clientError(err)
-	}
-	if resp.StatusCode != http.StatusOK {
-		return c.readErrorBody(resp.Body)
-	}
-	c.readBody(resp.Body)
-	return nil
-}
-
-func (c *v2client) readErrorBody(body io.ReadCloser) *etcdErr.Error {
-	b, err := c.readBody(body)
-	if err != nil {
-		return clientError(err)
-	}
-	uerr := &etcdErr.Error{}
-	if err := json.Unmarshal(b, uerr); err != nil {
-		str := strings.TrimSpace(string(b))
-		return etcdErr.NewError(etcdErr.EcodeClientInternal, str, 0)
-	}
-	return nil
-}
-
-func (c *v2client) readJSONBody(body io.ReadCloser, val interface{}) *etcdErr.Error {
-	if err := json.NewDecoder(body).Decode(val); err != nil {
-		return clientError(err)
-	}
-	c.readBody(body)
-	return nil
-}
-
-func (c *v2client) readBody(body io.ReadCloser) ([]byte, error) {
-	b, err := ioutil.ReadAll(body)
-	body.Close()
-	return b, err
-}
-
-// put sends server side PUT request.
-// It always follows redirects instead of stopping according to RFC 2616.
-func (c *v2client) put(urlStr string, body []byte) (*http.Response, error) {
-	return c.doAlwaysFollowingRedirects("PUT", urlStr, body)
-}
-
-func (c *v2client) doAlwaysFollowingRedirects(method string, urlStr string, body []byte) (resp *http.Response, err error) {
-	var req *http.Request
-
-	for redirect := 0; redirect < 10; redirect++ {
-		req, err = http.NewRequest(method, urlStr, bytes.NewBuffer(body))
-		if err != nil {
-			return
-		}
-
-		if resp, err = c.Do(req); err != nil {
-			if resp != nil {
-				resp.Body.Close()
-			}
-			return
-		}
-
-		if resp.StatusCode == http.StatusMovedPermanently || resp.StatusCode == http.StatusTemporaryRedirect {
-			resp.Body.Close()
-			if urlStr = resp.Header.Get("Location"); urlStr == "" {
-				err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
-				return
-			}
-			continue
-		}
-		return
-	}
-
-	err = errors.New("stopped after 10 redirects")
-	return
-}
-
-func (c *v2client) runOne() bool {
-	c.mu.RLock()
-	defer c.mu.RUnlock()
-	if c.stopped {
-		return false
-	}
-	c.wg.Add(1)
-	return true
-}
-
-func (c *v2client) finishOne() {
-	c.wg.Done()
-}
-
-func (c *v2client) stop() {
-	c.mu.Lock()
-	c.stopped = true
-	c.mu.Unlock()
-}
-
-func clientError(err error) *etcdErr.Error {
-	return etcdErr.NewError(etcdErr.EcodeClientInternal, err.Error(), 0)
-}

+ 0 - 174
etcdserver/v2_http.go

@@ -1,174 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"log"
-	"net/http"
-	"net/url"
-	"strings"
-	"time"
-
-	etcdErr "github.com/coreos/etcd/error"
-)
-
-func (p *participant) serveValue(w http.ResponseWriter, r *http.Request) error {
-	switch r.Method {
-	case "GET":
-		return p.GetHandler(w, r)
-	case "HEAD":
-		w = &HEADResponseWriter{w}
-		return p.GetHandler(w, r)
-	case "PUT":
-		return p.PutHandler(w, r)
-	case "POST":
-		return p.PostHandler(w, r)
-	case "DELETE":
-		return p.DeleteHandler(w, r)
-	}
-	return allow(w, "GET", "PUT", "POST", "DELETE", "HEAD")
-}
-
-func (p *participant) serveMachines(w http.ResponseWriter, r *http.Request) error {
-	if r.Method != "GET" {
-		return allow(w, "GET")
-	}
-	v, err := p.Store.Get(v2machineKVPrefix, false, false)
-	if err != nil {
-		panic(err)
-	}
-	ns := make([]string, len(v.Node.Nodes))
-	for i, n := range v.Node.Nodes {
-		m, err := url.ParseQuery(*n.Value)
-		if err != nil {
-			continue
-		}
-		ns[i] = m["etcd"][0]
-	}
-	w.Write([]byte(strings.Join(ns, ",")))
-	return nil
-}
-
-func (p *participant) serveLeader(w http.ResponseWriter, r *http.Request) error {
-	if r.Method != "GET" {
-		return allow(w, "GET")
-	}
-	if p, ok := p.peerHub.peers[p.node.Leader()]; ok {
-		w.Write([]byte(p.url))
-		return nil
-	}
-	return fmt.Errorf("no leader")
-}
-
-func (p *participant) serveSelfStats(w http.ResponseWriter, req *http.Request) error {
-	p.serverStats.LeaderInfo.Uptime = time.Now().Sub(p.serverStats.LeaderInfo.StartTime).String()
-
-	if p.node.IsLeader() {
-		p.serverStats.LeaderInfo.Name = fmt.Sprint(p.id)
-	}
-
-	queue := p.serverStats.sendRateQueue
-	p.serverStats.SendingPkgRate, p.serverStats.SendingBandwidthRate = queue.Rate()
-
-	queue = p.serverStats.recvRateQueue
-	p.serverStats.RecvingPkgRate, p.serverStats.RecvingBandwidthRate = queue.Rate()
-
-	return json.NewEncoder(w).Encode(p.serverStats)
-}
-
-func (p *participant) serveLeaderStats(w http.ResponseWriter, req *http.Request) error {
-	if !p.node.IsLeader() {
-		return p.redirect(w, req, p.node.Leader())
-	}
-	w.Header().Set("Content-Type", "application/json")
-	return json.NewEncoder(w).Encode(p.peerHub.followersStats)
-}
-
-func (p *participant) serveStoreStats(w http.ResponseWriter, req *http.Request) error {
-	w.Header().Set("Content-Type", "application/json")
-	w.Write(p.Store.JsonStats())
-	return nil
-}
-
-type handlerErr func(w http.ResponseWriter, r *http.Request) error
-
-func (eh handlerErr) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	err := eh(w, r)
-	if err == nil {
-		return
-	}
-
-	if r.Method == "HEAD" {
-		w = &HEADResponseWriter{w}
-	}
-
-	if etcdErr, ok := err.(*etcdErr.Error); ok {
-		w.Header().Set("Content-Type", "application/json")
-		etcdErr.Write(w)
-		return
-	}
-
-	log.Printf("HTTP.serve: req=%s err=\"%v\"\n", r.URL, err)
-	http.Error(w, "Internal Server Error", http.StatusInternalServerError)
-}
-
-func allow(w http.ResponseWriter, m ...string) error {
-	w.Header().Set("Allow", strings.Join(m, ","))
-	return nil
-}
-
-type HEADResponseWriter struct {
-	http.ResponseWriter
-}
-
-func (w *HEADResponseWriter) Write([]byte) (int, error) {
-	return 0, nil
-}
-
-func (p *participant) redirect(w http.ResponseWriter, r *http.Request, id int64) error {
-	e, err := p.Store.Get(fmt.Sprintf("%v/%d", v2machineKVPrefix, p.node.Leader()), false, false)
-	if err != nil {
-		return fmt.Errorf("redirect cannot find node %d", id)
-	}
-
-	m, err := url.ParseQuery(*e.Node.Value)
-	if err != nil {
-		return fmt.Errorf("failed to parse node entry: %s", *e.Node.Value)
-	}
-
-	redirectAddr, err := buildRedirectURL(m["etcd"][0], r.URL)
-	if err != nil {
-		return err
-	}
-
-	http.Redirect(w, r, redirectAddr, http.StatusTemporaryRedirect)
-	return nil
-}
-
-func buildRedirectURL(redirectAddr string, originalURL *url.URL) (string, error) {
-	redirectURL, err := url.Parse(redirectAddr)
-	if err != nil {
-		return "", fmt.Errorf("cannot parse url: %v", err)
-	}
-
-	redirectURL.Path = originalURL.Path
-	redirectURL.RawQuery = originalURL.RawQuery
-	redirectURL.Fragment = originalURL.Fragment
-	return redirectURL.String(), nil
-}

+ 0 - 82
etcdserver/v2_http_delete.go

@@ -1,82 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"net/http"
-	"strconv"
-
-	etcdErr "github.com/coreos/etcd/error"
-)
-
-func (p *participant) DeleteHandler(w http.ResponseWriter, req *http.Request) error {
-	if !p.node.IsLeader() {
-		return p.redirect(w, req, p.node.Leader())
-	}
-
-	key := req.URL.Path[len("/v2/keys"):]
-
-	recursive := (req.FormValue("recursive") == "true")
-	dir := (req.FormValue("dir") == "true")
-
-	req.ParseForm()
-	_, valueOk := req.Form["prevValue"]
-	_, indexOk := req.Form["prevIndex"]
-
-	if !valueOk && !indexOk {
-		return p.serveDelete(w, req, key, dir, recursive)
-	}
-
-	var err error
-	prevIndex := uint64(0)
-	prevValue := req.Form.Get("prevValue")
-
-	if indexOk {
-		prevIndexStr := req.Form.Get("prevIndex")
-		prevIndex, err = strconv.ParseUint(prevIndexStr, 10, 64)
-
-		// bad previous index
-		if err != nil {
-			return etcdErr.NewError(etcdErr.EcodeIndexNaN, "CompareAndDelete", p.Store.Index())
-		}
-	}
-
-	if valueOk {
-		if prevValue == "" {
-			return etcdErr.NewError(etcdErr.EcodePrevValueRequired, "CompareAndDelete", p.Store.Index())
-		}
-	}
-	return p.serveCAD(w, req, key, prevValue, prevIndex)
-}
-
-func (p *participant) serveDelete(w http.ResponseWriter, req *http.Request, key string, dir, recursive bool) error {
-	ret, err := p.Delete(key, dir, recursive)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}
-
-func (p *participant) serveCAD(w http.ResponseWriter, req *http.Request, key string, prevValue string, prevIndex uint64) error {
-	ret, err := p.CAD(key, prevValue, prevIndex)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}

+ 0 - 293
etcdserver/v2_http_endpoint_test.go

@@ -1,293 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"reflect"
-	"sort"
-	"strings"
-	"testing"
-
-	"github.com/coreos/etcd/conf"
-	"github.com/coreos/etcd/store"
-)
-
-func TestMachinesEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 3}
-	cl.Start()
-
-	w := make([]string, cl.Size)
-	for i := 0; i < cl.Size; i++ {
-		w[i] = cl.URL(i)
-	}
-
-	for i := 0; i < cl.Size; i++ {
-		r, err := http.Get(cl.URL(i) + v2machinePrefix)
-		if err != nil {
-			t.Errorf("%v", err)
-			break
-		}
-		b, err := ioutil.ReadAll(r.Body)
-		r.Body.Close()
-		if err != nil {
-			t.Errorf("%v", err)
-			break
-		}
-		g := strings.Split(string(b), ",")
-		sort.Strings(g)
-		if !reflect.DeepEqual(w, g) {
-			t.Errorf("machines = %v, want %v", g, w)
-		}
-	}
-
-	cl.Destroy()
-}
-
-func TestLeaderEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 3}
-	cl.Start()
-
-	us := make([]string, cl.Size)
-	for i := 0; i < cl.Size; i++ {
-		us[i] = cl.URL(i)
-	}
-	// todo(xiangli) change this to raft port...
-	w := cl.URL(0) + "/raft"
-
-	for i := 0; i < cl.Size; i++ {
-		r, err := http.Get(cl.URL(i) + v2LeaderPrefix)
-		if err != nil {
-			t.Errorf("%v", err)
-			break
-		}
-		b, err := ioutil.ReadAll(r.Body)
-		r.Body.Close()
-		if err != nil {
-			t.Errorf("%v", err)
-			break
-		}
-		if string(b) != w {
-			t.Errorf("leader = %v, want %v", string(b), w)
-		}
-	}
-
-	cl.Destroy()
-}
-
-func TestStoreStatsEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 1}
-	cl.Start()
-
-	resp, err := http.Get(cl.URL(0) + v2StoreStatsPrefix)
-	if err != nil {
-		t.Errorf("%v", err)
-	}
-	stats := new(store.Stats)
-	d := json.NewDecoder(resp.Body)
-	err = d.Decode(stats)
-	resp.Body.Close()
-	if err != nil {
-		t.Errorf("%v", err)
-	}
-
-	if stats.SetSuccess != 1 {
-		t.Errorf("setSuccess = %d, want 1", stats.SetSuccess)
-	}
-
-	cl.Destroy()
-}
-
-func TestGetAdminConfigEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 1}
-	cl.Start()
-
-	r, err := http.Get(cl.URL(0) + v2adminConfigPrefix)
-	if err != nil {
-		t.Errorf("%v", err)
-	}
-	if g := r.StatusCode; g != 200 {
-		t.Errorf("status = %d, want %d", g, 200)
-	}
-	if g := r.Header.Get("Content-Type"); g != "application/json" {
-		t.Errorf("ContentType = %s, want application/json", g)
-	}
-
-	cfg := new(conf.ClusterConfig)
-	err = json.NewDecoder(r.Body).Decode(cfg)
-	r.Body.Close()
-	if err != nil {
-		t.Errorf("%v", err)
-	}
-	w := conf.NewClusterConfig()
-	if !reflect.DeepEqual(cfg, w) {
-		t.Errorf("config = %+v, want %+v", cfg, w)
-	}
-
-	cl.Destroy()
-}
-
-func TestPutAdminConfigEndPoint(t *testing.T) {
-	tests := []struct {
-		c, wc string
-	}{
-		{
-			`{"activeSize":1,"removeDelay":1,"syncInterval":1}`,
-			`{"activeSize":3,"removeDelay":2,"syncInterval":1}`,
-		},
-		{
-			`{"activeSize":5,"removeDelay":20.5,"syncInterval":1.5}`,
-			`{"activeSize":5,"removeDelay":20.5,"syncInterval":1.5}`,
-		},
-		{
-			`{"activeSize":5 ,  "removeDelay":20 ,  "syncInterval": 2 }`,
-			`{"activeSize":5,"removeDelay":20,"syncInterval":2}`,
-		},
-		{
-			`{"activeSize":3, "removeDelay":60}`,
-			`{"activeSize":3,"removeDelay":60,"syncInterval":5}`,
-		},
-	}
-
-	for i, tt := range tests {
-		cl := &testCluster{Size: 1}
-		cl.Start()
-		index := cl.Participant(0).Index()
-
-		r, err := NewTestClient().Put(cl.URL(0)+v2adminConfigPrefix, "application/json", bytes.NewBufferString(tt.c))
-		if err != nil {
-			t.Fatalf("%v", err)
-		}
-		b, err := ioutil.ReadAll(r.Body)
-		r.Body.Close()
-		if err != nil {
-			t.Fatalf("%v", err)
-		}
-		if wbody := append([]byte(tt.wc), '\n'); !reflect.DeepEqual(b, wbody) {
-			t.Errorf("#%d: put result = %s, want %s", i, b, wbody)
-		}
-
-		w, err := cl.Participant(0).Watch(v2configKVPrefix, false, false, index)
-		if err != nil {
-			t.Errorf("%v", err)
-			continue
-		}
-		e := <-w.EventChan
-		if g := *e.Node.Value; g != tt.wc {
-			t.Errorf("#%d: %s = %s, want %s", i, v2configKVPrefix, g, tt.wc)
-		}
-
-		cl.Destroy()
-	}
-}
-
-func TestGetAdminMachineEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 3}
-	cl.Start()
-
-	for i := 0; i < cl.Size; i++ {
-		for j := 0; j < cl.Size; j++ {
-			name := fmt.Sprint(cl.Id(i))
-			r, err := http.Get(cl.URL(j) + v2adminMachinesPrefix + name)
-			if err != nil {
-				t.Errorf("%v", err)
-				continue
-			}
-			if g := r.StatusCode; g != 200 {
-				t.Errorf("#%d on %d: status = %d, want %d", i, j, g, 200)
-			}
-			if g := r.Header.Get("Content-Type"); g != "application/json" {
-				t.Errorf("#%d on %d: ContentType = %s, want application/json", i, j, g)
-			}
-
-			m := new(machineMessage)
-			err = json.NewDecoder(r.Body).Decode(m)
-			r.Body.Close()
-			if err != nil {
-				t.Errorf("%v", err)
-				continue
-			}
-			wm := &machineMessage{
-				Name:      name,
-				State:     stateFollower,
-				ClientURL: cl.URL(i),
-				PeerURL:   cl.URL(i),
-			}
-			if i == 0 {
-				wm.State = stateLeader
-			}
-			if !reflect.DeepEqual(m, wm) {
-				t.Errorf("#%d on %d: body = %+v, want %+v", i, j, m, wm)
-			}
-		}
-	}
-
-	cl.Destroy()
-}
-
-func TestGetAdminMachinesEndPoint(t *testing.T) {
-	cl := &testCluster{Size: 3}
-	cl.Start()
-
-	w := make([]*machineMessage, cl.Size)
-	for i := 0; i < cl.Size; i++ {
-		w[i] = &machineMessage{
-			Name:      fmt.Sprint(cl.Id(i)),
-			State:     stateFollower,
-			ClientURL: cl.URL(i),
-			PeerURL:   cl.URL(i),
-		}
-	}
-	w[0].State = stateLeader
-
-	for i := 0; i < cl.Size; i++ {
-		r, err := http.Get(cl.URL(i) + v2adminMachinesPrefix)
-		if err != nil {
-			t.Errorf("%v", err)
-			continue
-		}
-		m := make([]*machineMessage, 0)
-		err = json.NewDecoder(r.Body).Decode(&m)
-		r.Body.Close()
-		if err != nil {
-			t.Errorf("%v", err)
-			continue
-		}
-
-		sm := machineSlice(m)
-		sw := machineSlice(w)
-		sort.Sort(sm)
-		sort.Sort(sw)
-
-		if !reflect.DeepEqual(sm, sw) {
-			t.Errorf("on %d: machines = %+v, want %+v", i, sm, sw)
-		}
-	}
-
-	cl.Destroy()
-}
-
-// int64Slice implements sort interface
-type machineSlice []*machineMessage
-
-func (s machineSlice) Len() int           { return len(s) }
-func (s machineSlice) Less(i, j int) bool { return s[i].Name < s[j].Name }
-func (s machineSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

+ 0 - 146
etcdserver/v2_http_get.go

@@ -1,146 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"strconv"
-
-	etcdErr "github.com/coreos/etcd/error"
-)
-
-func (p *participant) GetHandler(w http.ResponseWriter, req *http.Request) error {
-	if req.FormValue("consistent") == "true" && !p.node.IsLeader() {
-		return p.redirect(w, req, p.node.Leader())
-	}
-
-	key := req.URL.Path[len("/v2/keys"):]
-	recursive := (req.FormValue("recursive") == "true")
-	sort := (req.FormValue("sorted") == "true")
-	waitIndex := req.FormValue("waitIndex")
-	stream := (req.FormValue("stream") == "true")
-	if req.FormValue("quorum") == "true" {
-		return p.handleQuorumGet(key, recursive, sort, w, req)
-	}
-	if req.FormValue("wait") == "true" {
-		return p.handleWatch(key, recursive, stream, waitIndex, w, req)
-	}
-	return p.handleGet(key, recursive, sort, w, req)
-}
-
-func (p *participant) handleWatch(key string, recursive, stream bool, waitIndex string, w http.ResponseWriter, req *http.Request) error {
-	// Create a command to watch from a given index (default 0).
-	var sinceIndex uint64 = 0
-	var err error
-
-	if waitIndex != "" {
-		sinceIndex, err = strconv.ParseUint(waitIndex, 10, 64)
-		if err != nil {
-			return etcdErr.NewError(etcdErr.EcodeIndexNaN, "Watch From Index", p.Store.Index())
-		}
-	}
-
-	watcher, err := p.Store.Watch(key, recursive, stream, sinceIndex)
-	if err != nil {
-		return err
-	}
-
-	cn, _ := w.(http.CloseNotifier)
-	closeChan := cn.CloseNotify()
-
-	p.writeHeaders(w)
-	w.(http.Flusher).Flush()
-
-	if stream {
-		// watcher hub will not help to remove stream watcher
-		// so we need to remove here
-		defer watcher.Remove()
-		for {
-			select {
-			case <-closeChan:
-				return nil
-			case event, ok := <-watcher.EventChan:
-				if !ok {
-					// If the channel is closed this may be an indication of
-					// that notifications are much more than we are able to
-					// send to the client in time. Then we simply end streaming.
-					return nil
-				}
-				if req.Method == "HEAD" {
-					continue
-				}
-
-				b, _ := json.Marshal(event)
-				_, err := w.Write(b)
-				if err != nil {
-					return nil
-				}
-				w.(http.Flusher).Flush()
-			}
-		}
-	}
-
-	select {
-	case <-closeChan:
-		watcher.Remove()
-	case event := <-watcher.EventChan:
-		if req.Method == "HEAD" {
-			return nil
-		}
-		b, _ := json.Marshal(event)
-		w.Write(b)
-	}
-	return nil
-}
-
-func (p *participant) handleGet(key string, recursive, sort bool, w http.ResponseWriter, req *http.Request) error {
-	event, err := p.Store.Get(key, recursive, sort)
-	if err != nil {
-		return err
-	}
-	p.writeHeaders(w)
-	if req.Method == "HEAD" {
-		return nil
-	}
-	b, err := json.Marshal(event)
-	if err != nil {
-		panic(fmt.Sprintf("handleGet: ", err))
-	}
-	w.Write(b)
-	return nil
-}
-
-func (p *participant) handleQuorumGet(key string, recursive, sort bool, w http.ResponseWriter, req *http.Request) error {
-	if req.Method == "HEAD" {
-		return fmt.Errorf("not support HEAD")
-	}
-	event, err := p.QuorumGet(key, recursive, sort)
-	if err != nil {
-		return err
-	}
-	p.handleRet(w, event)
-	return nil
-}
-
-func (p *participant) writeHeaders(w http.ResponseWriter) {
-	w.Header().Set("Content-Type", "application/json")
-	w.Header().Add("X-Etcd-Index", fmt.Sprint(p.Store.Index()))
-	// TODO(xiangli): raft-index and term
-	w.WriteHeader(http.StatusOK)
-}

+ 0 - 1080
etcdserver/v2_http_kv_test.go

@@ -1,1080 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"net/url"
-	"reflect"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestV2Set(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-	v := url.Values{}
-	v.Set("value", "bar")
-
-	tests := []struct {
-		relativeURL string
-		value       url.Values
-		wStatus     int
-		w           string
-	}{
-		{
-			"/v2/keys/foo/bar",
-			v,
-			http.StatusCreated,
-			`{"action":"set","node":{"key":"/foo/bar","value":"bar","modifiedIndex":2,"createdIndex":2}}`,
-		},
-		{
-			"/v2/keys/foodir?dir=true",
-			url.Values{},
-			http.StatusCreated,
-			`{"action":"set","node":{"key":"/foodir","dir":true,"modifiedIndex":3,"createdIndex":3}}`,
-		},
-		{
-			"/v2/keys/fooempty",
-			url.Values(map[string][]string{"value": {""}}),
-			http.StatusCreated,
-			`{"action":"set","node":{"key":"/fooempty","value":"","modifiedIndex":4,"createdIndex":4}}`,
-		},
-	}
-
-	for i, tt := range tests {
-		resp, err := tc.PutForm(fmt.Sprintf("%s%s", u, tt.relativeURL), tt.value)
-		if err != nil {
-			t.Errorf("#%d: err = %v, want nil", i, err)
-		}
-		g := string(tc.ReadBody(resp))
-		if g != tt.w {
-			t.Errorf("#%d: body = %v, want %v", i, g, tt.w)
-		}
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-	}
-}
-
-func TestV2CreateUpdate(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	tests := []struct {
-		relativeURL string
-		value       url.Values
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		// key with ttl
-		{
-			"/v2/keys/ttl/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "ttl": {"20"}}),
-			http.StatusCreated,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value": "XXX",
-					"ttl":   float64(20),
-				},
-			},
-		},
-		// key with bad ttl
-		{
-			"/v2/keys/ttl/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "ttl": {"bad_ttl"}}),
-			http.StatusBadRequest,
-			map[string]interface{}{
-				"errorCode": float64(202),
-				"message":   "The given TTL in POST form is not a number",
-				"cause":     "Update",
-			},
-		},
-		// create key
-		{
-			"/v2/keys/create/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevExist": {"false"}}),
-			http.StatusCreated,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value": "XXX",
-				},
-			},
-		},
-		// created key failed
-		{
-			"/v2/keys/create/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevExist": {"false"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(105),
-				"message":   "Key already exists",
-				"cause":     "/create/foo",
-			},
-		},
-		// update the newly created key with ttl
-		{
-			"/v2/keys/create/foo",
-			url.Values(map[string][]string{"value": {"YYY"}, "prevExist": {"true"}, "ttl": {"20"}}),
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value": "YYY",
-					"ttl":   float64(20),
-				},
-				"action": "update",
-			},
-		},
-		// update the ttl to none
-		{
-			"/v2/keys/create/foo",
-			url.Values(map[string][]string{"value": {"ZZZ"}, "prevExist": {"true"}}),
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value": "ZZZ",
-				},
-				"action": "update",
-			},
-		},
-		// update on a non-existing key
-		{
-			"/v2/keys/nonexist",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevExist": {"true"}}),
-			http.StatusNotFound,
-			map[string]interface{}{
-				"errorCode": float64(100),
-				"message":   "Key not found",
-				"cause":     "/nonexist",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, tt.relativeURL), tt.value)
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2CAS(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	tests := []struct {
-		relativeURL string
-		value       url.Values
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}}),
-			http.StatusCreated,
-			nil,
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"2"}}),
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value":         "YYY",
-					"modifiedIndex": float64(3),
-				},
-				"action": "compareAndSwap",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"10"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[10 != 3]",
-				"index":     float64(3),
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"bad_index"}}),
-			http.StatusBadRequest,
-			map[string]interface{}{
-				"errorCode": float64(203),
-				"message":   "The given index in POST form is not a number",
-				"cause":     "CompareAndSwap",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"ZZZ"}, "prevValue": {"YYY"}}),
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"value": "ZZZ",
-				},
-				"action": "compareAndSwap",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"bad_value"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[bad_value != ZZZ]",
-			},
-		},
-		// prevValue is required
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {""}}),
-			http.StatusBadRequest,
-			map[string]interface{}{
-				"errorCode": float64(201),
-				"message":   "PrevValue is Required in POST form",
-				"cause":     "CompareAndSwap",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"bad_value"}, "prevIndex": {"100"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[bad_value != ZZZ] [100 != 4]",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"ZZZ"}, "prevIndex": {"100"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[100 != 4]",
-			},
-		},
-		{
-			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"bad_value"}, "prevIndex": {"4"}}),
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[bad_value != ZZZ]",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, tt.relativeURL), tt.value)
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2Delete(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, err := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-	resp, err = tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/emptydir?dir=true"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-	resp, err = tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foodir/bar?dir=true"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-
-	tests := []struct {
-		relativeURL string
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/foo",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foo",
-				},
-				"prevNode": map[string]interface{}{
-					"key":   "/foo",
-					"value": "XXX",
-				},
-				"action": "delete",
-			},
-		},
-		{
-			"/v2/keys/emptydir",
-			http.StatusForbidden,
-			map[string]interface{}{
-				"errorCode": float64(102),
-				"message":   "Not a file",
-				"cause":     "/emptydir",
-			},
-		},
-		{
-			"/v2/keys/emptydir?dir=true",
-			http.StatusOK,
-			nil,
-		},
-		{
-			"/v2/keys/foodir?dir=true",
-			http.StatusForbidden,
-			map[string]interface{}{
-				"errorCode": float64(108),
-				"message":   "Directory not empty",
-				"cause":     "/foodir",
-			},
-		},
-		{
-			"/v2/keys/foodir?recursive=true",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foodir",
-					"dir": true,
-				},
-				"prevNode": map[string]interface{}{
-					"key": "/foodir",
-					"dir": true,
-				},
-				"action": "delete",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.DeleteForm(fmt.Sprintf("%s%s", u, tt.relativeURL), nil)
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2CAD(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, err := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-
-	resp, err = tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foovalue"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-
-	tests := []struct {
-		relativeURL string
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/foo?prevIndex=100",
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[100 != 2]",
-			},
-		},
-		{
-			"/v2/keys/foo?prevIndex=bad_index",
-			http.StatusBadRequest,
-			map[string]interface{}{
-				"errorCode": float64(203),
-				"message":   "The given index in POST form is not a number",
-				"cause":     "CompareAndDelete",
-			},
-		},
-		{
-			"/v2/keys/foo?prevIndex=2",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":           "/foo",
-					"modifiedIndex": float64(4),
-				},
-				"action": "compareAndDelete",
-			},
-		},
-		{
-			"/v2/keys/foovalue?prevValue=YYY",
-			http.StatusPreconditionFailed,
-			map[string]interface{}{
-				"errorCode": float64(101),
-				"message":   "Compare failed",
-				"cause":     "[YYY != XXX]",
-			},
-		},
-		{
-			"/v2/keys/foovalue?prevValue=",
-			http.StatusBadRequest,
-			map[string]interface{}{
-				"errorCode": float64(201),
-				"message":   "PrevValue is Required in POST form",
-				"cause":     "CompareAndDelete",
-			},
-		},
-		{
-			"/v2/keys/foovalue?prevValue=XXX",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":           "/foovalue",
-					"modifiedIndex": float64(5),
-				},
-				"action": "compareAndDelete",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.DeleteForm(fmt.Sprintf("%s%s", u, tt.relativeURL), nil)
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2Unique(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	tests := []struct {
-		relativeURL string
-		value       url.Values
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/foo",
-			url.Values(map[string][]string{"value": {"XXX"}}),
-			http.StatusCreated,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":   "/foo/2",
-					"value": "XXX",
-				},
-				"action": "create",
-			},
-		},
-		{
-			"/v2/keys/foo",
-			url.Values(map[string][]string{"value": {"XXX"}}),
-			http.StatusCreated,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":   "/foo/3",
-					"value": "XXX",
-				},
-				"action": "create",
-			},
-		},
-		{
-			"/v2/keys/bar",
-			url.Values(map[string][]string{"value": {"XXX"}}),
-			http.StatusCreated,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":   "/bar/4",
-					"value": "XXX",
-				},
-				"action": "create",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.PostForm(fmt.Sprintf("%s%s", u, tt.relativeURL), tt.value)
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2Get(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, err := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar/zar"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-
-	tests := []struct {
-		relativeURL string
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/foo/bar/zar",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":   "/foo/bar/zar",
-					"value": "XXX",
-				},
-				"action": "get",
-			},
-		},
-		{
-			"/v2/keys/foo",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foo",
-					"dir": true,
-					"nodes": []interface{}{
-						map[string]interface{}{
-							"key":           "/foo/bar",
-							"dir":           true,
-							"createdIndex":  float64(2),
-							"modifiedIndex": float64(2),
-						},
-					},
-				},
-				"action": "get",
-			},
-		},
-		{
-			"/v2/keys/foo?recursive=true",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foo",
-					"dir": true,
-					"nodes": []interface{}{
-						map[string]interface{}{
-							"key":           "/foo/bar",
-							"dir":           true,
-							"createdIndex":  float64(2),
-							"modifiedIndex": float64(2),
-							"nodes": []interface{}{
-								map[string]interface{}{
-									"key":           "/foo/bar/zar",
-									"value":         "XXX",
-									"createdIndex":  float64(2),
-									"modifiedIndex": float64(2),
-								},
-							},
-						},
-					},
-				},
-				"action": "get",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, tt.relativeURL))
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if resp.Header.Get("Content-Type") != "application/json" {
-			t.Errorf("#%d: header = %v, want %v", resp.Header.Get("Content-Type"), "application/json")
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestConsistentGet(t *testing.T) {
-	defer afterTest(t)
-
-	noredirect := func(req *http.Request, via []*http.Request) error {
-		return errors.New("no redirect")
-	}
-
-	c := &testCluster{Size: 3}
-	c.Start()
-	defer c.Destroy()
-
-	u := fmt.Sprintf("%s%s", c.URL(1), "/v2/keys/foo?consistent=true")
-	ru := fmt.Sprintf("%s%s", c.URL(0), "/v2/keys/foo?consistent=true")
-	tc := testHttpClient{&http.Client{CheckRedirect: noredirect}}
-	resp, _ := tc.Get(u)
-	if resp.StatusCode != http.StatusTemporaryRedirect {
-		t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusTemporaryRedirect)
-	}
-	location, err := resp.Location()
-	if err != nil {
-		t.Errorf("err = %v, want nil", err)
-	}
-	if location.String() != ru {
-		t.Errorf("location = %v, want %v", location.String(), ru)
-	}
-	resp.Body.Close()
-}
-
-func TestV2QuorumGet(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, err := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar/zar?quorum=true"), v)
-	if err != nil {
-		t.Error(err)
-	}
-	resp.Body.Close()
-
-	tests := []struct {
-		relativeURL string
-		wStatus     int
-		w           map[string]interface{}
-	}{
-		{
-			"/v2/keys/foo/bar/zar",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key":   "/foo/bar/zar",
-					"value": "XXX",
-				},
-				"action": "get",
-			},
-		},
-		{
-			"/v2/keys/foo",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foo",
-					"dir": true,
-					"nodes": []interface{}{
-						map[string]interface{}{
-							"key":           "/foo/bar",
-							"dir":           true,
-							"createdIndex":  float64(2),
-							"modifiedIndex": float64(2),
-						},
-					},
-				},
-				"action": "get",
-			},
-		},
-		{
-			"/v2/keys/foo?recursive=true",
-			http.StatusOK,
-			map[string]interface{}{
-				"node": map[string]interface{}{
-					"key": "/foo",
-					"dir": true,
-					"nodes": []interface{}{
-						map[string]interface{}{
-							"key":           "/foo/bar",
-							"dir":           true,
-							"createdIndex":  float64(2),
-							"modifiedIndex": float64(2),
-							"nodes": []interface{}{
-								map[string]interface{}{
-									"key":           "/foo/bar/zar",
-									"value":         "XXX",
-									"createdIndex":  float64(2),
-									"modifiedIndex": float64(2),
-								},
-							},
-						},
-					},
-				},
-				"action": "get",
-			},
-		},
-	}
-
-	for i, tt := range tests {
-		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, tt.relativeURL))
-		if resp.StatusCode != tt.wStatus {
-			t.Errorf("#%d: status = %d, want %d", i, resp.StatusCode, tt.wStatus)
-		}
-		if resp.Header.Get("Content-Type") != "application/json" {
-			t.Errorf("#%d: header = %v, want %v", resp.Header.Get("Content-Type"), "application/json")
-		}
-		if err := checkBody(tc.ReadBodyJSON(resp), tt.w); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestV2Watch(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	var watchResp *http.Response
-	c := make(chan bool)
-	go func() {
-		watchResp, _ = tc.Get(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?wait=true"))
-		c <- true
-	}()
-
-	// Make sure response didn't fire early.
-	time.Sleep(1 * time.Millisecond)
-
-	// Set a value.
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar"), v)
-	resp.Body.Close()
-
-	select {
-	case <-c:
-	case <-time.After(time.Millisecond):
-		t.Fatal("cannot get watch result")
-	}
-
-	body := tc.ReadBodyJSON(watchResp)
-	w := map[string]interface{}{
-		"node": map[string]interface{}{
-			"key":           "/foo/bar",
-			"value":         "XXX",
-			"modifiedIndex": float64(2),
-		},
-		"action": "set",
-	}
-
-	if err := checkBody(body, w); err != nil {
-		t.Error(err)
-	}
-}
-
-func TestV2WatchWithIndex(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	var body map[string]interface{}
-	c := make(chan bool, 1)
-	go func() {
-		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?wait=true&waitIndex=3"))
-		body = tc.ReadBodyJSON(resp)
-		c <- true
-	}()
-
-	select {
-	case <-c:
-		t.Fatal("should not get the watch result")
-	case <-time.After(time.Millisecond):
-	}
-
-	// Set a value (before given index).
-	v := url.Values{}
-	v.Set("value", "XXX")
-	resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar"), v)
-	resp.Body.Close()
-
-	select {
-	case <-c:
-		t.Fatal("should not get the watch result")
-	case <-time.After(time.Millisecond):
-	}
-
-	// Set a value (before given index).
-	resp, _ = tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar"), v)
-	resp.Body.Close()
-
-	select {
-	case <-c:
-	case <-time.After(time.Millisecond):
-		t.Fatal("cannot get watch result")
-	}
-
-	w := map[string]interface{}{
-		"node": map[string]interface{}{
-			"key":           "/foo/bar",
-			"value":         "XXX",
-			"modifiedIndex": float64(3),
-		},
-		"action": "set",
-	}
-	if err := checkBody(body, w); err != nil {
-		t.Error(err)
-	}
-}
-
-func TestV2WatchKeyInDir(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	var body map[string]interface{}
-	c := make(chan bool)
-
-	// Set a value (before given index).
-	v := url.Values{}
-	v.Set("dir", "true")
-	v.Set("ttl", "1")
-	resp, _ := tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/keyindir"), v)
-	resp.Body.Close()
-
-	// Set a value (before given index).
-	v = url.Values{}
-	v.Set("value", "XXX")
-	resp, _ = tc.PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/keyindir/bar"), v)
-	resp.Body.Close()
-
-	go func() {
-		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, "/v2/keys/keyindir/bar?wait=true"))
-		body = tc.ReadBodyJSON(resp)
-		c <- true
-	}()
-
-	select {
-	case <-c:
-	case <-time.After(time.Millisecond * 1500):
-		t.Fatal("cannot get watch result")
-	}
-
-	w := map[string]interface{}{
-		"node": map[string]interface{}{
-			"key": "/keyindir",
-		},
-		"action": "expire",
-	}
-	if err := checkBody(body, w); err != nil {
-		t.Error(err)
-	}
-}
-
-func TestV2Head(t *testing.T) {
-	cl := testCluster{Size: 1}
-	cl.Start()
-	defer cl.Destroy()
-
-	u := cl.URL(0)
-	tc := NewTestClient()
-
-	v := url.Values{}
-	v.Set("value", "XXX")
-	fullURL := fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar")
-	resp, _ := tc.Head(fullURL)
-	resp.Body.Close()
-	if resp.StatusCode != http.StatusNotFound {
-		t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusNotFound)
-	}
-	if resp.ContentLength != -1 {
-		t.Errorf("ContentLength = %d, want -1", resp.ContentLength)
-	}
-
-	resp, _ = tc.PutForm(fullURL, v)
-	resp.Body.Close()
-
-	resp, _ = tc.Head(fullURL)
-	resp.Body.Close()
-	if resp.StatusCode != http.StatusOK {
-		t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusOK)
-	}
-	if resp.ContentLength != -1 {
-		t.Errorf("ContentLength = %d, want -1", resp.ContentLength)
-	}
-}
-
-func checkBody(body map[string]interface{}, w map[string]interface{}) error {
-	if body["node"] != nil {
-		if w["node"] != nil {
-			wn := w["node"].(map[string]interface{})
-			n := body["node"].(map[string]interface{})
-			for k := range n {
-				if wn[k] == nil {
-					delete(n, k)
-				}
-			}
-			body["node"] = n
-		}
-		if w["prevNode"] != nil {
-			wn := w["prevNode"].(map[string]interface{})
-			n := body["prevNode"].(map[string]interface{})
-			for k := range n {
-				if wn[k] == nil {
-					delete(n, k)
-				}
-			}
-			body["prevNode"] = n
-		}
-	}
-	for k, v := range w {
-		g := body[k]
-		if !reflect.DeepEqual(g, v) {
-			return fmt.Errorf("%v = %+v, want %+v", k, g, v)
-		}
-	}
-	return nil
-}
-
-type testHttpClient struct {
-	*http.Client
-}
-
-// Creates a new HTTP client with KeepAlive disabled.
-func NewTestClient() *testHttpClient {
-	tr := &http.Transport{
-		Dial:              (&net.Dialer{Timeout: time.Second}).Dial,
-		DisableKeepAlives: true,
-	}
-	return &testHttpClient{&http.Client{Transport: tr}}
-}
-
-// Reads the body from the response and closes it.
-func (t *testHttpClient) ReadBody(resp *http.Response) []byte {
-	if resp == nil {
-		return []byte{}
-	}
-	body, _ := ioutil.ReadAll(resp.Body)
-	resp.Body.Close()
-	return body
-}
-
-// Reads the body from the response and parses it as JSON.
-func (t *testHttpClient) ReadBodyJSON(resp *http.Response) map[string]interface{} {
-	m := make(map[string]interface{})
-	b := t.ReadBody(resp)
-	if err := json.Unmarshal(b, &m); err != nil {
-		panic(fmt.Sprintf("HTTP body JSON parse error: %v: %s", err, string(b)))
-	}
-	return m
-}
-
-func (t *testHttpClient) Head(url string) (*http.Response, error) {
-	return t.send("HEAD", url, "application/json", nil)
-}
-
-func (t *testHttpClient) Get(url string) (*http.Response, error) {
-	return t.send("GET", url, "application/json", nil)
-}
-
-func (t *testHttpClient) Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return t.send("POST", url, bodyType, body)
-}
-
-func (t *testHttpClient) PostForm(url string, data url.Values) (*http.Response, error) {
-	return t.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func (t *testHttpClient) Put(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return t.send("PUT", url, bodyType, body)
-}
-
-func (t *testHttpClient) PutForm(url string, data url.Values) (*http.Response, error) {
-	return t.Put(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func (t *testHttpClient) Delete(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return t.send("DELETE", url, bodyType, body)
-}
-
-func (t *testHttpClient) DeleteForm(url string, data url.Values) (*http.Response, error) {
-	return t.Delete(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func (t *testHttpClient) send(method string, url string, bodyType string, body io.Reader) (*http.Response, error) {
-	req, err := http.NewRequest(method, url, body)
-	if err != nil {
-		return nil, err
-	}
-	req.Header.Set("Content-Type", bodyType)
-	return t.Do(req)
-}

+ 0 - 46
etcdserver/v2_http_post.go

@@ -1,46 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"net/http"
-
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/store"
-)
-
-func (p *participant) PostHandler(w http.ResponseWriter, req *http.Request) error {
-	if !p.node.IsLeader() {
-		return p.redirect(w, req, p.node.Leader())
-	}
-
-	key := req.URL.Path[len("/v2/keys"):]
-
-	value := req.FormValue("value")
-	dir := (req.FormValue("dir") == "true")
-	expireTime, err := store.TTL(req.FormValue("ttl"))
-	if err != nil {
-		return etcdErr.NewError(etcdErr.EcodeTTLNaN, "Create", p.Store.Index())
-	}
-
-	ret, err := p.Create(key, dir, value, expireTime, true)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}

+ 0 - 157
etcdserver/v2_http_put.go

@@ -1,157 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"net/url"
-	"strconv"
-	"time"
-
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/store"
-)
-
-func (p *participant) PutHandler(w http.ResponseWriter, req *http.Request) error {
-	if !p.node.IsLeader() {
-		return p.redirect(w, req, p.node.Leader())
-	}
-
-	key := req.URL.Path[len("/v2/keys"):]
-
-	req.ParseForm()
-
-	value := req.Form.Get("value")
-	dir := (req.FormValue("dir") == "true")
-
-	expireTime, err := store.TTL(req.Form.Get("ttl"))
-	if err != nil {
-		return etcdErr.NewError(etcdErr.EcodeTTLNaN, "Update", p.Store.Index())
-	}
-
-	prevValue, valueOk := firstValue(req.Form, "prevValue")
-	prevIndexStr, indexOk := firstValue(req.Form, "prevIndex")
-	prevExist, existOk := firstValue(req.Form, "prevExist")
-
-	// Set handler: create a new node or replace the old one.
-	if !valueOk && !indexOk && !existOk {
-		return p.serveSet(w, req, key, dir, value, expireTime)
-	}
-
-	// update with test
-	if existOk {
-		if prevExist == "false" {
-			// Create command: create a new node. Fail, if a node already exists
-			// Ignore prevIndex and prevValue
-			return p.serveCreate(w, req, key, dir, value, expireTime)
-		}
-
-		if prevExist == "true" && !indexOk && !valueOk {
-			return p.serveUpdate(w, req, key, value, expireTime)
-		}
-	}
-
-	var prevIndex uint64
-
-	if indexOk {
-		prevIndex, err = strconv.ParseUint(prevIndexStr, 10, 64)
-
-		// bad previous index
-		if err != nil {
-			return etcdErr.NewError(etcdErr.EcodeIndexNaN, "CompareAndSwap", p.Store.Index())
-		}
-	} else {
-		prevIndex = 0
-	}
-
-	if valueOk {
-		if prevValue == "" {
-			return etcdErr.NewError(etcdErr.EcodePrevValueRequired, "CompareAndSwap", p.Store.Index())
-		}
-	}
-
-	return p.serveCAS(w, req, key, value, prevValue, prevIndex, expireTime)
-}
-
-func (p *participant) handleRet(w http.ResponseWriter, ret *store.Event) {
-	b, _ := json.Marshal(ret)
-
-	w.Header().Set("Content-Type", "application/json")
-	// etcd index should be the same as the event index
-	// which is also the last modified index of the node
-	w.Header().Add("X-Etcd-Index", fmt.Sprint(ret.Index()))
-	// w.Header().Add("X-Raft-Index", fmt.Sprint(p.CommitIndex()))
-	// w.Header().Add("X-Raft-Term", fmt.Sprint(p.Term()))
-
-	if ret.IsCreated() {
-		w.WriteHeader(http.StatusCreated)
-	} else {
-		w.WriteHeader(http.StatusOK)
-	}
-
-	w.Write(b)
-}
-
-func (p *participant) serveSet(w http.ResponseWriter, req *http.Request, key string, dir bool, value string, expireTime time.Time) error {
-	ret, err := p.Set(key, dir, value, expireTime)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}
-
-func (p *participant) serveCreate(w http.ResponseWriter, req *http.Request, key string, dir bool, value string, expireTime time.Time) error {
-	ret, err := p.Create(key, dir, value, expireTime, false)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}
-
-func (p *participant) serveUpdate(w http.ResponseWriter, req *http.Request, key, value string, expireTime time.Time) error {
-	// Update should give at least one option
-	if value == "" && expireTime.Sub(store.Permanent) == 0 {
-		return etcdErr.NewError(etcdErr.EcodeValueOrTTLRequired, "Update", p.Store.Index())
-	}
-	ret, err := p.Update(key, value, expireTime)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}
-
-func (p *participant) serveCAS(w http.ResponseWriter, req *http.Request, key, value, prevValue string, prevIndex uint64, expireTime time.Time) error {
-	ret, err := p.CAS(key, value, prevValue, prevIndex, expireTime)
-	if err == nil {
-		p.handleRet(w, ret)
-		return nil
-	}
-	return err
-}
-
-func firstValue(f url.Values, key string) (string, bool) {
-	l, ok := f[key]
-	if !ok {
-		return "", false
-	}
-	return l[0], true
-}

+ 0 - 63
etcdserver/v2_raft.go

@@ -1,63 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"time"
-
-	"github.com/coreos/etcd/raft"
-)
-
-type v2Proposal struct {
-	data []byte
-	ret  chan interface{}
-}
-
-type wait struct {
-	index int64
-	term  int64
-}
-
-type v2Raft struct {
-	*raft.Node
-	result map[wait]chan interface{}
-	term   int64
-}
-
-func (r *v2Raft) Propose(p v2Proposal) {
-	if !r.Node.IsLeader() {
-		p.ret <- fmt.Errorf("not leader")
-		return
-	}
-	r.Node.Propose(p.data)
-	r.result[wait{r.Index(), r.Term()}] = p.ret
-	return
-}
-
-func (r *v2Raft) Sync() {
-	if !r.Node.IsLeader() {
-		return
-	}
-	t := time.Now()
-	sync := &Cmd{Type: stsync, Time: mustMarshalTime(&t)}
-	data, err := sync.Marshal()
-	if err != nil {
-		panic(err)
-	}
-	r.Node.Propose(data)
-}

+ 0 - 103
etcdserver/v2_store.go

@@ -1,103 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"fmt"
-	"time"
-
-	"github.com/coreos/etcd/store"
-)
-
-const (
-	stset = iota
-	stcreate
-	stupdate
-	stcas
-	stdelete
-	stcad
-	stqget
-	stsync
-)
-
-func (p *participant) Set(key string, dir bool, value string, expireTime time.Time) (*store.Event, error) {
-	set := &Cmd{Type: stset, Key: key, Dir: &dir, Value: &value, Time: mustMarshalTime(&expireTime)}
-	return p.do(set)
-}
-
-func (p *participant) Create(key string, dir bool, value string, expireTime time.Time, unique bool) (*store.Event, error) {
-	create := &Cmd{Type: stcreate, Key: key, Dir: &dir, Value: &value, Time: mustMarshalTime(&expireTime), Unique: &unique}
-	return p.do(create)
-}
-
-func (p *participant) Update(key string, value string, expireTime time.Time) (*store.Event, error) {
-	update := &Cmd{Type: stupdate, Key: key, Value: &value, Time: mustMarshalTime(&expireTime)}
-	return p.do(update)
-}
-
-func (p *participant) CAS(key, value, prevValue string, prevIndex uint64, expireTime time.Time) (*store.Event, error) {
-	cas := &Cmd{Type: stcas, Key: key, Value: &value, PrevValue: &prevValue, PrevIndex: &prevIndex, Time: mustMarshalTime(&expireTime)}
-	return p.do(cas)
-}
-
-func (p *participant) Delete(key string, dir, recursive bool) (*store.Event, error) {
-	d := &Cmd{Type: stdelete, Key: key, Dir: &dir, Recursive: &recursive}
-	return p.do(d)
-}
-
-func (p *participant) CAD(key string, prevValue string, prevIndex uint64) (*store.Event, error) {
-	cad := &Cmd{Type: stcad, Key: key, PrevValue: &prevValue, PrevIndex: &prevIndex}
-	return p.do(cad)
-}
-func (p *participant) QuorumGet(key string, recursive, sorted bool) (*store.Event, error) {
-	get := &Cmd{Type: stqget, Key: key, Recursive: &recursive, Sorted: &sorted}
-	return p.do(get)
-}
-
-func (p *participant) do(c *Cmd) (*store.Event, error) {
-	data, err := c.Marshal()
-	if err != nil {
-		panic(err)
-	}
-
-	pp := v2Proposal{
-		data: data,
-		ret:  make(chan interface{}, 1),
-	}
-
-	select {
-	case p.proposal <- pp:
-	default:
-		return nil, fmt.Errorf("unable to send out the proposal")
-	}
-
-	var ret interface{}
-	select {
-	case ret = <-pp.ret:
-	case <-p.stopNotifyc:
-		return nil, fmt.Errorf("stop serving")
-	}
-
-	switch t := ret.(type) {
-	case *store.Event:
-		return t, nil
-	case error:
-		return nil, t
-	default:
-		panic("server.do: unexpected return type")
-	}
-}

+ 0 - 454
etcdserver/v2_store_cmd.pb.go

@@ -1,454 +0,0 @@
-// Code generated by protoc-gen-gogo.
-// source: v2_store_cmd.proto
-// DO NOT EDIT!
-
-/*
-	Package etcd is a generated protocol buffer package.
-
-	It is generated from these files:
-		v2_store_cmd.proto
-
-	It has these top-level messages:
-		Cmd
-*/
-package etcdserver
-
-import proto "code.google.com/p/gogoprotobuf/proto"
-import json "encoding/json"
-import math "math"
-
-// discarding unused import gogoproto "code.google.com/p/gogoprotobuf/gogoproto/gogo.pb"
-
-import io "io"
-import code_google_com_p_gogoprotobuf_proto "code.google.com/p/gogoprotobuf/proto"
-
-// Reference proto, json, and math imports to suppress error if they are not otherwise used.
-var _ = proto.Marshal
-var _ = &json.SyntaxError{}
-var _ = math.Inf
-
-type Cmd struct {
-	Type             int32   `protobuf:"varint,1,req,name=type" json:"type"`
-	Key              string  `protobuf:"bytes,2,req,name=key" json:"key"`
-	Value            *string `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"`
-	PrevValue        *string `protobuf:"bytes,4,opt,name=prevValue" json:"prevValue,omitempty"`
-	PrevIndex        *uint64 `protobuf:"varint,5,opt,name=prevIndex" json:"prevIndex,omitempty"`
-	Dir              *bool   `protobuf:"varint,6,opt,name=dir" json:"dir,omitempty"`
-	Recursive        *bool   `protobuf:"varint,7,opt,name=recursive" json:"recursive,omitempty"`
-	Unique           *bool   `protobuf:"varint,8,opt,name=unique" json:"unique,omitempty"`
-	Sorted           *bool   `protobuf:"varint,9,opt,name=sorted" json:"sorted,omitempty"`
-	Time             []byte  `protobuf:"bytes,10,opt,name=time" json:"time,omitempty"`
-	XXX_unrecognized []byte  `json:"-"`
-}
-
-func (m *Cmd) Reset()         { *m = Cmd{} }
-func (m *Cmd) String() string { return proto.CompactTextString(m) }
-func (*Cmd) ProtoMessage()    {}
-
-func init() {
-}
-func (m *Cmd) Unmarshal(data []byte) error {
-	l := len(data)
-	index := 0
-	for index < l {
-		var wire uint64
-		for shift := uint(0); ; shift += 7 {
-			if index >= l {
-				return io.ErrUnexpectedEOF
-			}
-			b := data[index]
-			index++
-			wire |= (uint64(b) & 0x7F) << shift
-			if b < 0x80 {
-				break
-			}
-		}
-		fieldNum := int32(wire >> 3)
-		wireType := int(wire & 0x7)
-		switch fieldNum {
-		case 1:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				m.Type |= (int32(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-		case 2:
-			if wireType != 2 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var stringLen uint64
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				stringLen |= (uint64(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			postIndex := index + int(stringLen)
-			if postIndex > l {
-				return io.ErrUnexpectedEOF
-			}
-			m.Key = string(data[index:postIndex])
-			index = postIndex
-		case 3:
-			if wireType != 2 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var stringLen uint64
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				stringLen |= (uint64(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			postIndex := index + int(stringLen)
-			if postIndex > l {
-				return io.ErrUnexpectedEOF
-			}
-			s := string(data[index:postIndex])
-			m.Value = &s
-			index = postIndex
-		case 4:
-			if wireType != 2 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var stringLen uint64
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				stringLen |= (uint64(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			postIndex := index + int(stringLen)
-			if postIndex > l {
-				return io.ErrUnexpectedEOF
-			}
-			s := string(data[index:postIndex])
-			m.PrevValue = &s
-			index = postIndex
-		case 5:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var v uint64
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				v |= (uint64(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			m.PrevIndex = &v
-		case 6:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var v int
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				v |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			b := bool(v != 0)
-			m.Dir = &b
-		case 7:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var v int
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				v |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			b := bool(v != 0)
-			m.Recursive = &b
-		case 8:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var v int
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				v |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			b := bool(v != 0)
-			m.Unique = &b
-		case 9:
-			if wireType != 0 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var v int
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				v |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			b := bool(v != 0)
-			m.Sorted = &b
-		case 10:
-			if wireType != 2 {
-				return code_google_com_p_gogoprotobuf_proto.ErrWrongType
-			}
-			var byteLen int
-			for shift := uint(0); ; shift += 7 {
-				if index >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := data[index]
-				index++
-				byteLen |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			postIndex := index + byteLen
-			if postIndex > l {
-				return io.ErrUnexpectedEOF
-			}
-			m.Time = append(m.Time, data[index:postIndex]...)
-			index = postIndex
-		default:
-			var sizeOfWire int
-			for {
-				sizeOfWire++
-				wire >>= 7
-				if wire == 0 {
-					break
-				}
-			}
-			index -= sizeOfWire
-			skippy, err := code_google_com_p_gogoprotobuf_proto.Skip(data[index:])
-			if err != nil {
-				return err
-			}
-			if (index + skippy) > l {
-				return io.ErrUnexpectedEOF
-			}
-			m.XXX_unrecognized = append(m.XXX_unrecognized, data[index:index+skippy]...)
-			index += skippy
-		}
-	}
-	return nil
-}
-func (m *Cmd) Size() (n int) {
-	var l int
-	_ = l
-	n += 1 + sovV2StoreCmd(uint64(uint32(m.Type)))
-	l = len(m.Key)
-	n += 1 + l + sovV2StoreCmd(uint64(l))
-	if m.Value != nil {
-		l = len(*m.Value)
-		n += 1 + l + sovV2StoreCmd(uint64(l))
-	}
-	if m.PrevValue != nil {
-		l = len(*m.PrevValue)
-		n += 1 + l + sovV2StoreCmd(uint64(l))
-	}
-	if m.PrevIndex != nil {
-		n += 1 + sovV2StoreCmd(uint64(*m.PrevIndex))
-	}
-	if m.Dir != nil {
-		n += 2
-	}
-	if m.Recursive != nil {
-		n += 2
-	}
-	if m.Unique != nil {
-		n += 2
-	}
-	if m.Sorted != nil {
-		n += 2
-	}
-	if m.Time != nil {
-		l = len(m.Time)
-		n += 1 + l + sovV2StoreCmd(uint64(l))
-	}
-	if m.XXX_unrecognized != nil {
-		n += len(m.XXX_unrecognized)
-	}
-	return n
-}
-
-func sovV2StoreCmd(x uint64) (n int) {
-	for {
-		n++
-		x >>= 7
-		if x == 0 {
-			break
-		}
-	}
-	return n
-}
-func sozV2StoreCmd(x uint64) (n int) {
-	return sovV2StoreCmd(uint64((x << 1) ^ uint64((int64(x) >> 63))))
-}
-func (m *Cmd) Marshal() (data []byte, err error) {
-	size := m.Size()
-	data = make([]byte, size)
-	n, err := m.MarshalTo(data)
-	if err != nil {
-		return nil, err
-	}
-	return data[:n], nil
-}
-
-func (m *Cmd) MarshalTo(data []byte) (n int, err error) {
-	var i int
-	_ = i
-	var l int
-	_ = l
-	data[i] = 0x8
-	i++
-	i = encodeVarintV2StoreCmd(data, i, uint64(uint32(m.Type)))
-	data[i] = 0x12
-	i++
-	i = encodeVarintV2StoreCmd(data, i, uint64(len(m.Key)))
-	i += copy(data[i:], m.Key)
-	if m.Value != nil {
-		data[i] = 0x1a
-		i++
-		i = encodeVarintV2StoreCmd(data, i, uint64(len(*m.Value)))
-		i += copy(data[i:], *m.Value)
-	}
-	if m.PrevValue != nil {
-		data[i] = 0x22
-		i++
-		i = encodeVarintV2StoreCmd(data, i, uint64(len(*m.PrevValue)))
-		i += copy(data[i:], *m.PrevValue)
-	}
-	if m.PrevIndex != nil {
-		data[i] = 0x28
-		i++
-		i = encodeVarintV2StoreCmd(data, i, uint64(*m.PrevIndex))
-	}
-	if m.Dir != nil {
-		data[i] = 0x30
-		i++
-		if *m.Dir {
-			data[i] = 1
-		} else {
-			data[i] = 0
-		}
-		i++
-	}
-	if m.Recursive != nil {
-		data[i] = 0x38
-		i++
-		if *m.Recursive {
-			data[i] = 1
-		} else {
-			data[i] = 0
-		}
-		i++
-	}
-	if m.Unique != nil {
-		data[i] = 0x40
-		i++
-		if *m.Unique {
-			data[i] = 1
-		} else {
-			data[i] = 0
-		}
-		i++
-	}
-	if m.Sorted != nil {
-		data[i] = 0x48
-		i++
-		if *m.Sorted {
-			data[i] = 1
-		} else {
-			data[i] = 0
-		}
-		i++
-	}
-	if m.Time != nil {
-		data[i] = 0x52
-		i++
-		i = encodeVarintV2StoreCmd(data, i, uint64(len(m.Time)))
-		i += copy(data[i:], m.Time)
-	}
-	if m.XXX_unrecognized != nil {
-		i += copy(data[i:], m.XXX_unrecognized)
-	}
-	return i, nil
-}
-func encodeFixed64V2StoreCmd(data []byte, offset int, v uint64) int {
-	data[offset] = uint8(v)
-	data[offset+1] = uint8(v >> 8)
-	data[offset+2] = uint8(v >> 16)
-	data[offset+3] = uint8(v >> 24)
-	data[offset+4] = uint8(v >> 32)
-	data[offset+5] = uint8(v >> 40)
-	data[offset+6] = uint8(v >> 48)
-	data[offset+7] = uint8(v >> 56)
-	return offset + 8
-}
-func encodeFixed32V2StoreCmd(data []byte, offset int, v uint32) int {
-	data[offset] = uint8(v)
-	data[offset+1] = uint8(v >> 8)
-	data[offset+2] = uint8(v >> 16)
-	data[offset+3] = uint8(v >> 24)
-	return offset + 4
-}
-func encodeVarintV2StoreCmd(data []byte, offset int, v uint64) int {
-	for v >= 1<<7 {
-		data[offset] = uint8(v&0x7f | 0x80)
-		v >>= 7
-		offset++
-	}
-	data[offset] = uint8(v)
-	return offset + 1
-}

+ 0 - 21
etcdserver/v2_store_cmd.proto

@@ -1,21 +0,0 @@
-package etcdserver;
-
-import "code.google.com/p/gogoprotobuf/gogoproto/gogo.proto";
-
-option (gogoproto.marshaler_all) = true;
-option (gogoproto.sizer_all) = true;
-option (gogoproto.unmarshaler_all) = true;
-option (gogoproto.goproto_getters_all) = false;
-
-message cmd {
-	required int32  type       = 1 [(gogoproto.nullable) = false];
-	required string key        = 2 [(gogoproto.nullable) = false];
-	optional string value      = 3;
-	optional string prevValue  = 4;
-	optional uint64 prevIndex  = 5;
-	optional bool   dir        = 6;
-	optional bool   recursive  = 7;
-	optional bool   unique     = 8;
-	optional bool   sorted     = 9;
-	optional bytes  time       = 10;
-}

+ 0 - 82
etcdserver/v2_usage.go

@@ -1,82 +0,0 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package etcdserver
-
-import (
-	"strings"
-)
-
-// usage defines the message shown when a help flag is passed to etcd.
-var usage = `
-etcd
-
-Usage:
-  etcd -name <name>
-  etcd -name <name> [-data-dir=<path>]
-  etcd -h | -help
-  etcd -version
-
-Options:
-  -h -help          Show this screen.
-  --version         Show version.
-  -f -force         Force a new configuration to be used.
-  -config=<path>    Path to configuration file.
-  -name=<name>      Name of this node in the etcd cluster.
-  -data-dir=<path>  Path to the data directory.
-  -cors=<origins>   Comma-separated list of CORS origins.
-  -v                Enabled verbose logging.
-  -vv               Enabled very verbose logging.
-
-Cluster Configuration Options:
-  -discovery=<url>                Discovery service used to find a peer list.
-  -peers-file=<path>              Path to a file containing the peer list.
-  -peers=<host:port>,<host:port>  Comma-separated list of peers. The members
-                                  should match the peer's '-peer-addr' flag.
-
-Client Communication Options:
-  -addr=<host:port>         The public host:port used for client communication.
-  -bind-addr=<host[:port]>  The listening host:port used for client communication.
-  -ca-file=<path>           Path to the client CA file.
-  -cert-file=<path>         Path to the client cert file.
-  -key-file=<path>          Path to the client key file.
-
-Peer Communication Options:
-  -peer-addr=<host:port>  The public host:port used for peer communication.
-  -peer-bind-addr=<host[:port]>  The listening host:port used for peer communication.
-  -peer-ca-file=<path>    Path to the peer CA file.
-  -peer-cert-file=<path>  Path to the peer cert file.
-  -peer-key-file=<path>   Path to the peer key file.
-  -peer-heartbeat-interval=<time>
-                          Time (in milliseconds) of a heartbeat interval.
-  -peer-election-timeout=<time>
-                          Time (in milliseconds) for an election to timeout.
-
-Other Options:
-  -max-result-buffer   Max size of the result buffer.
-  -max-retry-attempts  Number of times a node will try to join a cluster.
-  -retry-interval      Seconds to wait between cluster join retry attempts.
-  -snapshot=false      Disable log snapshots
-  -snapshot-count      Number of transactions before issuing a snapshot.
-  -cluster-active-size Number of active nodes in the cluster.
-  -cluster-remove-delay Seconds before one node is removed.
-  -cluster-sync-interval Seconds between synchronizations for standby mode.
-`
-
-// Usage returns the usage message for etcd.
-func Usage() string {
-	return strings.TrimSpace(usage)
-}

+ 0 - 14
etcdserver/version.go

@@ -1,14 +0,0 @@
-package etcdserver
-
-import (
-	"fmt"
-	"net/http"
-)
-
-const (
-	releaseVersion = "0.5rc1+git"
-)
-
-func versionHandler(w http.ResponseWriter, req *http.Request) {
-	fmt.Fprintf(w, "etcd %s", releaseVersion)
-}

+ 0 - 94
etcdserver/z_last_test.go

@@ -1,94 +0,0 @@
-// 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 etcdserver
-
-import (
-	"net/http"
-	"runtime"
-	"sort"
-	"strings"
-	"testing"
-	"time"
-)
-
-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 testing.RunTests") ||
-			strings.Contains(stack, "testing.Main(") ||
-			strings.Contains(stack, "runtime.goexit") ||
-			strings.Contains(stack, "created by runtime.gc") ||
-			strings.Contains(stack, "runtime.MHeap_Scavenger") {
-			continue
-		}
-		gs = append(gs, stack)
-	}
-	sort.Strings(gs)
-	return
-}
-
-// Verify the other tests didn't leave any goroutines running.
-// This is in a file named z_last_test.go so it sorts at the end.
-func TestGoroutinesRunning(t *testing.T) {
-	if testing.Short() {
-		t.Skip("not counting goroutines for leakage in -short mode")
-	}
-	gs := interestingGoroutines()
-
-	n := 0
-	stackCount := make(map[string]int)
-	for _, g := range gs {
-		stackCount[g]++
-		n++
-	}
-
-	t.Logf("num goroutines = %d", n)
-	if n > 0 {
-		t.Error("Too many goroutines.")
-		for stack, count := range stackCount {
-			t.Logf("%d instances of:\n%s", count, stack)
-		}
-	}
-}
-
-func afterTest(t *testing.T) {
-	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
-	if testing.Short() {
-		return
-	}
-	var bad string
-	badSubstring := map[string]string{
-		").readLoop(":                                  "a Transport",
-		").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",
-	}
-	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)
-}

+ 2 - 2
main.go

@@ -7,8 +7,8 @@ import (
 	"strconv"
 	"time"
 
-	etcdserver "github.com/coreos/etcd/etcdserver2"
-	"github.com/coreos/etcd/etcdserver2/etcdhttp"
+	"github.com/coreos/etcd/etcdserver"
+	"github.com/coreos/etcd/etcdserver/etcdhttp"
 	"github.com/coreos/etcd/raft"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/store"

+ 0 - 93
tests/functional/discovery_test.go

@@ -1,93 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"errors"
-	"fmt"
-	"net/http"
-	"net/http/httptest"
-	"net/url"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-
-	"github.com/coreos/etcd/server"
-	etcdtest "github.com/coreos/etcd/tests"
-	goetcd "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-type garbageHandler struct {
-	t       *testing.T
-	success bool
-	sync.Mutex
-}
-
-func (g *garbageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintln(w, "Hello, client")
-	if r.URL.String() != "/v2/keys/_etcd/registry/1/node1" {
-		g.t.Fatalf("Unexpected web request")
-	}
-	g.Lock()
-	defer g.Unlock()
-
-	g.success = true
-}
-
-// TestDiscoverySecondPeerFirstNoResponse ensures that if the first etcd
-// machine stops after heartbeating that the second machine fails too.
-func TestDiscoverySecondPeerFirstNoResponse(t *testing.T) {
-	etcdtest.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "started")
-		resp, err := etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/2/_state"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusCreated)
-
-		v = url.Values{}
-		v.Set("value", "http://127.0.0.1:49151")
-		resp, err = etcdtest.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/_etcd/registry/2/ETCDTEST"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusCreated)
-
-		proc, err := startServer([]string{"-retry-interval", "0.2", "-discovery", s.URL() + "/v2/keys/_etcd/registry/2"})
-		if err != nil {
-			t.Fatal(err.Error())
-		}
-		defer stopServer(proc)
-
-		// TODO(bp): etcd will take 30 seconds to shutdown, figure this
-		// out instead
-		time.Sleep(1 * time.Second)
-
-		client := http.Client{}
-		_, err = client.Get("/")
-		if err != nil && strings.Contains(err.Error(), "connection reset by peer") {
-			t.Fatal(err.Error())
-		}
-	})
-}
-
-func assertServerNotUp(client http.Client, scheme string) error {
-	path := fmt.Sprintf("%s://127.0.0.1:4001/v2/keys/foo", scheme)
-	fields := url.Values(map[string][]string{"value": {"bar"}})
-
-	for i := 0; i < 10; i++ {
-		time.Sleep(1 * time.Second)
-
-		_, err := client.PostForm(path, fields)
-		if err == nil {
-			return errors.New("Expected error during POST, got nil")
-		} else {
-			errString := err.Error()
-			if strings.Contains(errString, "connection refused") {
-				return nil
-			} else {
-				return err
-			}
-		}
-	}
-
-	return nil
-}

+ 0 - 36
tests/functional/etcd_direct_call.go

@@ -1,36 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"net/http"
-	"os"
-	"testing"
-	"time"
-)
-
-func BenchmarkEtcdDirectCall(b *testing.B) {
-	templateBenchmarkEtcdDirectCall(b, false)
-}
-
-func BenchmarkEtcdDirectCallTls(b *testing.B) {
-	templateBenchmarkEtcdDirectCall(b, true)
-}
-
-func templateBenchmarkEtcdDirectCall(b *testing.B, tls bool) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 3
-	_, etcds, _ := CreateCluster(clusterSize, procAttr, tls)
-
-	defer DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		resp, _ := http.Get("http://127.0.0.1:4001/test/speed")
-		resp.Body.Close()
-	}
-}

+ 0 - 270
tests/functional/etcd_tls_test.go

@@ -1,270 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"crypto/tls"
-	"crypto/x509"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"net/url"
-	"os"
-	"strings"
-	"testing"
-	"time"
-)
-
-// TestTLSOff asserts that non-TLS-encrypted communication between the
-// etcd server and an unauthenticated client works
-func TestTLSOff(t *testing.T) {
-	proc, err := startServer([]string{})
-	if err != nil {
-		t.Fatal(err.Error())
-	}
-	defer stopServer(proc)
-
-	client := buildClient()
-	err = assertServerFunctional(client, "http")
-	if err != nil {
-		t.Fatal(err.Error())
-	}
-}
-
-// TestTLSAnonymousClient asserts that TLS-encrypted communication between the etcd
-// server and an anonymous client works
-func TestTLSAnonymousClient(t *testing.T) {
-	proc, err := startServer([]string{
-		"-cert-file=../../fixtures/ca/server.crt",
-		"-key-file=../../fixtures/ca/server.key.insecure",
-	})
-	if err != nil {
-		t.Fatal(err.Error())
-	}
-	defer stopServer(proc)
-
-	cacertfile := "../../fixtures/ca/ca.crt"
-
-	cp := x509.NewCertPool()
-	bytes, err := ioutil.ReadFile(cacertfile)
-	if err != nil {
-		panic(err)
-	}
-	cp.AppendCertsFromPEM(bytes)
-
-	cfg := tls.Config{}
-	cfg.RootCAs = cp
-
-	client := buildTLSClient(&cfg)
-	err = assertServerFunctional(client, "https")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// TestTLSAuthenticatedClient asserts that TLS-encrypted communication
-// between the etcd server and an authenticated client works
-func TestTLSAuthenticatedClient(t *testing.T) {
-	proc, err := startServer([]string{
-		"-cert-file=../../fixtures/ca/server.crt",
-		"-key-file=../../fixtures/ca/server.key.insecure",
-		"-ca-file=../../fixtures/ca/ca.crt",
-	})
-	if err != nil {
-		t.Fatal(err.Error())
-	}
-	defer stopServer(proc)
-
-	cacertfile := "../../fixtures/ca/ca.crt"
-	certfile := "../../fixtures/ca/server2.crt"
-	keyfile := "../../fixtures/ca/server2.key.insecure"
-
-	cert, err := tls.LoadX509KeyPair(certfile, keyfile)
-	if err != nil {
-		panic(err)
-	}
-
-	cp := x509.NewCertPool()
-	bytes, err := ioutil.ReadFile(cacertfile)
-	if err != nil {
-		panic(err)
-	}
-	cp.AppendCertsFromPEM(bytes)
-
-	cfg := tls.Config{}
-	cfg.Certificates = []tls.Certificate{cert}
-	cfg.RootCAs = cp
-
-	time.Sleep(time.Second)
-
-	client := buildTLSClient(&cfg)
-	err = assertServerFunctional(client, "https")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-// TestTLSUnathenticatedClient asserts that TLS-encrypted communication
-// between the etcd server and an unauthenticated client fails
-func TestTLSUnauthenticatedClient(t *testing.T) {
-	proc, err := startServer([]string{
-		"-cert-file=../../fixtures/ca/server.crt",
-		"-key-file=../../fixtures/ca/server.key.insecure",
-		"-ca-file=../../fixtures/ca/ca.crt",
-	})
-	if err != nil {
-		t.Fatal(err.Error())
-	}
-	defer stopServer(proc)
-
-	cacertfile := "../../fixtures/ca/ca.crt"
-	certfile := "../../fixtures/ca/broken_server.crt"
-	keyfile := "../../fixtures/ca/broken_server.key.insecure"
-
-	cert, err := tls.LoadX509KeyPair(certfile, keyfile)
-	if err != nil {
-		panic(err)
-	}
-
-	cp := x509.NewCertPool()
-	bytes, err := ioutil.ReadFile(cacertfile)
-	if err != nil {
-		panic(err)
-	}
-	cp.AppendCertsFromPEM(bytes)
-
-	cfg := tls.Config{}
-	cfg.Certificates = []tls.Certificate{cert}
-	cfg.RootCAs = cp
-
-	time.Sleep(time.Second)
-
-	client := buildTLSClient(&cfg)
-	err = assertServerNotFunctional(client, "https")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func buildClient() http.Client {
-	return http.Client{}
-}
-
-func buildTLSClient(tlsConf *tls.Config) http.Client {
-	tr := http.Transport{TLSClientConfig: tlsConf}
-	return http.Client{Transport: &tr}
-}
-
-func startServer(extra []string) (*os.Process, error) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	cmd := []string{"etcd", "-f", "-data-dir=/tmp/node1", "-name=node1"}
-	cmd = append(cmd, extra...)
-
-	println(strings.Join(cmd, " "))
-
-	return os.StartProcess(EtcdBinPath, cmd, procAttr)
-}
-
-// TODO(yichengq): refactor these helper functions in #645
-func startServer2(extra []string) (*os.Process, error) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	cmd := []string{"etcd", "-f", "-data-dir=/tmp/node2", "-name=node2"}
-	cmd = append(cmd, extra...)
-
-	fmt.Println(strings.Join(cmd, " "))
-
-	return os.StartProcess(EtcdBinPath, cmd, procAttr)
-}
-
-func startServerWithDataDir(extra []string) (*os.Process, error) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	cmd := []string{"etcd", "-data-dir=/tmp/node1", "-name=node1"}
-	cmd = append(cmd, extra...)
-
-	fmt.Println(strings.Join(cmd, " "))
-
-	return os.StartProcess(EtcdBinPath, cmd, procAttr)
-}
-
-func startServer2WithDataDir(extra []string) (*os.Process, error) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	cmd := []string{"etcd", "-data-dir=/tmp/node2", "-name=node2"}
-	cmd = append(cmd, extra...)
-
-	println(strings.Join(cmd, " "))
-
-	return os.StartProcess(EtcdBinPath, cmd, procAttr)
-}
-
-func stopServer(proc *os.Process) {
-	err := proc.Kill()
-	if err != nil {
-		panic(err.Error())
-	}
-	proc.Release()
-}
-
-func assertServerFunctional(client http.Client, scheme string) error {
-	path := fmt.Sprintf("%s://127.0.0.1:4001/v2/keys/foo", scheme)
-	fields := url.Values(map[string][]string{"value": {"bar"}})
-
-	for i := 0; i < 10; i++ {
-		time.Sleep(1 * time.Second)
-
-		resp, err := client.PostForm(path, fields)
-		// If the status is Temporary Redirect, we should follow the
-		// new location, because the request did not go to the leader yet.
-		// TODO(yichengq): the difference between Temporary Redirect(307)
-		// and Created(201) could distinguish between leader and followers
-		for err == nil && resp.StatusCode == http.StatusTemporaryRedirect {
-			loc, _ := resp.Location()
-			newPath := loc.String()
-			resp, err = client.PostForm(newPath, fields)
-		}
-
-		if err == nil {
-			// Internal error may mean that servers are in leader election
-			if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusInternalServerError {
-				return errors.New(fmt.Sprintf("resp.StatusCode == %s", resp.Status))
-			} else {
-				return nil
-			}
-		}
-	}
-
-	return errors.New("etcd server was not reachable in time / had internal error")
-}
-
-func assertServerNotFunctional(client http.Client, scheme string) error {
-	path := fmt.Sprintf("%s://127.0.0.1:4001/v2/keys/foo", scheme)
-	fields := url.Values(map[string][]string{"value": {"bar"}})
-
-	for i := 0; i < 10; i++ {
-		time.Sleep(1 * time.Second)
-
-		_, err := client.PostForm(path, fields)
-		if err == nil {
-			return errors.New("Expected error during POST, got nil")
-		} else {
-			errString := err.Error()
-			if strings.Contains(errString, "connection refused") {
-				continue
-			} else if strings.Contains(errString, "bad certificate") {
-				return nil
-			} else {
-				return err
-			}
-		}
-	}
-
-	return errors.New("Expected server to fail with 'bad certificate'")
-}

+ 0 - 19
tests/functional/init.go

@@ -1,19 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"go/build"
-	"os"
-	"path/filepath"
-)
-
-var EtcdBinPath string
-
-func init() {
-	// Initialize the 'etcd' binary path or default it to the etcd diretory.
-	EtcdBinPath = os.Getenv("ETCD_BIN_PATH")
-	if EtcdBinPath == "" {
-		EtcdBinPath = filepath.Join(build.Default.GOPATH, "src", "github.com", "coreos", "etcd", "etcd")
-	}
-}

+ 0 - 65
tests/functional/internal_version_test.go

@@ -1,65 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"fmt"
-	"net/http"
-	"net/http/httptest"
-	"net/url"
-	"os"
-	"sync"
-	"testing"
-	"time"
-)
-
-// Ensure that etcd does not come up if the internal raft versions do not match.
-func TestInternalVersion(t *testing.T) {
-	var mu sync.Mutex
-
-	checkedVersion := false
-	testMux := http.NewServeMux()
-
-	testMux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
-		fmt.Fprintln(w, "This is not a version number")
-		mu.Lock()
-		defer mu.Unlock()
-
-		checkedVersion = true
-	})
-
-	testMux.HandleFunc("/join", func(w http.ResponseWriter, r *http.Request) {
-		t.Fatal("should not attempt to join!")
-	})
-
-	ts := httptest.NewServer(testMux)
-	defer ts.Close()
-
-	fakeURL, _ := url.Parse(ts.URL)
-
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-	args := []string{"etcd", "-name=node1", "-f", "-data-dir=/tmp/node1", "-peers=" + fakeURL.Host}
-
-	process, err := os.StartProcess(EtcdBinPath, args, procAttr)
-	if err != nil {
-		t.Fatal("start process failed:" + err.Error())
-		return
-	}
-
-	time.Sleep(time.Second)
-	process.Kill()
-
-	_, err = http.Get("http://127.0.0.1:4001")
-	if err == nil {
-		t.Fatal("etcd node should not be up")
-		return
-	}
-
-	mu.Lock()
-	defer mu.Unlock()
-	if checkedVersion == false {
-		t.Fatal("etcd did not check the version")
-		return
-	}
-}

+ 0 - 103
tests/functional/kill_leader_test.go

@@ -1,103 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"bytes"
-	"fmt"
-	"os"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// This test will kill the current leader and wait for the etcd cluster to elect a new leader for 200 times.
-// It will print out the election time and the average election time.
-// It runs in a cluster with standby nodes.
-func TestKillLeaderWithStandbys(t *testing.T) {
-	// https://github.com/goraft/raft/issues/222
-	t.Skip("stuck on raft issue")
-
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-	defer DestroyCluster(etcds)
-
-	stop := make(chan bool)
-	leaderChan := make(chan string, 1)
-	all := make(chan bool, 1)
-
-	time.Sleep(time.Second)
-
-	go Monitor(clusterSize, 1, leaderChan, all, stop)
-
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	// Reconfigure with a small active size.
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":3, "removeDelay":2, "syncInterval":1}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	// Wait for two monitor cycles before checking for demotion.
-	time.Sleep((2 * server.ActiveMonitorTimeout) + (2 * time.Second))
-
-	// Verify that we have 3 peers.
-	result, err := c.Get("_etcd/machines", true, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 3)
-
-	var totalTime time.Duration
-
-	leader := "http://127.0.0.1:7001"
-
-	for i := 0; i < clusterSize; i++ {
-		t.Log("leader is ", leader)
-		port, _ := strconv.Atoi(strings.Split(leader, ":")[2])
-		num := port - 7001
-		t.Log("kill server ", num)
-		etcds[num].Kill()
-		etcds[num].Release()
-
-		start := time.Now()
-		for {
-			newLeader := <-leaderChan
-			if newLeader != leader {
-				leader = newLeader
-				break
-			}
-		}
-		take := time.Now().Sub(start)
-
-		totalTime += take
-		avgTime := totalTime / (time.Duration)(i+1)
-		fmt.Println("Total time:", totalTime, "; Avg time:", avgTime)
-
-		time.Sleep(server.ActiveMonitorTimeout + (1 * time.Second))
-		time.Sleep(2 * time.Second)
-
-		// Verify that we have 3 peers.
-		result, err = c.Get("_etcd/machines", true, true)
-		assert.NoError(t, err)
-		assert.Equal(t, len(result.Node.Nodes), 3)
-
-		// Verify that killed node is not one of those peers.
-		_, err = c.Get(fmt.Sprintf("_etcd/machines/node%d", num+1), false, false)
-		assert.Error(t, err)
-
-		etcds[num], err = os.StartProcess(EtcdBinPath, argGroup[num], procAttr)
-	}
-	stop <- true
-}

+ 0 - 248
tests/functional/multi_node_kill_all_and_recovery_test.go

@@ -1,248 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"bytes"
-	"os"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// TestTLSMultiNodeKillAllAndRecovery create a five nodes
-// then kill all the nodes and restart
-func TestTLSMultiNodeKillAllAndRecovery(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	stop := make(chan bool)
-	leaderChan := make(chan string, 1)
-	all := make(chan bool, 1)
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, true)
-	defer DestroyCluster(etcds)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	go Monitor(clusterSize, clusterSize, leaderChan, all, stop)
-	<-all
-	<-leaderChan
-	stop <- true
-
-	c.SyncCluster()
-
-	// send 10 commands
-	for i := 0; i < 10; i++ {
-		// Test Set
-		_, err := c.Set("foo", "bar", 0)
-		if err != nil {
-			panic(err)
-		}
-	}
-
-	time.Sleep(time.Second)
-
-	// kill all
-	DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	stop = make(chan bool)
-	leaderChan = make(chan string, 1)
-	all = make(chan bool, 1)
-
-	time.Sleep(time.Second)
-
-	for i := 0; i < clusterSize; i++ {
-		etcds[i], err = os.StartProcess(EtcdBinPath, argGroup[i], procAttr)
-		// See util.go for the reason to wait for server
-		client := buildClient()
-		err = WaitForServer("127.0.0.1:400"+strconv.Itoa(i+1), client, "http")
-		if err != nil {
-			t.Fatalf("node start error: %s", err)
-		}
-	}
-
-	go Monitor(clusterSize, 1, leaderChan, all, stop)
-
-	<-all
-	<-leaderChan
-
-	result, err := c.Set("foo", "bar", 0)
-
-	if err != nil {
-		t.Fatalf("Recovery error: %s", err)
-	}
-
-	if result.Node.ModifiedIndex != 17 {
-		t.Fatalf("recovery failed! [%d/17]", result.Node.ModifiedIndex)
-	}
-}
-
-// Create a five-node cluster
-// Kill all the nodes and restart
-func TestMultiNodeKillAllAndRecoveryWithStandbys(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	stop := make(chan bool)
-	leaderChan := make(chan string, 1)
-	all := make(chan bool, 1)
-
-	clusterSize := 15
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-	defer DestroyCluster(etcds)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	c := etcd.NewClient(nil)
-
-	go Monitor(clusterSize, clusterSize, leaderChan, all, stop)
-	<-all
-	<-leaderChan
-	stop <- true
-
-	c.SyncCluster()
-
-	// Reconfigure with smaller active size (7 nodes) and wait for remove.
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":7}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	time.Sleep(2*server.ActiveMonitorTimeout + (1 * time.Second))
-
-	// Verify that there is three machines in peer mode.
-	result, err := c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 7)
-
-	// send set commands
-	for i := 0; i < 2*clusterSize; i++ {
-		// Test Set
-		_, err := c.Set("foo", "bar", 0)
-		if err != nil {
-			panic(err)
-		}
-	}
-
-	time.Sleep(time.Second)
-
-	// kill all
-	DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	stop = make(chan bool)
-	leaderChan = make(chan string, 1)
-	all = make(chan bool, 1)
-
-	time.Sleep(time.Second)
-
-	for i := 0; i < clusterSize; i++ {
-		etcds[i], err = os.StartProcess(EtcdBinPath, append(argGroup[i], "-peers="), procAttr)
-	}
-
-	time.Sleep(2 * time.Second)
-
-	// send set commands
-	for i := 0; i < 2*clusterSize; i++ {
-		// Test Set
-		_, err := c.Set("foo", "bar", 0)
-		if err != nil {
-			t.Fatalf("Recovery error: %s", err)
-		}
-	}
-
-	// Verify that we have seven machines.
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 7)
-}
-
-// Create a five nodes
-// Kill all the nodes and restart, then remove the leader
-func TestMultiNodeKillAllAndRecoveryAndRemoveLeader(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	stop := make(chan bool)
-	leaderChan := make(chan string, 1)
-	all := make(chan bool, 1)
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-	defer DestroyCluster(etcds)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	c := etcd.NewClient(nil)
-
-	go Monitor(clusterSize, clusterSize, leaderChan, all, stop)
-	<-all
-	<-leaderChan
-	stop <- true
-
-	// It needs some time to sync current commits and write it to disk.
-	// Or some instance may be restarted as a new peer, and we don't support
-	// to connect back the old cluster that doesn't have majority alive
-	// without log now.
-	time.Sleep(time.Second)
-
-	c.SyncCluster()
-
-	// kill all
-	DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	stop = make(chan bool)
-	leaderChan = make(chan string, 1)
-	all = make(chan bool, 1)
-
-	time.Sleep(time.Second)
-
-	for i := 0; i < clusterSize; i++ {
-		etcds[i], err = os.StartProcess(EtcdBinPath, argGroup[i], procAttr)
-	}
-
-	go Monitor(clusterSize, 1, leaderChan, all, stop)
-
-	<-all
-	leader := <-leaderChan
-
-	_, err = c.Set("foo", "bar", 0)
-	if err != nil {
-		t.Fatalf("Recovery error: %s", err)
-	}
-
-	port, _ := strconv.Atoi(strings.Split(leader, ":")[2])
-	num := port - 7000
-	resp, _ := tests.Delete(leader+"/v2/admin/machines/node"+strconv.Itoa(num), "application/json", nil)
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	// check the old leader is in standby mode now
-	time.Sleep(time.Second)
-	resp, _ = tests.Get(leader + "/name")
-	assert.Equal(t, resp.StatusCode, 404)
-}

+ 0 - 195
tests/functional/rejoin_test.go

@@ -1,195 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"fmt"
-	"math/rand"
-	"os"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-func increasePeerAddressPort(args []string, delta int) []string {
-	for i, arg := range args {
-		if !strings.Contains(arg, "peer-addr") {
-			continue
-		}
-		splitArg := strings.Split(arg, ":")
-		port, _ := strconv.Atoi(splitArg[len(splitArg)-1])
-		args[i] = "-peer-addr=127.0.0.1:" + strconv.Itoa(port+delta)
-		return args
-	}
-	return append(args, "-peer-addr=127.0.0.1:"+strconv.Itoa(7001+delta))
-}
-
-func increaseAddressPort(args []string, delta int) []string {
-	for i, arg := range args {
-		if !strings.HasPrefix(arg, "-addr") && !strings.HasPrefix(arg, "--addr") {
-			continue
-		}
-		splitArg := strings.Split(arg, ":")
-		port, _ := strconv.Atoi(splitArg[len(splitArg)-1])
-		args[i] = "-addr=127.0.0.1:" + strconv.Itoa(port+delta)
-		return args
-	}
-	return append(args, "-addr=127.0.0.1:"+strconv.Itoa(4001+delta))
-}
-
-func increaseDataDir(args []string, delta int) []string {
-	for i, arg := range args {
-		if !strings.Contains(arg, "-data-dir") {
-			continue
-		}
-		splitArg := strings.Split(arg, "node")
-		idx, _ := strconv.Atoi(splitArg[len(splitArg)-1])
-		args[i] = "-data-dir=/tmp/node" + strconv.Itoa(idx+delta)
-		return args
-	}
-	return args
-}
-
-// Create a five-node cluster
-// Random kill one of the nodes and restart it with different peer address
-func TestRejoinWithDifferentPeerAddress(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	defer DestroyCluster(etcds)
-
-	time.Sleep(2 * time.Second)
-
-	for i := 0; i < 10; i++ {
-		num := rand.Int() % clusterSize
-		fmt.Println("kill node", num+1)
-
-		etcds[num].Kill()
-		etcds[num].Release()
-		time.Sleep(time.Second)
-
-		argGroup[num] = increasePeerAddressPort(argGroup[num], clusterSize)
-		// restart
-		etcds[num], err = os.StartProcess(EtcdBinPath, argGroup[num], procAttr)
-		if err != nil {
-			panic(err)
-		}
-		time.Sleep(time.Second)
-	}
-
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-	result, err := c.Set("foo", "bar", 0)
-	if err != nil || result.Node.Key != "/foo" || result.Node.Value != "bar" {
-		t.Fatal("Failed to set value in etcd cluster")
-	}
-}
-
-// Create a five-node cluster
-// Replace one of the nodes with different peer address
-func TestReplaceWithDifferentPeerAddress(t *testing.T) {
-	// TODO(yichengq): find some way to avoid the error that will be
-	// caused if some node joins the cluster with the collided name.
-	// Possible solutions:
-	// 1. Remove itself when executing a join command with the same name
-	// and different peer address. However, it should find some way to
-	// trigger that execution because the leader may update its address
-	// and stop heartbeat.
-	// 2. Remove the node with the same name before join each time.
-	// But this way could be rather overkill.
-	t.Skip("Unimplemented functionality")
-
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	defer DestroyCluster(etcds)
-
-	time.Sleep(2 * time.Second)
-
-	rand.Int()
-	for i := 0; i < 10; i++ {
-		num := rand.Int() % clusterSize
-		fmt.Println("replace node", num+1)
-
-		argGroup[num] = increasePeerAddressPort(argGroup[num], clusterSize)
-		argGroup[num] = increaseAddressPort(argGroup[num], clusterSize)
-		argGroup[num] = increaseDataDir(argGroup[num], clusterSize)
-		// restart
-		newEtcd, err := os.StartProcess(EtcdBinPath, append(argGroup[num], "-f"), procAttr)
-		if err != nil {
-			panic(err)
-		}
-
-		etcds[num].Wait()
-		etcds[num] = newEtcd
-	}
-
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-	result, err := c.Set("foo", "bar", 0)
-	if err != nil || result.Node.Key != "/foo" || result.Node.Value != "bar" {
-		t.Fatal("Failed to set value in etcd cluster")
-	}
-}
-
-// Create a five-node cluster
-// Let the sixth instance join with different name and existing peer address
-func TestRejoinWithDifferentName(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 5
-	argGroup, etcds, err := CreateCluster(clusterSize, procAttr, false)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	defer DestroyCluster(etcds)
-
-	time.Sleep(2 * time.Second)
-
-	num := rand.Int() % clusterSize
-	fmt.Println("join node 6 that collides with node", num+1)
-
-	// kill
-	etcds[num].Kill()
-	etcds[num].Release()
-	time.Sleep(time.Second)
-
-	for i := 0; i < 2; i++ {
-		// restart
-		if i == 0 {
-			etcds[num], err = os.StartProcess(EtcdBinPath, append(argGroup[num], "-name=node6", "-peers=127.0.0.1:7002"), procAttr)
-		} else {
-			etcds[num], err = os.StartProcess(EtcdBinPath, append(argGroup[num], "-f", "-name=node6", "-peers=127.0.0.1:7002"), procAttr)
-		}
-		if err != nil {
-			t.Fatal("failed to start process:", err)
-		}
-
-		timer := time.AfterFunc(10*time.Second, func() {
-			t.Fatal("new etcd should fail immediately")
-		})
-		etcds[num].Wait()
-		etcds[num] = nil
-		timer.Stop()
-	}
-}

+ 0 - 200
tests/functional/remove_node_test.go

@@ -1,200 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"bytes"
-	"fmt"
-	"math/rand"
-	"net/http"
-	"os"
-	"syscall"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// remove the node and node rejoin with previous log
-func TestRemoveNode(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 4
-	argGroup, etcds, _ := CreateCluster(clusterSize, procAttr, false)
-	defer DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	c.SyncCluster()
-
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":4, "syncInterval":5}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	rmReq, _ := http.NewRequest("DELETE", "http://127.0.0.1:7001/remove/node3", nil)
-
-	client := &http.Client{}
-	for i := 0; i < 2; i++ {
-		for i := 0; i < 2; i++ {
-			client.Do(rmReq)
-
-			fmt.Println("send remove to node3 and wait for its exiting")
-			time.Sleep(100 * time.Millisecond)
-
-			resp, err := c.Get("_etcd/machines", false, false)
-
-			if err != nil {
-				panic(err)
-			}
-
-			if len(resp.Node.Nodes) != 3 {
-				t.Fatal("cannot remove peer")
-			}
-
-			etcds[2].Kill()
-			etcds[2].Wait()
-
-			if i == 1 {
-				// rejoin with log
-				etcds[2], err = os.StartProcess(EtcdBinPath, argGroup[2], procAttr)
-			} else {
-				// rejoin without log
-				etcds[2], err = os.StartProcess(EtcdBinPath, append(argGroup[2], "-f"), procAttr)
-			}
-
-			if err != nil {
-				panic(err)
-			}
-
-			time.Sleep(time.Second + 5*time.Second)
-
-			resp, err = c.Get("_etcd/machines", false, false)
-
-			if err != nil {
-				panic(err)
-			}
-
-			if len(resp.Node.Nodes) != 4 {
-				t.Fatalf("add peer fails #1 (%d != 4)", len(resp.Node.Nodes))
-			}
-		}
-
-		// first kill the node, then remove it, then add it back
-		for i := 0; i < 2; i++ {
-			etcds[2].Kill()
-			fmt.Println("kill node3 and wait for its exiting")
-			etcds[2].Wait()
-
-			client.Do(rmReq)
-
-			time.Sleep(100 * time.Millisecond)
-
-			resp, err := c.Get("_etcd/machines", false, false)
-
-			if err != nil {
-				panic(err)
-			}
-
-			if len(resp.Node.Nodes) != 3 {
-				t.Fatal("cannot remove peer")
-			}
-
-			if i == 1 {
-				// rejoin with log
-				etcds[2], err = os.StartProcess(EtcdBinPath, append(argGroup[2]), procAttr)
-			} else {
-				// rejoin without log
-				etcds[2], err = os.StartProcess(EtcdBinPath, append(argGroup[2], "-f"), procAttr)
-			}
-
-			if err != nil {
-				panic(err)
-			}
-
-			time.Sleep(time.Second + time.Second)
-
-			resp, err = c.Get("_etcd/machines", false, false)
-
-			if err != nil {
-				panic(err)
-			}
-
-			if len(resp.Node.Nodes) != 4 {
-				t.Fatalf("add peer fails #2 (%d != 4)", len(resp.Node.Nodes))
-			}
-		}
-	}
-}
-
-func TestRemovePausedNode(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 4
-	_, etcds, _ := CreateCluster(clusterSize, procAttr, false)
-	defer DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	c.SyncCluster()
-
-	r, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":3, "removeDelay":1, "syncInterval":1}`))
-	if !assert.Equal(t, r.StatusCode, 200) {
-		t.FailNow()
-	}
-	// Wait for standby instances to update its cluster config
-	time.Sleep(6 * time.Second)
-
-	resp, err := c.Get("_etcd/machines", false, false)
-	if err != nil {
-		panic(err)
-	}
-	if len(resp.Node.Nodes) != 3 {
-		t.Fatal("cannot remove peer")
-	}
-
-	for i := 0; i < clusterSize; i++ {
-		// first pause the node, then remove it, then resume it
-		idx := rand.Int() % clusterSize
-
-		etcds[idx].Signal(syscall.SIGSTOP)
-		fmt.Printf("pause node%d and let standby node take its place\n", idx+1)
-
-		time.Sleep(4 * time.Second)
-
-		etcds[idx].Signal(syscall.SIGCONT)
-		// let it change its state to candidate at least
-		time.Sleep(time.Second)
-
-		stop := make(chan bool)
-		leaderChan := make(chan string, 1)
-		all := make(chan bool, 1)
-
-		go Monitor(clusterSize, clusterSize, leaderChan, all, stop)
-		<-all
-		<-leaderChan
-		stop <- true
-
-		resp, err = c.Get("_etcd/machines", false, false)
-		if err != nil {
-			panic(err)
-		}
-		if len(resp.Node.Nodes) != 3 {
-			t.Fatalf("add peer fails (%d != 3)", len(resp.Node.Nodes))
-		}
-		for i := 0; i < 3; i++ {
-			if resp.Node.Nodes[i].Key == fmt.Sprintf("node%d", idx+1) {
-				t.Fatal("node should be removed")
-			}
-		}
-	}
-}

+ 0 - 67
tests/functional/simple_multi_node_test.go

@@ -1,67 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"os"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-func TestSimpleMultiNode(t *testing.T) {
-	templateTestSimpleMultiNode(t, false)
-}
-
-func TestSimpleMultiNodeTls(t *testing.T) {
-	templateTestSimpleMultiNode(t, true)
-}
-
-// Create a three nodes and try to set value
-func templateTestSimpleMultiNode(t *testing.T, tls bool) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	clusterSize := 3
-
-	_, etcds, err := CreateCluster(clusterSize, procAttr, tls)
-
-	if err != nil {
-		t.Fatalf("cannot create cluster: %v", err)
-	}
-
-	defer DestroyCluster(etcds)
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	if c.SyncCluster() == false {
-		t.Fatal("Cannot sync cluster!")
-	}
-
-	// Test Set
-	result, err := c.Set("foo", "bar", 100)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	node := result.Node
-	if node.Key != "/foo" || node.Value != "bar" || node.TTL < 95 {
-		t.Fatalf("Set 1 failed with %s %s %v", node.Key, node.Value, node.TTL)
-	}
-
-	time.Sleep(time.Second)
-
-	result, err = c.Set("foo", "bar", 100)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	node = result.Node
-	if node.Key != "/foo" || node.Value != "bar" || node.TTL < 95 {
-		t.Fatalf("Set 2 failed with %s %s %v", node.Key, node.Value, node.TTL)
-	}
-
-}

+ 0 - 151
tests/functional/simple_snapshot_test.go

@@ -1,151 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"io/ioutil"
-	"os"
-	"strconv"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-// This test creates a single node and then set a value to it to trigger snapshot
-func TestSnapshot(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-	args := []string{"etcd", "-name=node1", "-data-dir=/tmp/node1", "-snapshot=true", "-snapshot-count=500"}
-
-	process, err := os.StartProcess(EtcdBinPath, append(args, "-f"), procAttr)
-	if err != nil {
-		t.Fatal("start process failed:" + err.Error())
-	}
-	defer process.Kill()
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	c.SyncCluster()
-	// issue first 501 commands
-	for i := 0; i < 501; i++ {
-		result, err := c.Set("foo", "bar", 100)
-		node := result.Node
-
-		if err != nil || node.Key != "/foo" || node.Value != "bar" || node.TTL < 95 {
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			t.Fatalf("Set failed with %s %s %v", node.Key, node.Value, node.TTL)
-		}
-	}
-
-	// wait for a snapshot interval
-	time.Sleep(3 * time.Second)
-
-	snapshots, err := ioutil.ReadDir("/tmp/node1/snapshot")
-
-	if err != nil {
-		t.Fatal("list snapshot failed:" + err.Error())
-	}
-
-	if len(snapshots) != 1 {
-		t.Fatal("wrong number of snapshot :[1/", len(snapshots), "]")
-	}
-
-	index, _ := strconv.Atoi(snapshots[0].Name()[2:5])
-
-	if index < 503 || index > 516 {
-		t.Fatal("wrong name of snapshot :", snapshots[0].Name())
-	}
-
-	// issue second 501 commands
-	for i := 0; i < 501; i++ {
-		result, err := c.Set("foo", "bar", 100)
-		node := result.Node
-
-		if err != nil || node.Key != "/foo" || node.Value != "bar" || node.TTL < 95 {
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			t.Fatalf("Set failed with %s %s %v", node.Key, node.Value, node.TTL)
-		}
-	}
-
-	// wait for a snapshot interval
-	time.Sleep(3 * time.Second)
-
-	snapshots, err = ioutil.ReadDir("/tmp/node1/snapshot")
-
-	if err != nil {
-		t.Fatal("list snapshot failed:" + err.Error())
-	}
-
-	if len(snapshots) != 1 {
-		t.Fatal("wrong number of snapshot :[1/", len(snapshots), "]")
-	}
-
-	index, _ = strconv.Atoi(snapshots[0].Name()[2:6])
-
-	if index < 1010 || index > 1029 {
-		t.Fatal("wrong name of snapshot :", snapshots[0].Name())
-	}
-}
-
-// TestSnapshotRestart tests etcd restarts with snapshot file
-func TestSnapshotRestart(t *testing.T) {
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-	args := []string{"etcd", "-name=node1", "-data-dir=/tmp/node1", "-snapshot=true", "-snapshot-count=500"}
-
-	process, err := os.StartProcess(EtcdBinPath, append(args, "-f"), procAttr)
-	if err != nil {
-		t.Fatal("start process failed:" + err.Error())
-	}
-
-	time.Sleep(time.Second)
-
-	c := etcd.NewClient(nil)
-
-	c.SyncCluster()
-	// issue first 501 commands
-	for i := 0; i < 501; i++ {
-		result, err := c.Set("foo", "bar", 100)
-		node := result.Node
-
-		if err != nil || node.Key != "/foo" || node.Value != "bar" || node.TTL < 95 {
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			t.Fatalf("Set failed with %s %s %v", node.Key, node.Value, node.TTL)
-		}
-	}
-
-	// wait for a snapshot interval
-	time.Sleep(3 * time.Second)
-
-	_, err = ioutil.ReadDir("/tmp/node1/snapshot")
-	if err != nil {
-		t.Fatal("list snapshot failed:" + err.Error())
-	}
-
-	process.Kill()
-
-	process, err = os.StartProcess(EtcdBinPath, args, procAttr)
-	if err != nil {
-		t.Fatal("start process failed:" + err.Error())
-	}
-	defer process.Kill()
-
-	time.Sleep(1 * time.Second)
-
-	_, err = c.Set("foo", "bar", 100)
-	if err != nil {
-		t.Fatal(err)
-	}
-}

+ 0 - 342
tests/functional/standby_test.go

@@ -1,342 +0,0 @@
-// +build ignore
-
-package test
-
-import (
-	"bytes"
-	"fmt"
-	"os"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/store"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Create a full cluster and then change the active size.
-func TestStandby(t *testing.T) {
-	clusterSize := 15
-	_, etcds, err := CreateCluster(clusterSize, &os.ProcAttr{Files: []*os.File{nil, os.Stdout, os.Stderr}}, false)
-	if !assert.NoError(t, err) {
-		t.Fatal("cannot create cluster")
-	}
-	defer DestroyCluster(etcds)
-
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"syncInterval":1}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	time.Sleep(time.Second)
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	// Verify that we just have default machines.
-	result, err := c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 9)
-
-	t.Log("Reconfigure with a smaller active size")
-	resp, _ = tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":7, "syncInterval":1}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	// Wait for two monitor cycles before checking for demotion.
-	time.Sleep((2 * server.ActiveMonitorTimeout) + (2 * time.Second))
-
-	// Verify that we now have seven peers.
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 7)
-
-	t.Log("Test the functionality of all servers")
-	// Set key.
-	time.Sleep(time.Second)
-	if _, err := c.Set("foo", "bar", 0); err != nil {
-		panic(err)
-	}
-	time.Sleep(time.Second)
-
-	// Check that all peers and standbys have the value.
-	for i := range etcds {
-		resp, err := tests.Get(fmt.Sprintf("http://localhost:%d/v2/keys/foo", 4000+(i+1)))
-		if assert.NoError(t, err) {
-			body := tests.ReadBodyJSON(resp)
-			if node, _ := body["node"].(map[string]interface{}); assert.NotNil(t, node) {
-				assert.Equal(t, node["value"], "bar")
-			}
-		}
-	}
-
-	t.Log("Reconfigure with larger active size and wait for join")
-	resp, _ = tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":8, "syncInterval":1}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	time.Sleep((1 * time.Second) + (1 * time.Second))
-
-	// Verify that exactly eight machines are in the cluster.
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 8)
-}
-
-// Create a full cluster, disconnect a peer, wait for removal, wait for standby join.
-func TestStandbyAutoJoin(t *testing.T) {
-	clusterSize := 5
-	_, etcds, err := CreateCluster(clusterSize, &os.ProcAttr{Files: []*os.File{nil, os.Stdout, os.Stderr}}, false)
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-	defer func() {
-		// Wrap this in a closure so that it picks up the updated version of
-		// the "etcds" variable.
-		DestroyCluster(etcds)
-	}()
-
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	time.Sleep(1 * time.Second)
-
-	// Verify that we have five machines.
-	result, err := c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 5)
-
-	// Reconfigure with a short remove delay (2 second).
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"activeSize":4, "removeDelay":2, "syncInterval":1}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	// Wait for a monitor cycle before checking for removal.
-	time.Sleep(server.ActiveMonitorTimeout + (1 * time.Second))
-
-	// Verify that we now have four peers.
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 4)
-
-	// Remove peer.
-	etcd := etcds[1]
-	etcds = append(etcds[:1], etcds[2:]...)
-	if err := etcd.Kill(); err != nil {
-		panic(err.Error())
-	}
-	etcd.Release()
-
-	// Wait for it to get dropped.
-	time.Sleep(server.PeerActivityMonitorTimeout + (1 * time.Second))
-
-	// Wait for the standby to join.
-	time.Sleep((1 * time.Second) + (1 * time.Second))
-
-	// Verify that we have 4 peers.
-	result, err = c.Get("_etcd/machines", true, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 4)
-
-	// Verify that node2 is not one of those peers.
-	_, err = c.Get("_etcd/machines/node2", false, false)
-	assert.Error(t, err)
-}
-
-// Create a full cluster and then change the active size gradually.
-func TestStandbyGradualChange(t *testing.T) {
-	clusterSize := 9
-	_, etcds, err := CreateCluster(clusterSize, &os.ProcAttr{Files: []*os.File{nil, os.Stdout, os.Stderr}}, false)
-	assert.NoError(t, err)
-	defer DestroyCluster(etcds)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	time.Sleep(time.Second)
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	num := clusterSize
-	for inc := 0; inc < 2; inc++ {
-		for i := 0; i < 6; i++ {
-			// Verify that we just have i machines.
-			result, err := c.Get("_etcd/machines", false, true)
-			assert.NoError(t, err)
-			assert.Equal(t, len(result.Node.Nodes), num)
-
-			if inc == 0 {
-				num--
-			} else {
-				num++
-			}
-
-			t.Log("Reconfigure with active size", num)
-			resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(fmt.Sprintf(`{"activeSize":%d, "syncInterval":1}`, num)))
-			if !assert.Equal(t, resp.StatusCode, 200) {
-				t.FailNow()
-			}
-
-			if inc == 0 {
-				// Wait for monitor cycles before checking for demotion.
-				time.Sleep(server.ActiveMonitorTimeout + (1 * time.Second))
-			} else {
-				time.Sleep(time.Second + (1 * time.Second))
-			}
-
-			// Verify that we now have peers.
-			result, err = c.Get("_etcd/machines", false, true)
-			assert.NoError(t, err)
-			assert.Equal(t, len(result.Node.Nodes), num)
-
-			t.Log("Test the functionality of all servers")
-			// Set key.
-			if _, err := c.Set("foo", "bar", 0); err != nil {
-				panic(err)
-			}
-			time.Sleep(100 * time.Millisecond)
-
-			// Check that all peers and standbys have the value.
-			for i := range etcds {
-				resp, err := tests.Get(fmt.Sprintf("http://localhost:%d/v2/keys/foo", 4000+(i+1)))
-				if assert.NoError(t, err) {
-					body := tests.ReadBodyJSON(resp)
-					if node, _ := body["node"].(map[string]interface{}); assert.NotNil(t, node) {
-						assert.Equal(t, node["value"], "bar")
-					}
-				}
-			}
-		}
-	}
-}
-
-// Create a full cluster and then change the active size dramatically.
-func TestStandbyDramaticChange(t *testing.T) {
-	clusterSize := 9
-	_, etcds, err := CreateCluster(clusterSize, &os.ProcAttr{Files: []*os.File{nil, os.Stdout, os.Stderr}}, false)
-	assert.NoError(t, err)
-	defer DestroyCluster(etcds)
-
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-
-	time.Sleep(time.Second)
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	num := clusterSize
-	for i := 0; i < 3; i++ {
-		for inc := 0; inc < 2; inc++ {
-			// Verify that we just have i machines.
-			result, err := c.Get("_etcd/machines", false, true)
-			assert.NoError(t, err)
-			assert.Equal(t, len(result.Node.Nodes), num)
-
-			if inc == 0 {
-				num -= 6
-			} else {
-				num += 6
-			}
-
-			t.Log("Reconfigure with active size", num)
-			resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(fmt.Sprintf(`{"activeSize":%d, "syncInterval":1}`, num)))
-			if !assert.Equal(t, resp.StatusCode, 200) {
-				t.FailNow()
-			}
-
-			if inc == 0 {
-				// Wait for monitor cycles before checking for demotion.
-				time.Sleep(6*server.ActiveMonitorTimeout + (1 * time.Second))
-			} else {
-				time.Sleep(time.Second + (1 * time.Second))
-			}
-
-			// Verify that we now have peers.
-			result, err = c.Get("_etcd/machines", false, true)
-			assert.NoError(t, err)
-			assert.Equal(t, len(result.Node.Nodes), num)
-
-			t.Log("Test the functionality of all servers")
-			// Set key.
-			if _, err := c.Set("foo", "bar", 0); err != nil {
-				panic(err)
-			}
-			time.Sleep(100 * time.Millisecond)
-
-			// Check that all peers and standbys have the value.
-			for i := range etcds {
-				resp, err := tests.Get(fmt.Sprintf("http://localhost:%d/v2/keys/foo", 4000+(i+1)))
-				if assert.NoError(t, err) {
-					body := tests.ReadBodyJSON(resp)
-					if node, _ := body["node"].(map[string]interface{}); assert.NotNil(t, node) {
-						assert.Equal(t, node["value"], "bar")
-					}
-				}
-			}
-		}
-	}
-}
-
-func TestStandbyJoinMiss(t *testing.T) {
-	clusterSize := 2
-	_, etcds, err := CreateCluster(clusterSize, &os.ProcAttr{Files: []*os.File{nil, os.Stdout, os.Stderr}}, false)
-	if err != nil {
-		t.Fatal("cannot create cluster")
-	}
-	defer DestroyCluster(etcds)
-
-	c := etcd.NewClient(nil)
-	c.SyncCluster()
-
-	time.Sleep(1 * time.Second)
-
-	// Verify that we have two machines.
-	result, err := c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), clusterSize)
-
-	resp, _ := tests.Put("http://localhost:7001/v2/admin/config", "application/json", bytes.NewBufferString(`{"removeDelay":4, "syncInterval":4}`))
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-	time.Sleep(time.Second)
-
-	resp, _ = tests.Delete("http://localhost:7001/v2/admin/machines/node2", "application/json", nil)
-	if !assert.Equal(t, resp.StatusCode, 200) {
-		t.FailNow()
-	}
-
-	// Wait for a monitor cycle before checking for removal.
-	time.Sleep(server.ActiveMonitorTimeout + (1 * time.Second))
-
-	// Verify that we now have one peer.
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 1)
-
-	// Simulate the join failure
-	_, err = server.NewClient(nil).AddMachine("http://localhost:7001",
-		&server.JoinCommand{
-			MinVersion: store.MinVersion(),
-			MaxVersion: store.MaxVersion(),
-			Name:       "node2",
-			RaftURL:    "http://127.0.0.1:7002",
-			EtcdURL:    "http://127.0.0.1:4002",
-		})
-	assert.NoError(t, err)
-
-	time.Sleep(6 * time.Second)
-
-	go tests.Delete("http://localhost:7001/v2/admin/machines/node2", "application/json", nil)
-
-	time.Sleep(time.Second)
-	result, err = c.Get("_etcd/machines", false, true)
-	assert.NoError(t, err)
-	assert.Equal(t, len(result.Node.Nodes), 1)
-}

+ 0 - 258
tests/functional/util.go

@@ -1,258 +0,0 @@
-// +build ignore
-
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package test
-
-import (
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"os"
-	"strconv"
-	"time"
-
-	"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
-)
-
-var client = http.Client{
-	Transport: &http.Transport{
-		Dial: dialTimeoutFast,
-	},
-}
-
-// Sending set commands
-func Set(stop chan bool) {
-
-	stopSet := false
-	i := 0
-	c := etcd.NewClient(nil)
-	for {
-		key := fmt.Sprintf("%s_%v", "foo", i)
-
-		result, err := c.Set(key, "bar", 0)
-
-		if err != nil || result.Node.Key != "/"+key || result.Node.Value != "bar" {
-			select {
-			case <-stop:
-				stopSet = true
-
-			default:
-			}
-		}
-
-		select {
-		case <-stop:
-			stopSet = true
-
-		default:
-		}
-
-		if stopSet {
-			break
-		}
-
-		i++
-	}
-	stop <- true
-}
-
-func WaitForServer(host string, client http.Client, scheme string) error {
-	path := fmt.Sprintf("%s://%s/v2/keys/", scheme, host)
-
-	var resp *http.Response
-	var err error
-	for i := 0; i < 10; i++ {
-		time.Sleep(1 * time.Second)
-
-		resp, err = client.Get(path)
-		if err == nil && resp.StatusCode == 200 {
-			return nil
-		}
-	}
-
-	return errors.New(fmt.Sprintf("etcd server was not reachable in a long time, last-time response and error: %v; %v", resp, err))
-}
-
-// Create a cluster of etcd nodes
-func CreateCluster(size int, procAttr *os.ProcAttr, ssl bool) ([][]string, []*os.Process, error) {
-	argGroup := make([][]string, size)
-
-	sslServer1 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt",
-		"-peer-cert-file=../../fixtures/ca/server.crt",
-		"-peer-key-file=../../fixtures/ca/server.key.insecure",
-	}
-
-	sslServer2 := []string{"-peer-ca-file=../../fixtures/ca/ca.crt",
-		"-peer-cert-file=../../fixtures/ca/server2.crt",
-		"-peer-key-file=../../fixtures/ca/server2.key.insecure",
-	}
-
-	for i := 0; i < size; i++ {
-		if i == 0 {
-			argGroup[i] = []string{"etcd", "-data-dir=/tmp/node1", "-name=node1", "-cluster-remove-delay=1800"}
-			if ssl {
-				argGroup[i] = append(argGroup[i], sslServer1...)
-			}
-		} else {
-			strI := strconv.Itoa(i + 1)
-			argGroup[i] = []string{"etcd", "-name=node" + strI, fmt.Sprintf("-addr=127.0.0.1:%d", 4001+i), fmt.Sprintf("-peer-addr=127.0.0.1:%d", 7001+i), "-data-dir=/tmp/node" + strI, "-peers=127.0.0.1:7001", "-cluster-remove-delay=1800"}
-			if ssl {
-				argGroup[i] = append(argGroup[i], sslServer2...)
-			}
-		}
-	}
-
-	etcds := make([]*os.Process, size)
-
-	for i := range etcds {
-		var err error
-		etcds[i], err = os.StartProcess(EtcdBinPath, append(argGroup[i], "-f"), procAttr)
-		if err != nil {
-			return nil, nil, err
-		}
-
-		// The problem is that if the master isn't up then the children
-		// have to retry. This retry can take upwards of 15 seconds
-		// which slows tests way down and some of them fail.
-		//
-		// Waiting for each server to start when ssl is a workaround.
-		// Autotest machines are dramatically slow, and it could spend
-		// several seconds to build TSL connections between servers. That
-		// is extremely terribe when the second machine joins the cluster
-		// because the cluster is out of work at this time. The guy
-		// tries to join during this time will fail, and current implementation
-		// makes it fail after just one-time try(bug in #661). This
-		// makes the cluster start with N-1 machines.
-		// TODO(yichengq): It should be fixed.
-		if i == 0 || ssl {
-			client := buildClient()
-			err = WaitForServer("127.0.0.1:400"+strconv.Itoa(i+1), client, "http")
-			if err != nil {
-				return nil, nil, err
-			}
-		}
-	}
-
-	return argGroup, etcds, nil
-}
-
-// Destroy all the nodes in the cluster
-func DestroyCluster(etcds []*os.Process) error {
-	for _, etcd := range etcds {
-		if etcd == nil {
-			continue
-		}
-		err := etcd.Kill()
-		if err != nil {
-			panic(err.Error())
-		}
-		etcd.Release()
-	}
-	return nil
-}
-
-//
-func Monitor(size int, allowDeadNum int, leaderChan chan string, all chan bool, stop chan bool) {
-	leaderMap := make(map[int]string)
-	baseAddrFormat := "http://0.0.0.0:%d"
-
-	for {
-		knownLeader := "unknown"
-		dead := 0
-		var i int
-
-		for i = 0; i < size; i++ {
-			leader, err := getLeader(fmt.Sprintf(baseAddrFormat, i+4001))
-
-			if err == nil {
-				leaderMap[i] = leader
-
-				if knownLeader == "unknown" {
-					knownLeader = leader
-				} else {
-					if leader != knownLeader {
-						break
-					}
-
-				}
-
-			} else {
-				dead++
-				if dead > allowDeadNum {
-					break
-				}
-			}
-
-		}
-
-		if i == size {
-			select {
-			case <-stop:
-				return
-			case <-leaderChan:
-				leaderChan <- knownLeader
-			default:
-				leaderChan <- knownLeader
-			}
-
-		}
-		if dead == 0 {
-			select {
-			case <-all:
-				all <- true
-			default:
-				all <- true
-			}
-		}
-
-		time.Sleep(time.Millisecond * 10)
-	}
-
-}
-
-func getLeader(addr string) (string, error) {
-
-	resp, err := client.Get(addr + "/v2/leader")
-
-	if err != nil {
-		return "", err
-	}
-
-	if resp.StatusCode != http.StatusOK {
-		resp.Body.Close()
-		return "", fmt.Errorf("no leader")
-	}
-
-	b, err := ioutil.ReadAll(resp.Body)
-
-	resp.Body.Close()
-
-	if err != nil {
-		return "", err
-	}
-
-	return string(b), nil
-
-}
-
-// Dial with timeout
-func dialTimeoutFast(network, addr string) (net.Conn, error) {
-	return net.DialTimeout(network, addr, time.Millisecond*10)
-}

+ 0 - 80
tests/http_utils.go

@@ -1,80 +0,0 @@
-// +build ignore
-
-package tests
-
-import (
-	"encoding/json"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"net/url"
-	"strings"
-)
-
-// Creates a new HTTP client with KeepAlive disabled.
-func NewHTTPClient() *http.Client {
-	return &http.Client{Transport: &http.Transport{DisableKeepAlives: true}}
-}
-
-// Reads the body from the response and closes it.
-func ReadBody(resp *http.Response) []byte {
-	if resp == nil {
-		return []byte{}
-	}
-	body, _ := ioutil.ReadAll(resp.Body)
-	resp.Body.Close()
-	return body
-}
-
-// Reads the body from the response and parses it as JSON.
-func ReadBodyJSON(resp *http.Response) map[string]interface{} {
-	m := make(map[string]interface{})
-	b := ReadBody(resp)
-	if err := json.Unmarshal(b, &m); err != nil {
-		panic(fmt.Sprintf("HTTP body JSON parse error: %v: %s", err, string(b)))
-	}
-	return m
-}
-
-func Head(url string) (*http.Response, error) {
-	return send("HEAD", url, "application/json", nil)
-}
-
-func Get(url string) (*http.Response, error) {
-	return send("GET", url, "application/json", nil)
-}
-
-func Post(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return send("POST", url, bodyType, body)
-}
-
-func PostForm(url string, data url.Values) (*http.Response, error) {
-	return Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func Put(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return send("PUT", url, bodyType, body)
-}
-
-func PutForm(url string, data url.Values) (*http.Response, error) {
-	return Put(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func Delete(url string, bodyType string, body io.Reader) (*http.Response, error) {
-	return send("DELETE", url, bodyType, body)
-}
-
-func DeleteForm(url string, data url.Values) (*http.Response, error) {
-	return Delete(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-func send(method string, url string, bodyType string, body io.Reader) (*http.Response, error) {
-	c := NewHTTPClient()
-	req, err := http.NewRequest(method, url, body)
-	if err != nil {
-		return nil, err
-	}
-	req.Header.Set("Content-Type", bodyType)
-	return c.Do(req)
-}

+ 0 - 69
tests/mock/mock_store.go

@@ -1,69 +0,0 @@
-// +build ignore
-
-package mock
-
-import (
-	"time"
-
-	"github.com/coreos/etcd/store"
-	"github.com/stretchr/testify/mock"
-)
-
-// A mock Store object used for testing.
-type Store struct {
-	mock.Mock
-}
-
-func NewStore() *Store {
-	return &Store{}
-}
-
-func (s *Store) Get(nodePath string, recursive, sorted bool, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, recursive, sorted, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) Set(nodePath string, value string, expireTime time.Time, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, value, expireTime, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) Update(nodePath string, newValue string, expireTime time.Time, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, newValue, expireTime, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) Create(nodePath string, value string, incrementalSuffix bool, expireTime time.Time, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, value, incrementalSuffix, expireTime, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) CompareAndSwap(nodePath string, prevValue string, prevIndex uint64, value string, expireTime time.Time, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, prevValue, prevIndex, value, expireTime, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) Delete(nodePath string, recursive bool, index uint64, term uint64) (*store.Event, error) {
-	args := s.Called(nodePath, recursive, index, term)
-	return args.Get(0).(*store.Event), args.Error(1)
-}
-
-func (s *Store) Watch(prefix string, recursive bool, sinceIndex uint64, index uint64, term uint64) (<-chan *store.Event, error) {
-	args := s.Called(prefix, recursive, sinceIndex, index, term)
-	return args.Get(0).(<-chan *store.Event), args.Error(1)
-}
-
-func (s *Store) Save() ([]byte, error) {
-	args := s.Called()
-	return args.Get(0).([]byte), args.Error(1)
-}
-
-func (s *Store) Recovery(b []byte) error {
-	args := s.Called(b)
-	return args.Error(1)
-}
-
-func (s *Store) JsonStats() []byte {
-	args := s.Called()
-	return args.Get(0).([]byte)
-}

+ 0 - 62
tests/mock/server_v2.go

@@ -1,62 +0,0 @@
-// +build ignore
-
-package mock
-
-import (
-	"net/http"
-
-	"github.com/coreos/etcd/store"
-	"github.com/coreos/etcd/third_party/github.com/goraft/raft"
-	"github.com/stretchr/testify/mock"
-)
-
-// A mock Server for the v2 handlers.
-type ServerV2 struct {
-	mock.Mock
-	store store.Store
-}
-
-func NewServerV2(store store.Store) *ServerV2 {
-	return &ServerV2{
-		store: store,
-	}
-}
-
-func (s *ServerV2) State() string {
-	args := s.Called()
-	return args.String(0)
-}
-
-func (s *ServerV2) Leader() string {
-	args := s.Called()
-	return args.String(0)
-}
-
-func (s *ServerV2) CommitIndex() uint64 {
-	args := s.Called()
-	return args.Get(0).(uint64)
-}
-
-func (s *ServerV2) Term() uint64 {
-	args := s.Called()
-	return args.Get(0).(uint64)
-}
-
-func (s *ServerV2) PeerURL(name string) (string, bool) {
-	args := s.Called(name)
-	return args.String(0), args.Bool(1)
-}
-
-func (s *ServerV2) ClientURL(name string) (string, bool) {
-	args := s.Called(name)
-	return args.String(0), args.Bool(1)
-}
-
-func (s *ServerV2) Store() store.Store {
-	return s.store
-}
-
-func (s *ServerV2) Dispatch(c raft.Command, w http.ResponseWriter, req *http.Request) error {
-	args := s.Called(c, w, req)
-	return args.Error(0)
-}

+ 0 - 42
tests/server_utils.go

@@ -1,42 +0,0 @@
-// +build ignore
-
-package tests
-
-import (
-	"github.com/coreos/etcd/config"
-	"github.com/coreos/etcd/etcd"
-	"github.com/coreos/etcd/server"
-)
-
-const (
-	testName              = "ETCDTEST"
-	testClientURL         = "localhost:4401"
-	testRaftURL           = "localhost:7701"
-	testSnapshotCount     = 10000
-	testHeartbeatInterval = 50
-	testElectionTimeout   = 200
-	testDataDir           = "/tmp/ETCDTEST"
-)
-
-// Starts a new server.
-func RunServer(f func(*server.Server)) {
-	c := cfg.New()
-
-	c.Name = testName
-	c.Addr = testClientURL
-	c.Peer.Addr = testRaftURL
-
-	c.DataDir = testDataDir
-	c.Force = true
-
-	c.Peer.HeartbeatInterval = testHeartbeatInterval
-	c.Peer.ElectionTimeout = testElectionTimeout
-	c.SnapshotCount = testSnapshotCount
-
-	i := etcd.New(c)
-	go i.Run()
-	<-i.ReadyNotify()
-	// Execute the function passed in.
-	f(i.Server)
-	i.Stop()
-}