Changed HTTPGetAction to allow user-defined schemes

pull/6/head
Steve Kuznetsov 2015-06-25 13:53:41 -04:00
parent d581d1f6c0
commit 3008ff6150
23 changed files with 160 additions and 95 deletions

View File

@ -12722,6 +12722,10 @@
"host": { "host": {
"type": "string", "type": "string",
"description": "hostname to connect to; defaults to pod IP" "description": "hostname to connect to; defaults to pod IP"
},
"scheme": {
"type": "string",
"description": "scheme to connect with, must be HTTP or HTTPS, defaults to HTTP"
} }
} }
}, },

View File

@ -12724,6 +12724,10 @@
"host": { "host": {
"type": "string", "type": "string",
"description": "hostname to connect to; defaults to pod IP" "description": "hostname to connect to; defaults to pod IP"
},
"scheme": {
"type": "string",
"description": "scheme to connect with, must be HTTP or HTTPS, defaults to HTTP"
} }
} }
}, },

View File

@ -88,7 +88,7 @@ func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServ
EtcdHelper: helper, EtcdHelper: helper,
KubeletClient: &client.HTTPKubeletClient{ KubeletClient: &client.HTTPKubeletClient{
Client: http.DefaultClient, Client: http.DefaultClient,
Port: 10250, Config: &client.KubeletConfig{Port: 10250},
}, },
EnableCoreControllers: true, EnableCoreControllers: true,
EnableLogsSupport: false, EnableLogsSupport: false,

View File

@ -1,2 +1,3 @@
config/ config/
secret.json secret.json
*.log

View File

@ -505,6 +505,7 @@ func deepCopy_api_HTTPGetAction(in HTTPGetAction, out *HTTPGetAction, c *convers
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = in.Scheme
return nil return nil
} }

View File

@ -252,8 +252,9 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
s.Phase = api.NamespaceActive s.Phase = api.NamespaceActive
}, },
func(http *api.HTTPGetAction, c fuzz.Continue) { func(http *api.HTTPGetAction, c fuzz.Continue) {
c.FuzzNoCustom(http) // fuzz self without calling this function again c.FuzzNoCustom(http) // fuzz self without calling this function again
http.Path = "/" + http.Path // can't be blank http.Path = "/" + http.Path // can't be blank
http.Scheme = "x" + http.Scheme // can't be blank
}, },
func(ss *api.ServiceSpec, c fuzz.Continue) { func(ss *api.ServiceSpec, c fuzz.Continue) {
c.FuzzNoCustom(ss) // fuzz self without calling this function again c.FuzzNoCustom(ss) // fuzz self without calling this function again

View File

@ -610,8 +610,20 @@ type HTTPGetAction struct {
Port util.IntOrString `json:"port,omitempty"` Port util.IntOrString `json:"port,omitempty"`
// Optional: Host name to connect to, defaults to the pod IP. // Optional: Host name to connect to, defaults to the pod IP.
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
// Optional: Scheme to use for connecting to the host, defaults to HTTP.
Scheme URIScheme `json:"scheme,omitempty"`
} }
// URIScheme identifies the scheme used for connection to a host for Get actions
type URIScheme string
const (
// URISchemeHTTP means that the scheme used will be http://
URISchemeHTTP URIScheme = "HTTP"
// URISchemeHTTPS means that the scheme used will be https://
URISchemeHTTPS URIScheme = "HTTPS"
)
// TCPSocketAction describes an action based on opening a socket // TCPSocketAction describes an action based on opening a socket
type TCPSocketAction struct { type TCPSocketAction struct {
// Required: Port to connect to. // Required: Port to connect to.

View File

@ -592,6 +592,7 @@ func convert_api_HTTPGetAction_To_v1_HTTPGetAction(in *api.HTTPGetAction, out *H
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = URIScheme(in.Scheme)
return nil return nil
} }
@ -2903,6 +2904,7 @@ func convert_v1_HTTPGetAction_To_api_HTTPGetAction(in *HTTPGetAction, out *api.H
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = api.URIScheme(in.Scheme)
return nil return nil
} }

View File

@ -518,6 +518,7 @@ func deepCopy_v1_HTTPGetAction(in HTTPGetAction, out *HTTPGetAction, c *conversi
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = in.Scheme
return nil return nil
} }

View File

@ -137,6 +137,9 @@ func addDefaultingFuncs() {
if obj.Path == "" { if obj.Path == "" {
obj.Path = "/" obj.Path = "/"
} }
if obj.Scheme == "" {
obj.Scheme = URISchemeHTTP
}
}, },
func(obj *NamespaceStatus) { func(obj *NamespaceStatus) {
if obj.Phase == "" { if obj.Phase == "" {

View File

@ -586,8 +586,20 @@ type HTTPGetAction struct {
Port util.IntOrString `json:"port" description:"number or name of the port to access on the container"` Port util.IntOrString `json:"port" description:"number or name of the port to access on the container"`
// Optional: Host name to connect to, defaults to the pod IP. // Optional: Host name to connect to, defaults to the pod IP.
Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"`
// Optional: Scheme to use for connecting to the host, defaults to HTTP.
Scheme URIScheme `json:"scheme,omitempty" description:"scheme to connect with, must be HTTP or HTTPS, defaults to HTTP"`
} }
// URIScheme identifies the scheme used for connection to a host for Get actions
type URIScheme string
const (
// URISchemeHTTP means that the scheme used will be http://
URISchemeHTTP URIScheme = "HTTP"
// URISchemeHTTPS means that the scheme used will be https://
URISchemeHTTPS URIScheme = "HTTPS"
)
// TCPSocketAction describes an action based on opening a socket // TCPSocketAction describes an action based on opening a socket
type TCPSocketAction struct { type TCPSocketAction struct {
// Required: Port to connect to. // Required: Port to connect to.

View File

@ -450,6 +450,7 @@ func convert_api_HTTPGetAction_To_v1beta3_HTTPGetAction(in *api.HTTPGetAction, o
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = URIScheme(in.Scheme)
return nil return nil
} }
@ -2515,6 +2516,7 @@ func convert_v1beta3_HTTPGetAction_To_api_HTTPGetAction(in *HTTPGetAction, out *
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = api.URIScheme(in.Scheme)
return nil return nil
} }

View File

@ -522,6 +522,7 @@ func deepCopy_v1beta3_HTTPGetAction(in HTTPGetAction, out *HTTPGetAction, c *con
return err return err
} }
out.Host = in.Host out.Host = in.Host
out.Scheme = in.Scheme
return nil return nil
} }

View File

@ -141,6 +141,9 @@ func addDefaultingFuncs() {
if obj.Path == "" { if obj.Path == "" {
obj.Path = "/" obj.Path = "/"
} }
if obj.Scheme == "" {
obj.Scheme = URISchemeHTTP
}
}, },
func(obj *NamespaceStatus) { func(obj *NamespaceStatus) {
if obj.Phase == "" { if obj.Phase == "" {

View File

@ -586,8 +586,20 @@ type HTTPGetAction struct {
Port util.IntOrString `json:"port" description:"number or name of the port to access on the container"` Port util.IntOrString `json:"port" description:"number or name of the port to access on the container"`
// Optional: Host name to connect to, defaults to the pod IP. // Optional: Host name to connect to, defaults to the pod IP.
Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"`
// Optional: Scheme to use for connecting to the host, defaults to HTTP.
Scheme URIScheme `json:"scheme,omitempty" description:"scheme to connect with, must be HTTP or HTTPS, defaults to HTTP"`
} }
// URIScheme identifies the scheme used for connection to a host for Get actions
type URIScheme string
const (
// URISchemeHTTP means that the scheme used will be http://
URISchemeHTTP URIScheme = "HTTP"
// URISchemeHTTPS means that the scheme used will be https://
URISchemeHTTPS URIScheme = "HTTPS"
)
// TCPSocketAction describes an action based on opening a socket // TCPSocketAction describes an action based on opening a socket
type TCPSocketAction struct { type TCPSocketAction struct {
// Required: Port to connect to. // Required: Port to connect to.

View File

@ -762,6 +762,10 @@ func validateHTTPGetAction(http *api.HTTPGetAction) errs.ValidationErrorList {
} else if http.Port.Kind == util.IntstrString && len(http.Port.StrVal) == 0 { } else if http.Port.Kind == util.IntstrString && len(http.Port.StrVal) == 0 {
allErrors = append(allErrors, errs.NewFieldRequired("port")) allErrors = append(allErrors, errs.NewFieldRequired("port"))
} }
supportedSchemes := util.NewStringSet(string(api.URISchemeHTTP), string(api.URISchemeHTTPS))
if !supportedSchemes.Has(string(http.Scheme)) {
allErrors = append(allErrors, errs.NewFieldInvalid("scheme", http.Scheme, fmt.Sprintf("must be one of %v", supportedSchemes.List())))
}
return allErrors return allErrors
} }

View File

@ -712,9 +712,9 @@ func TestValidateProbe(t *testing.T) {
func TestValidateHandler(t *testing.T) { func TestValidateHandler(t *testing.T) {
successCases := []api.Handler{ successCases := []api.Handler{
{Exec: &api.ExecAction{Command: []string{"echo"}}}, {Exec: &api.ExecAction{Command: []string{"echo"}}},
{HTTPGet: &api.HTTPGetAction{Path: "/", Port: util.NewIntOrStringFromInt(1), Host: ""}}, {HTTPGet: &api.HTTPGetAction{Path: "/", Port: util.NewIntOrStringFromInt(1), Host: "", Scheme: "HTTP"}},
{HTTPGet: &api.HTTPGetAction{Path: "/foo", Port: util.NewIntOrStringFromInt(65535), Host: "host"}}, {HTTPGet: &api.HTTPGetAction{Path: "/foo", Port: util.NewIntOrStringFromInt(65535), Host: "host", Scheme: "HTTP"}},
{HTTPGet: &api.HTTPGetAction{Path: "/", Port: util.NewIntOrStringFromString("port"), Host: ""}}, {HTTPGet: &api.HTTPGetAction{Path: "/", Port: util.NewIntOrStringFromString("port"), Host: "", Scheme: "HTTP"}},
} }
for _, h := range successCases { for _, h := range successCases {
if errs := validateHandler(&h); len(errs) != 0 { if errs := validateHandler(&h); len(errs) != 0 {

View File

@ -44,10 +44,8 @@ type ConnectionInfoGetter interface {
// HTTPKubeletClient is the default implementation of KubeletHealthchecker, accesses the kubelet over HTTP. // HTTPKubeletClient is the default implementation of KubeletHealthchecker, accesses the kubelet over HTTP.
type HTTPKubeletClient struct { type HTTPKubeletClient struct {
Client *http.Client Client *http.Client
Config *KubeletConfig Config *KubeletConfig
Port uint
EnableHttps bool
} }
func MakeTransport(config *KubeletConfig) (http.RoundTripper, error) { func MakeTransport(config *KubeletConfig) (http.RoundTripper, error) {
@ -83,33 +81,31 @@ func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) {
Timeout: config.HTTPTimeout, Timeout: config.HTTPTimeout,
} }
return &HTTPKubeletClient{ return &HTTPKubeletClient{
Client: c, Client: c,
Config: config, Config: config,
Port: config.Port,
EnableHttps: config.EnableHttps,
}, nil }, nil
} }
func (c *HTTPKubeletClient) GetConnectionInfo(host string) (string, uint, http.RoundTripper, error) { func (c *HTTPKubeletClient) GetConnectionInfo(host string) (string, uint, http.RoundTripper, error) {
scheme := "http" scheme := "http"
if c.EnableHttps { if c.Config.EnableHttps {
scheme = "https" scheme = "https"
} }
return scheme, c.Port, c.Client.Transport, nil return scheme, c.Config.Port, c.Client.Transport, nil
} }
func (c *HTTPKubeletClient) url(host, path, query string) string { func (c *HTTPKubeletClient) url(host, path, query string) *url.URL {
scheme := "http" scheme := "http"
if c.EnableHttps { if c.Config.EnableHttps {
scheme = "https" scheme = "https"
} }
return (&url.URL{ return &url.URL{
Scheme: scheme, Scheme: scheme,
Host: net.JoinHostPort(host, strconv.FormatUint(uint64(c.Port), 10)), Host: net.JoinHostPort(host, strconv.FormatUint(uint64(c.Config.Port), 10)),
Path: path, Path: path,
RawQuery: query, RawQuery: query,
}).String() }
} }
func (c *HTTPKubeletClient) HealthCheck(host string) (probe.Result, string, error) { func (c *HTTPKubeletClient) HealthCheck(host string) (probe.Result, string, error) {

View File

@ -57,7 +57,7 @@ func TestHTTPKubeletClient(t *testing.T) {
c := &HTTPKubeletClient{ c := &HTTPKubeletClient{
Client: http.DefaultClient, Client: http.DefaultClient,
Port: uint(port), Config: &KubeletConfig{Port: uint(port)},
} }
gotObj, _, err := c.HealthCheck(parts[0]) gotObj, _, err := c.HealthCheck(parts[0])
if err != nil { if err != nil {
@ -91,7 +91,7 @@ func TestHTTPKubeletClientError(t *testing.T) {
c := &HTTPKubeletClient{ c := &HTTPKubeletClient{
Client: http.DefaultClient, Client: http.DefaultClient,
Port: uint(port), Config: &KubeletConfig{Port: uint(port)},
} }
gotObj, _, err := c.HealthCheck(parts[0]) gotObj, _, err := c.HealthCheck(parts[0])
if gotObj != expectObj { if gotObj != expectObj {

View File

@ -18,7 +18,10 @@ package prober
import ( import (
"fmt" "fmt"
"net"
"net/url"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
@ -200,13 +203,19 @@ func (pb *prober) runProbe(p *api.Probe, pod *api.Pod, status api.PodStatus, con
return pb.exec.Probe(pb.newExecInContainer(pod, container, containerID, p.Exec.Command)) return pb.exec.Probe(pb.newExecInContainer(pod, container, containerID, p.Exec.Command))
} }
if p.HTTPGet != nil { if p.HTTPGet != nil {
scheme := strings.ToLower(string(p.HTTPGet.Scheme))
host := p.HTTPGet.Host
if host == "" {
host = status.PodIP
}
port, err := extractPort(p.HTTPGet.Port, container) port, err := extractPort(p.HTTPGet.Port, container)
if err != nil { if err != nil {
return probe.Unknown, "", err return probe.Unknown, "", err
} }
host, port, path := extractGetParams(p.HTTPGet, status, port) path := p.HTTPGet.Path
glog.V(4).Infof("HTTP-Probe Host: %v, Port: %v, Path: %v", host, port, path) glog.V(4).Infof("HTTP-Probe Host: %v://%v, Port: %v, Path: %v", scheme, host, port, path)
return pb.http.Probe(host, port, path, timeout) url := formatURL(scheme, host, port, path)
return pb.http.Probe(url, timeout)
} }
if p.TCPSocket != nil { if p.TCPSocket != nil {
port, err := extractPort(p.TCPSocket.Port, container) port, err := extractPort(p.TCPSocket.Port, container)
@ -220,50 +229,45 @@ func (pb *prober) runProbe(p *api.Probe, pod *api.Pod, status api.PodStatus, con
return probe.Unknown, "", nil return probe.Unknown, "", nil
} }
func extractGetParams(action *api.HTTPGetAction, status api.PodStatus, port int) (string, int, string) {
host := action.Host
if host == "" {
host = status.PodIP
}
return host, port, action.Path
}
func extractPort(param util.IntOrString, container api.Container) (int, error) { func extractPort(param util.IntOrString, container api.Container) (int, error) {
port := -1 port := -1
var err error var err error
switch param.Kind { switch param.Kind {
case util.IntstrInt: case util.IntstrInt:
port := param.IntVal port = param.IntVal
if port > 0 && port < 65536 {
return port, nil
}
return port, fmt.Errorf("invalid port number: %v", port)
case util.IntstrString: case util.IntstrString:
port = findPortByName(container, param.StrVal) if port, err = findPortByName(container, param.StrVal); err != nil {
if port == -1 {
// Last ditch effort - maybe it was an int stored as string? // Last ditch effort - maybe it was an int stored as string?
if port, err = strconv.Atoi(param.StrVal); err != nil { if port, err = strconv.Atoi(param.StrVal); err != nil {
return port, err return port, err
} }
} }
if port > 0 && port < 65536 {
return port, nil
}
return port, fmt.Errorf("invalid port number: %v", port)
default: default:
return port, fmt.Errorf("IntOrString had no kind: %+v", param) return port, fmt.Errorf("IntOrString had no kind: %+v", param)
} }
if port > 0 && port < 65536 {
return port, nil
}
return port, fmt.Errorf("invalid port number: %v", port)
} }
// findPortByName is a helper function to look up a port in a container by name. // findPortByName is a helper function to look up a port in a container by name.
// Returns the HostPort if found, -1 if not found. func findPortByName(container api.Container, portName string) (int, error) {
func findPortByName(container api.Container, portName string) int {
for _, port := range container.Ports { for _, port := range container.Ports {
if port.Name == portName { if port.Name == portName {
return port.HostPort return port.HostPort, nil
} }
} }
return -1 return 0, fmt.Errorf("port %s not found", portName)
}
// formatURL formats a URL from args. For testability.
func formatURL(scheme string, host string, port int, path string) *url.URL {
return &url.URL{
Scheme: scheme,
Host: net.JoinHostPort(host, strconv.Itoa(port)),
Path: path,
}
} }
type execInContainer struct { type execInContainer struct {

View File

@ -25,6 +25,25 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
) )
func TestFormatURL(t *testing.T) {
testCases := []struct {
scheme string
host string
port int
path string
result string
}{
{"http", "localhost", 93, "", "http://localhost:93"},
{"https", "localhost", 93, "/path", "https://localhost:93/path"},
}
for _, test := range testCases {
url := formatURL(test.scheme, test.host, test.port, test.path)
if url.String() != test.result {
t.Errorf("Expected %s, got %s", test.result, url.String())
}
}
}
func TestFindPortByName(t *testing.T) { func TestFindPortByName(t *testing.T) {
container := api.Container{ container := api.Container{
Ports: []api.ContainerPort{ Ports: []api.ContainerPort{
@ -39,9 +58,9 @@ func TestFindPortByName(t *testing.T) {
}, },
} }
want := 8080 want := 8080
got := findPortByName(container, "foo") got, err := findPortByName(container, "foo")
if got != want { if got != want || err != nil {
t.Errorf("Expected %v, got %v", want, got) t.Errorf("Expected %v, got %v, err: %v", want, got, err)
} }
} }
@ -73,13 +92,23 @@ func TestGetURLParts(t *testing.T) {
}, },
}, },
} }
p, err := extractPort(test.probe.Port, container)
scheme := test.probe.Scheme
if scheme == "" {
scheme = api.URISchemeHTTP
}
host := test.probe.Host
if host == "" {
host = state.PodIP
}
port, err := extractPort(test.probe.Port, container)
if test.ok && err != nil { if test.ok && err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
host, port, path := extractGetParams(test.probe, state, p) path := test.probe.Path
if !test.ok && err == nil { if !test.ok && err == nil {
t.Errorf("Expected error for %+v, got %s:%d/%s", test, host, port, path) t.Errorf("Expected error for %+v, got %s%s:%d/%s", test, scheme, host, port, path)
} }
if test.ok { if test.ok {
if host != test.host || port != test.port || path != test.path { if host != test.host || port != test.port || path != test.path {

View File

@ -17,11 +17,10 @@ limitations under the License.
package http package http
import ( import (
"crypto/tls"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
@ -30,12 +29,13 @@ import (
) )
func New() HTTPProber { func New() HTTPProber {
transport := &http.Transport{} tlsConfig := &tls.Config{InsecureSkipVerify: true}
transport := &http.Transport{TLSClientConfig: tlsConfig}
return httpProber{transport} return httpProber{transport}
} }
type HTTPProber interface { type HTTPProber interface {
Probe(host string, port int, path string, timeout time.Duration) (probe.Result, string, error) Probe(url *url.URL, timeout time.Duration) (probe.Result, string, error)
} }
type httpProber struct { type httpProber struct {
@ -43,8 +43,8 @@ type httpProber struct {
} }
// Probe returns a ProbeRunner capable of running an http check. // Probe returns a ProbeRunner capable of running an http check.
func (pr httpProber) Probe(host string, port int, path string, timeout time.Duration) (probe.Result, string, error) { func (pr httpProber) Probe(url *url.URL, timeout time.Duration) (probe.Result, string, error) {
return DoHTTPProbe(formatURL(host, port, path), &http.Client{Timeout: timeout, Transport: pr.transport}) return DoHTTPProbe(url, &http.Client{Timeout: timeout, Transport: pr.transport})
} }
type HTTPGetInterface interface { type HTTPGetInterface interface {
@ -55,8 +55,8 @@ type HTTPGetInterface interface {
// If the HTTP response code is successful (i.e. 400 > code >= 200), it returns Success. // If the HTTP response code is successful (i.e. 400 > code >= 200), it returns Success.
// If the HTTP response code is unsuccessful or HTTP communication fails, it returns Failure. // If the HTTP response code is unsuccessful or HTTP communication fails, it returns Failure.
// This is exported because some other packages may want to do direct HTTP probes. // This is exported because some other packages may want to do direct HTTP probes.
func DoHTTPProbe(url string, client HTTPGetInterface) (probe.Result, string, error) { func DoHTTPProbe(url *url.URL, client HTTPGetInterface) (probe.Result, string, error) {
res, err := client.Get(url) res, err := client.Get(url.String())
if err != nil { if err != nil {
// Convert errors into failures to catch timeouts. // Convert errors into failures to catch timeouts.
return probe.Failure, err.Error(), nil return probe.Failure, err.Error(), nil
@ -68,18 +68,9 @@ func DoHTTPProbe(url string, client HTTPGetInterface) (probe.Result, string, err
} }
body := string(b) body := string(b)
if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest { if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest {
glog.V(4).Infof("Probe succeeded for %s, Response: %v", url.String(), *res)
return probe.Success, body, nil return probe.Success, body, nil
} }
glog.V(4).Infof("Probe failed for %s, Response: %v", url, *res) glog.V(4).Infof("Probe failed for %s, Response: %v", url.String(), *res)
return probe.Failure, body, nil return probe.Failure, body, nil
} }
// formatURL formats a URL from args. For testability.
func formatURL(host string, port int, path string) string {
u := url.URL{
Scheme: "http",
Host: net.JoinHostPort(host, strconv.Itoa(port)),
Path: path,
}
return u.String()
}

View File

@ -29,24 +29,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
) )
func TestFormatURL(t *testing.T) {
testCases := []struct {
host string
port int
path string
result string
}{
{"localhost", 93, "", "http://localhost:93"},
{"localhost", 93, "/path", "http://localhost:93/path"},
}
for _, test := range testCases {
url := formatURL(test.host, test.port, test.path)
if url != test.result {
t.Errorf("Expected %s, got %s", test.result, url)
}
}
}
func TestHTTPProbeChecker(t *testing.T) { func TestHTTPProbeChecker(t *testing.T) {
handleReq := func(s int, body string) func(w http.ResponseWriter) { handleReq := func(s int, body string) func(w http.ResponseWriter) {
return func(w http.ResponseWriter) { return func(w http.ResponseWriter) {
@ -74,15 +56,15 @@ func TestHTTPProbeChecker(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
host, port, err := net.SplitHostPort(u.Host) _, port, err := net.SplitHostPort(u.Host)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
p, err := strconv.Atoi(port) _, err = strconv.Atoi(port)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
health, output, err := prober.Probe(host, p, "", 1*time.Second) health, output, err := prober.Probe(u, 1*time.Second)
if test.health == probe.Unknown && err == nil { if test.health == probe.Unknown && err == nil {
t.Errorf("Expected error") t.Errorf("Expected error")
} }