Browse Source

etcd: support raft tls

Xiang Li 11 years ago
parent
commit
4181f1b2e1
6 changed files with 105 additions and 48 deletions
  1. 13 1
      etcd/etcd.go
  2. 24 3
      etcd/etcd_test.go
  3. 3 1
      etcd/transporter.go
  4. 3 3
      etcd/v2_http_endpoint_test.go
  5. 38 38
      etcd/v2_http_kv_test.go
  6. 24 2
      main.go

+ 13 - 1
etcd/etcd.go

@@ -1,6 +1,7 @@
 package etcd
 package etcd
 
 
 import (
 import (
+	"crypto/tls"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"log"
 	"log"
@@ -54,6 +55,17 @@ func New(c *config.Config, id int64) *Server {
 		log.Fatalf("failed sanitizing configuration: %v", err)
 		log.Fatalf("failed sanitizing configuration: %v", err)
 	}
 	}
 
 
+	tc := &tls.Config{
+		InsecureSkipVerify: true,
+	}
+	var err error
+	if c.PeerTLSInfo().Scheme() == "https" {
+		tc, err = c.PeerTLSInfo().ClientConfig()
+		if err != nil {
+			log.Fatal("failed to create raft transporter tls:", err)
+		}
+	}
+
 	s := &Server{
 	s := &Server{
 		config:       c,
 		config:       c,
 		id:           id,
 		id:           id,
@@ -66,7 +78,7 @@ func New(c *config.Config, id int64) *Server {
 			Node:   raft.New(id, defaultHeartbeat, defaultElection),
 			Node:   raft.New(id, defaultHeartbeat, defaultElection),
 			result: make(map[wait]chan interface{}),
 			result: make(map[wait]chan interface{}),
 		},
 		},
-		t: newTransporter(),
+		t: newTransporter(tc),
 
 
 		Store: store.New(),
 		Store: store.New(),
 
 

+ 24 - 3
etcd/etcd_test.go

@@ -14,7 +14,7 @@ func TestMultipleNodes(t *testing.T) {
 	tests := []int{1, 3, 5, 9, 11}
 	tests := []int{1, 3, 5, 9, 11}
 
 
 	for _, tt := range tests {
 	for _, tt := range tests {
-		es, hs := buildCluster(tt)
+		es, hs := buildCluster(tt, false)
 		waitCluster(t, es)
 		waitCluster(t, es)
 		for i := range es {
 		for i := range es {
 			es[len(es)-i-1].Stop()
 			es[len(es)-i-1].Stop()
@@ -26,7 +26,23 @@ func TestMultipleNodes(t *testing.T) {
 	afterTest(t)
 	afterTest(t)
 }
 }
 
 
-func buildCluster(number int) ([]*Server, []*httptest.Server) {
+func TestMultipleTLSNodes(t *testing.T) {
+	tests := []int{1, 3, 5}
+
+	for _, tt := range tests {
+		es, hs := buildCluster(tt, true)
+		waitCluster(t, es)
+		for i := range es {
+			es[len(es)-i-1].Stop()
+		}
+		for i := range hs {
+			hs[len(hs)-i-1].Close()
+		}
+	}
+	afterTest(t)
+}
+
+func buildCluster(number int, tls bool) ([]*Server, []*httptest.Server) {
 	bootstrapper := 0
 	bootstrapper := 0
 	es := make([]*Server, number)
 	es := make([]*Server, number)
 	hs := make([]*httptest.Server, number)
 	hs := make([]*httptest.Server, number)
@@ -42,7 +58,12 @@ func buildCluster(number int) ([]*Server, []*httptest.Server) {
 		m.Handle("/raft", es[i].t)
 		m.Handle("/raft", es[i].t)
 		m.Handle("/raft/", es[i].t)
 		m.Handle("/raft/", es[i].t)
 
 
-		hs[i] = httptest.NewServer(m)
+		if tls {
+			hs[i] = httptest.NewTLSServer(m)
+		} else {
+			hs[i] = httptest.NewServer(m)
+		}
+
 		es[i].raftPubAddr = hs[i].URL
 		es[i].raftPubAddr = hs[i].URL
 		es[i].pubAddr = hs[i].URL
 		es[i].pubAddr = hs[i].URL
 
 

+ 3 - 1
etcd/transporter.go

@@ -2,6 +2,7 @@ package etcd
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"crypto/tls"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
@@ -31,8 +32,9 @@ type transporter struct {
 	*http.ServeMux
 	*http.ServeMux
 }
 }
 
 
-func newTransporter() *transporter {
+func newTransporter(tc *tls.Config) *transporter {
 	tr := new(http.Transport)
 	tr := new(http.Transport)
+	tr.TLSClientConfig = tc
 	c := &http.Client{Transport: tr}
 	c := &http.Client{Transport: tr}
 
 
 	t := &transporter{
 	t := &transporter{

+ 3 - 3
etcd/v2_http_endpoint_test.go

@@ -13,7 +13,7 @@ import (
 )
 )
 
 
 func TestMachinesEndPoint(t *testing.T) {
 func TestMachinesEndPoint(t *testing.T) {
-	es, hs := buildCluster(3)
+	es, hs := buildCluster(3, false)
 	waitCluster(t, es)
 	waitCluster(t, es)
 
 
 	w := make([]string, len(hs))
 	w := make([]string, len(hs))
@@ -50,7 +50,7 @@ func TestMachinesEndPoint(t *testing.T) {
 }
 }
 
 
 func TestLeaderEndPoint(t *testing.T) {
 func TestLeaderEndPoint(t *testing.T) {
-	es, hs := buildCluster(3)
+	es, hs := buildCluster(3, false)
 	waitCluster(t, es)
 	waitCluster(t, es)
 
 
 	us := make([]string, len(hs))
 	us := make([]string, len(hs))
@@ -87,7 +87,7 @@ func TestLeaderEndPoint(t *testing.T) {
 }
 }
 
 
 func TestStoreStatsEndPoint(t *testing.T) {
 func TestStoreStatsEndPoint(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	waitCluster(t, es)
 	waitCluster(t, es)
 
 
 	resp, err := http.Get(hs[0].URL + v2StoreStatsPrefix)
 	resp, err := http.Get(hs[0].URL + v2StoreStatsPrefix)

+ 38 - 38
etcd/v2_http_kv_test.go

@@ -17,7 +17,7 @@ import (
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true
 //
 //
 func TestV2SetDirectory(t *testing.T) {
 func TestV2SetDirectory(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
 	assert.Equal(t, resp.StatusCode, http.StatusCreated)
 	assert.Equal(t, resp.StatusCode, http.StatusCreated)
@@ -34,7 +34,7 @@ func TestV2SetDirectory(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=20
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=20
 //
 //
 func TestV2SetKeyWithTTL(t *testing.T) {
 func TestV2SetKeyWithTTL(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	t0 := time.Now()
 	t0 := time.Now()
 	v := url.Values{}
 	v := url.Values{}
@@ -59,7 +59,7 @@ func TestV2SetKeyWithTTL(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=bad_ttl
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=bad_ttl
 //
 //
 func TestV2SetKeyWithBadTTL(t *testing.T) {
 func TestV2SetKeyWithBadTTL(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -80,7 +80,7 @@ func TestV2SetKeyWithBadTTL(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false
 //
 //
 func TestV2CreateKeySuccess(t *testing.T) {
 func TestV2CreateKeySuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -101,7 +101,7 @@ func TestV2CreateKeySuccess(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false -> fail
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false -> fail
 //
 //
 func TestV2CreateKeyFail(t *testing.T) {
 func TestV2CreateKeyFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -127,7 +127,7 @@ func TestV2CreateKeyFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true
 //
 //
 func TestV2UpdateKeySuccess(t *testing.T) {
 func TestV2UpdateKeySuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 
 
@@ -154,7 +154,7 @@ func TestV2UpdateKeySuccess(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=true
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=true
 //
 //
 func TestV2UpdateKeyFailOnValue(t *testing.T) {
 func TestV2UpdateKeyFailOnValue(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	resp, _ := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), v)
 	resp, _ := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), v)
@@ -180,7 +180,7 @@ func TestV2UpdateKeyFailOnValue(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true -> fail
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true -> fail
 //
 //
 func TestV2UpdateKeyFailOnMissingDirectory(t *testing.T) {
 func TestV2UpdateKeyFailOnMissingDirectory(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "YYY")
 	v.Set("value", "YYY")
@@ -210,7 +210,7 @@ func TestV2UpdateKeyFailOnMissingDirectory(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX -d ttl= -d prevExist=true
 //   $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX -d ttl= -d prevExist=true
 //
 //
 func TestV2UpdateKeySuccessWithTTL(t *testing.T) {
 func TestV2UpdateKeySuccessWithTTL(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -248,7 +248,7 @@ func TestV2UpdateKeySuccessWithTTL(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=1
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=1
 //
 //
 func TestV2SetKeyCASOnIndexSuccess(t *testing.T) {
 func TestV2SetKeyCASOnIndexSuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -277,7 +277,7 @@ func TestV2SetKeyCASOnIndexSuccess(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=10
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=10
 //
 //
 func TestV2SetKeyCASOnIndexFail(t *testing.T) {
 func TestV2SetKeyCASOnIndexFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -304,7 +304,7 @@ func TestV2SetKeyCASOnIndexFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=bad_index
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=bad_index
 //
 //
 func TestV2SetKeyCASWithInvalidIndex(t *testing.T) {
 func TestV2SetKeyCASWithInvalidIndex(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "YYY")
 	v.Set("value", "YYY")
@@ -326,7 +326,7 @@ func TestV2SetKeyCASWithInvalidIndex(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX
 //
 //
 func TestV2SetKeyCASOnValueSuccess(t *testing.T) {
 func TestV2SetKeyCASOnValueSuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -354,7 +354,7 @@ func TestV2SetKeyCASOnValueSuccess(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA
 //
 //
 func TestV2SetKeyCASOnValueFail(t *testing.T) {
 func TestV2SetKeyCASOnValueFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -381,7 +381,7 @@ func TestV2SetKeyCASOnValueFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevValue=
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevValue=
 //
 //
 func TestV2SetKeyCASWithMissingValueFails(t *testing.T) {
 func TestV2SetKeyCASWithMissingValueFails(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -403,7 +403,7 @@ func TestV2SetKeyCASWithMissingValueFails(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=4
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=4
 //
 //
 func TestV2SetKeyCASOnValueAndIndexFail(t *testing.T) {
 func TestV2SetKeyCASOnValueAndIndexFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -432,7 +432,7 @@ func TestV2SetKeyCASOnValueAndIndexFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX -d prevIndex=4
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX -d prevIndex=4
 //
 //
 func TestV2SetKeyCASOnValueMatchAndIndexFail(t *testing.T) {
 func TestV2SetKeyCASOnValueMatchAndIndexFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -461,7 +461,7 @@ func TestV2SetKeyCASOnValueMatchAndIndexFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=3
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=3
 //
 //
 func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
 func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "XXX")
 	v.Set("value", "XXX")
@@ -489,7 +489,7 @@ func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=
 //
 //
 func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
 func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("value", "")
 	v.Set("value", "")
@@ -503,7 +503,7 @@ func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
 }
 }
 
 
 func TestV2SetKey(t *testing.T) {
 func TestV2SetKey(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -521,7 +521,7 @@ func TestV2SetKey(t *testing.T) {
 }
 }
 
 
 func TestV2SetKeyRedirect(t *testing.T) {
 func TestV2SetKeyRedirect(t *testing.T) {
-	es, hs := buildCluster(3)
+	es, hs := buildCluster(3, false)
 	waitCluster(t, es)
 	waitCluster(t, es)
 	u := hs[1].URL
 	u := hs[1].URL
 	ru := fmt.Sprintf("%s%s", hs[0].URL, "/v2/keys/foo/bar")
 	ru := fmt.Sprintf("%s%s", hs[0].URL, "/v2/keys/foo/bar")
@@ -555,7 +555,7 @@ func TestV2SetKeyRedirect(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar
 //
 //
 func TestV2DeleteKey(t *testing.T) {
 func TestV2DeleteKey(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -583,7 +583,7 @@ func TestV2DeleteKey(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true
 //
 //
 func TestV2DeleteEmptyDirectory(t *testing.T) {
 func TestV2DeleteEmptyDirectory(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
@@ -611,7 +611,7 @@ func TestV2DeleteEmptyDirectory(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true&recursive=true
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true&recursive=true
 //
 //
 func TestV2DeleteNonEmptyDirectory(t *testing.T) {
 func TestV2DeleteNonEmptyDirectory(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?dir=true"), url.Values{})
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?dir=true"), url.Values{})
@@ -637,7 +637,7 @@ func TestV2DeleteNonEmptyDirectory(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?recursive=true
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?recursive=true
 //
 //
 func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) {
 func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
 	resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
@@ -659,7 +659,7 @@ func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=3
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=3
 //
 //
 func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
 func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -686,7 +686,7 @@ func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=100
 //   $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=100
 //
 //
 func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
 func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -709,7 +709,7 @@ func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=bad_index
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=bad_index
 //
 //
 func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
 func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -731,7 +731,7 @@ func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=XXX
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=XXX
 //
 //
 func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
 func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -756,7 +756,7 @@ func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=YYY
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=YYY
 //
 //
 func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
 func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -778,7 +778,7 @@ func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=
 //   $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=
 //
 //
 func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
 func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -801,7 +801,7 @@ func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
 //   $ curl -X POST localhost:4001/v2/keys/foo/baz
 //   $ curl -X POST localhost:4001/v2/keys/foo/baz
 //
 //
 func TestV2CreateUnique(t *testing.T) {
 func TestV2CreateUnique(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	// POST should add index to list.
 	// POST should add index to list.
@@ -843,7 +843,7 @@ func TestV2CreateUnique(t *testing.T) {
 //   $ curl localhost:4001/v2/keys/foo/bar
 //   $ curl localhost:4001/v2/keys/foo/bar
 //
 //
 func TestV2GetKey(t *testing.T) {
 func TestV2GetKey(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -878,7 +878,7 @@ func TestV2GetKey(t *testing.T) {
 //   $ curl localhost:4001/v2/keys/foo -d recursive=true
 //   $ curl localhost:4001/v2/keys/foo -d recursive=true
 //
 //
 func TestV2GetKeyRecursively(t *testing.T) {
 func TestV2GetKeyRecursively(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}
@@ -927,7 +927,7 @@ func TestV2GetKeyRecursively(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
 //
 //
 func TestV2WatchKey(t *testing.T) {
 func TestV2WatchKey(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	// There exists a little gap between etcd ready to serve and
 	// There exists a little gap between etcd ready to serve and
@@ -985,7 +985,7 @@ func TestV2WatchKey(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY
 //   $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY
 //
 //
 func TestV2WatchKeyWithIndex(t *testing.T) {
 func TestV2WatchKeyWithIndex(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	var body map[string]interface{}
 	var body map[string]interface{}
@@ -1044,7 +1044,7 @@ func TestV2WatchKeyWithIndex(t *testing.T) {
 //   $ curl -X PUT localhost:4001/v2/keys/keyindir/bar -d value=YYY
 //   $ curl -X PUT localhost:4001/v2/keys/keyindir/bar -d value=YYY
 //
 //
 func TestV2WatchKeyInDir(t *testing.T) {
 func TestV2WatchKeyInDir(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	var body map[string]interface{}
 	var body map[string]interface{}
@@ -1096,7 +1096,7 @@ func TestV2WatchKeyInDir(t *testing.T) {
 //   $ curl -I localhost:4001/v2/keys/foo/bar
 //   $ curl -I localhost:4001/v2/keys/foo/bar
 //
 //
 func TestV2HeadKey(t *testing.T) {
 func TestV2HeadKey(t *testing.T) {
-	es, hs := buildCluster(1)
+	es, hs := buildCluster(1, false)
 	u := hs[0].URL
 	u := hs[0].URL
 
 
 	v := url.Values{}
 	v := url.Values{}

+ 24 - 2
main.go

@@ -1,9 +1,11 @@
 package main
 package main
 
 
 import (
 import (
+	"crypto/tls"
 	"fmt"
 	"fmt"
 	"log"
 	"log"
 	"math/rand"
 	"math/rand"
+	"net"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"time"
 	"time"
@@ -25,12 +27,32 @@ func main() {
 	}
 	}
 
 
 	e := etcd.New(config, genId())
 	e := etcd.New(config, genId())
+	rTLS, rerr := config.PeerTLSInfo().ServerConfig()
+
 	go e.Run()
 	go e.Run()
 
 
 	go func() {
 	go func() {
-		if err := http.ListenAndServe(config.Peer.BindAddr, e.RaftHandler()); err != nil {
-			log.Fatal("system", err)
+		l, err := net.Listen("tcp", config.Peer.BindAddr)
+		if err != nil {
+			log.Fatal(err)
 		}
 		}
+		log.Println("raft server starts listening on", config.Peer.BindAddr)
+
+		switch config.PeerTLSInfo().Scheme() {
+		case "http":
+			log.Println("raft server starts serving HTTP")
+
+		case "https":
+			if rTLS == nil {
+				log.Fatal("failed to create raft tls:", rerr)
+			}
+			l = tls.NewListener(l, rTLS)
+			log.Println("raft server starts serving HTTPS")
+		default:
+			log.Fatal("unsupported http scheme", config.PeerTLSInfo().Scheme())
+		}
+
+		log.Fatal(http.Serve(l, e.RaftHandler()))
 	}()
 	}()
 
 
 	if err := http.ListenAndServe(config.BindAddr, e); err != nil {
 	if err := http.ListenAndServe(config.BindAddr, e); err != nil {