Switch to using the official etcd health check.
This commit is contained in:
@@ -33,11 +33,14 @@ type httpGet interface {
|
|||||||
Get(url string) (*http.Response, error)
|
Get(url string) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ValidatorFn func([]byte) error
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Addr string
|
Addr string
|
||||||
Port int
|
Port int
|
||||||
Path string
|
Path string
|
||||||
EnableHTTPS bool
|
EnableHTTPS bool
|
||||||
|
Validate ValidatorFn
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerStatus struct {
|
type ServerStatus struct {
|
||||||
@@ -85,5 +88,10 @@ func (server *Server) DoServerCheck(rt http.RoundTripper) (probe.Result, string,
|
|||||||
return probe.Failure, string(data),
|
return probe.Failure, string(data),
|
||||||
fmt.Errorf("unhealthy http status code: %d (%s)", resp.StatusCode, resp.Status)
|
fmt.Errorf("unhealthy http status code: %d (%s)", resp.StatusCode, resp.Status)
|
||||||
}
|
}
|
||||||
|
if server.Validate != nil {
|
||||||
|
if err := server.Validate(data); err != nil {
|
||||||
|
return probe.Failure, string(data), err
|
||||||
|
}
|
||||||
|
}
|
||||||
return probe.Success, string(data), nil
|
return probe.Success, string(data), nil
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package apiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -37,6 +38,15 @@ func (f *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
|
|||||||
return f.resp, f.err
|
return f.resp, f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func alwaysError([]byte) error { return errors.New("test error") }
|
||||||
|
|
||||||
|
func matchError(data []byte) error {
|
||||||
|
if string(data) == "bar" {
|
||||||
|
return errors.New("match error")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidate(t *testing.T) {
|
func TestValidate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
err error
|
err error
|
||||||
@@ -44,10 +54,13 @@ func TestValidate(t *testing.T) {
|
|||||||
expectedStatus probe.Result
|
expectedStatus probe.Result
|
||||||
code int
|
code int
|
||||||
expectErr bool
|
expectErr bool
|
||||||
|
validator ValidatorFn
|
||||||
}{
|
}{
|
||||||
{fmt.Errorf("test error"), "", probe.Unknown, 500 /*ignored*/, true},
|
{fmt.Errorf("test error"), "", probe.Unknown, 500 /*ignored*/, true, nil},
|
||||||
{nil, "foo", probe.Success, 200, false},
|
{nil, "foo", probe.Success, 200, false, nil},
|
||||||
{nil, "foo", probe.Failure, 500, true},
|
{nil, "foo", probe.Failure, 500, true, nil},
|
||||||
|
{nil, "foo", probe.Failure, 200, true, alwaysError},
|
||||||
|
{nil, "foo", probe.Success, 200, false, matchError},
|
||||||
}
|
}
|
||||||
|
|
||||||
s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"}
|
s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"}
|
||||||
@@ -60,6 +73,7 @@ func TestValidate(t *testing.T) {
|
|||||||
StatusCode: test.code,
|
StatusCode: test.code,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
s.Validate = test.validator
|
||||||
status, data, err := s.DoServerCheck(fakeRT)
|
status, data, err := s.DoServerCheck(fakeRT)
|
||||||
expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port)
|
expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port)
|
||||||
if fakeRT.url != expect {
|
if fakeRT.url != expect {
|
||||||
|
@@ -715,7 +715,7 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server {
|
|||||||
addr = etcdUrl.Host
|
addr = etcdUrl.Host
|
||||||
port = 4001
|
port = 4001
|
||||||
}
|
}
|
||||||
serversToValidate[fmt.Sprintf("etcd-%d", ix)] = apiserver.Server{Addr: addr, Port: port, Path: "/v2/keys/"}
|
serversToValidate[fmt.Sprintf("etcd-%d", ix)] = apiserver.Server{Addr: addr, Port: port, Path: "/health", Validate: tools.EtcdHealthCheck}
|
||||||
}
|
}
|
||||||
return serversToValidate
|
return serversToValidate
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package tools
|
package tools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -712,3 +713,19 @@ func NewEtcdClientStartServerIfNecessary(server string) (EtcdClient, error) {
|
|||||||
servers := []string{server}
|
servers := []string{server}
|
||||||
return etcd.NewClient(servers), nil
|
return etcd.NewClient(servers), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type etcdHealth struct {
|
||||||
|
// Note this has to be public so the json library can modify it.
|
||||||
|
Health string `json:health`
|
||||||
|
}
|
||||||
|
|
||||||
|
func EtcdHealthCheck(data []byte) error {
|
||||||
|
obj := etcdHealth{}
|
||||||
|
if err := json.Unmarshal(data, &obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if obj.Health != "true" {
|
||||||
|
return fmt.Errorf("Unhealthy status: %s", obj.Health)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -856,3 +856,32 @@ func TestPrefixEtcdKey(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, keyBefore, keyAfter, "Prefix incorrectly added by EtcdHelper")
|
assert.Equal(t, keyBefore, keyAfter, "Prefix incorrectly added by EtcdHelper")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEtcdHealthCheck(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
data string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
data: "{\"health\": \"true\"}",
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "{\"health\": \"false\"}",
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "invalid json",
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
err := EtcdHealthCheck([]byte(test.data))
|
||||||
|
if err != nil && !test.expectErr {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if err == nil && test.expectErr {
|
||||||
|
t.Error("unexpected non-error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user