mirror of https://github.com/k3s-io/k3s
Changed HTTPGetAction to allow user-defined schemes
parent
d581d1f6c0
commit
3008ff6150
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
config/
|
config/
|
||||||
secret.json
|
secret.json
|
||||||
|
*.log
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 == "" {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 == "" {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue