etcd: support raft tls

release-2.0
Xiang Li 2014-07-08 13:49:22 -07:00 committed by Yicheng Qin
parent c3f8eabac3
commit 4181f1b2e1
6 changed files with 105 additions and 48 deletions

View File

@ -1,6 +1,7 @@
package etcd
import (
"crypto/tls"
"encoding/json"
"fmt"
"log"
@ -54,6 +55,17 @@ func New(c *config.Config, id int64) *Server {
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{
config: c,
id: id,
@ -66,7 +78,7 @@ func New(c *config.Config, id int64) *Server {
Node: raft.New(id, defaultHeartbeat, defaultElection),
result: make(map[wait]chan interface{}),
},
t: newTransporter(),
t: newTransporter(tc),
Store: store.New(),

View File

@ -14,7 +14,7 @@ func TestMultipleNodes(t *testing.T) {
tests := []int{1, 3, 5, 9, 11}
for _, tt := range tests {
es, hs := buildCluster(tt)
es, hs := buildCluster(tt, false)
waitCluster(t, es)
for i := range es {
es[len(es)-i-1].Stop()
@ -26,7 +26,23 @@ func TestMultipleNodes(t *testing.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
es := make([]*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)
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].pubAddr = hs[i].URL

View File

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

View File

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

View File

@ -17,7 +17,7 @@ import (
// $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true
//
func TestV2SetDirectory(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
resp, err := PutForm(fmt.Sprintf("%s%s", u, "/v2/keys/foo?dir=true"), url.Values{})
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
//
func TestV2SetKeyWithTTL(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
t0 := time.Now()
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
//
func TestV2SetKeyWithBadTTL(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2CreateKeySuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2CreateKeyFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2UpdateKeySuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
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
//
func TestV2UpdateKeyFailOnValue(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2UpdateKeyFailOnMissingDirectory(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2UpdateKeySuccessWithTTL(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnIndexSuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnIndexFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASWithInvalidIndex(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnValueSuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnValueFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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=
//
func TestV2SetKeyCASWithMissingValueFails(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnValueAndIndexFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnValueMatchAndIndexFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
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
//
func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
v.Set("value", "XXX")
@ -489,7 +489,7 @@ func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
// $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=
//
func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
v.Set("value", "")
@ -503,7 +503,7 @@ func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
}
func TestV2SetKey(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -521,7 +521,7 @@ func TestV2SetKey(t *testing.T) {
}
func TestV2SetKeyRedirect(t *testing.T) {
es, hs := buildCluster(3)
es, hs := buildCluster(3, false)
waitCluster(t, es)
u := hs[1].URL
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
//
func TestV2DeleteKey(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -583,7 +583,7 @@ func TestV2DeleteKey(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true
//
func TestV2DeleteEmptyDirectory(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
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
//
func TestV2DeleteNonEmptyDirectory(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
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
//
func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
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
//
func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -686,7 +686,7 @@ func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=100
//
func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -709,7 +709,7 @@ func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=bad_index
//
func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -731,7 +731,7 @@ func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=XXX
//
func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -756,7 +756,7 @@ func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=YYY
//
func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -778,7 +778,7 @@ func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
// $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=
//
func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -801,7 +801,7 @@ func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
// $ curl -X POST localhost:4001/v2/keys/foo/baz
//
func TestV2CreateUnique(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
// POST should add index to list.
@ -843,7 +843,7 @@ func TestV2CreateUnique(t *testing.T) {
// $ curl localhost:4001/v2/keys/foo/bar
//
func TestV2GetKey(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -878,7 +878,7 @@ func TestV2GetKey(t *testing.T) {
// $ curl localhost:4001/v2/keys/foo -d recursive=true
//
func TestV2GetKeyRecursively(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}
@ -927,7 +927,7 @@ func TestV2GetKeyRecursively(t *testing.T) {
// $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
//
func TestV2WatchKey(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
// 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
//
func TestV2WatchKeyWithIndex(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
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
//
func TestV2WatchKeyInDir(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
var body map[string]interface{}
@ -1096,7 +1096,7 @@ func TestV2WatchKeyInDir(t *testing.T) {
// $ curl -I localhost:4001/v2/keys/foo/bar
//
func TestV2HeadKey(t *testing.T) {
es, hs := buildCluster(1)
es, hs := buildCluster(1, false)
u := hs[0].URL
v := url.Values{}

26
main.go
View File

@ -1,9 +1,11 @@
package main
import (
"crypto/tls"
"fmt"
"log"
"math/rand"
"net"
"net/http"
"os"
"time"
@ -25,12 +27,32 @@ func main() {
}
e := etcd.New(config, genId())
rTLS, rerr := config.PeerTLSInfo().ServerConfig()
go e.Run()
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 {