332 lines
7.8 KiB
Go
332 lines
7.8 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
httpv1alpha1 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1"
|
|
"github.com/kedacore/http-add-on/pkg/k8s"
|
|
routingtest "github.com/kedacore/http-add-on/pkg/routing/test"
|
|
)
|
|
|
|
var _ = Describe("RoutingMiddleware", func() {
|
|
Context("New", func() {
|
|
It("returns new object with expected fields", func() {
|
|
var (
|
|
routingTable = routingtest.NewTable()
|
|
probeHandler = http.NewServeMux()
|
|
upstreamHandler = http.NewServeMux()
|
|
)
|
|
emptyHandler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
|
|
probeHandler.Handle("/probe", emptyHandler)
|
|
upstreamHandler.Handle("/upstream", emptyHandler)
|
|
svcCache := k8s.NewFakeServiceCache()
|
|
|
|
rm := NewRouting(routingTable, probeHandler, upstreamHandler, svcCache, false)
|
|
Expect(rm).NotTo(BeNil())
|
|
Expect(rm.routingTable).To(Equal(routingTable))
|
|
Expect(rm.probeHandler).To(Equal(probeHandler))
|
|
Expect(rm.upstreamHandler).To(Equal(upstreamHandler))
|
|
})
|
|
})
|
|
|
|
Context("ServeHTTP", func() {
|
|
const (
|
|
host = "keda.sh"
|
|
path = "/README"
|
|
)
|
|
|
|
var (
|
|
upstreamHandler *http.ServeMux
|
|
probeHandler *http.ServeMux
|
|
svcCache *k8s.FakeServiceCache
|
|
routingTable *routingtest.Table
|
|
routingMiddleware *Routing
|
|
w *httptest.ResponseRecorder
|
|
r *http.Request
|
|
|
|
httpso = httpv1alpha1.HTTPScaledObject{
|
|
Spec: httpv1alpha1.HTTPScaledObjectSpec{
|
|
Hosts: []string{
|
|
host,
|
|
},
|
|
ScaleTargetRef: httpv1alpha1.ScaleTargetRef{
|
|
Port: 80,
|
|
},
|
|
},
|
|
}
|
|
|
|
httpsoWithPortName = httpv1alpha1.HTTPScaledObject{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "keda",
|
|
Namespace: "default",
|
|
},
|
|
Spec: httpv1alpha1.HTTPScaledObjectSpec{
|
|
Hosts: []string{
|
|
"keda2.sh",
|
|
},
|
|
ScaleTargetRef: httpv1alpha1.ScaleTargetRef{
|
|
Service: "keda-svc",
|
|
PortName: "http",
|
|
},
|
|
},
|
|
}
|
|
svc = &corev1.Service{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "keda-svc",
|
|
Namespace: "default",
|
|
},
|
|
Spec: corev1.ServiceSpec{
|
|
Ports: []corev1.ServicePort{
|
|
{
|
|
Name: "http",
|
|
Port: 80,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
upstreamHandler = http.NewServeMux()
|
|
probeHandler = http.NewServeMux()
|
|
routingTable = routingtest.NewTable()
|
|
svcCache = k8s.NewFakeServiceCache()
|
|
routingMiddleware = NewRouting(routingTable, probeHandler, upstreamHandler, svcCache, false)
|
|
|
|
w = httptest.NewRecorder()
|
|
|
|
r = httptest.NewRequest(http.MethodGet, path, nil)
|
|
r.Host = host
|
|
})
|
|
|
|
When("route is found", func() {
|
|
It("routes to the upstream handler", func() {
|
|
var (
|
|
sc = http.StatusTeapot
|
|
st = http.StatusText(sc)
|
|
)
|
|
|
|
var uh bool
|
|
upstreamHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusTeapot)
|
|
|
|
_, err := w.Write([]byte(st))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
uh = true
|
|
}))
|
|
|
|
var ph bool
|
|
probeHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ph = true
|
|
}))
|
|
|
|
routingTable.Memory[host] = &httpso
|
|
|
|
routingMiddleware.ServeHTTP(w, r)
|
|
Expect(uh).To(BeTrue())
|
|
Expect(ph).To(BeFalse())
|
|
Expect(w.Code).To(Equal(sc))
|
|
Expect(w.Body.String()).To(Equal(st))
|
|
})
|
|
})
|
|
|
|
When("route is found with portName", func() {
|
|
It("routes to the upstream handler", func() {
|
|
svcCache.Add(*svc)
|
|
var (
|
|
sc = http.StatusTeapot
|
|
st = http.StatusText(sc)
|
|
)
|
|
|
|
var uh bool
|
|
upstreamHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusTeapot)
|
|
|
|
_, err := w.Write([]byte(st))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
uh = true
|
|
}))
|
|
|
|
var ph bool
|
|
probeHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ph = true
|
|
}))
|
|
|
|
routingTable.Memory["keda2.sh"] = &httpsoWithPortName
|
|
|
|
r.Host = "keda2.sh"
|
|
routingMiddleware.ServeHTTP(w, r)
|
|
Expect(uh).To(BeTrue())
|
|
Expect(ph).To(BeFalse())
|
|
Expect(w.Code).To(Equal(sc))
|
|
Expect(w.Body.String()).To(Equal(st))
|
|
})
|
|
})
|
|
|
|
When("route is found with portName but endpoints are mismatched", func() {
|
|
It("errors to route to upstream handler", func() {
|
|
var (
|
|
sc = http.StatusTeapot
|
|
st = http.StatusText(sc)
|
|
)
|
|
|
|
var uh bool
|
|
upstreamHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusTeapot)
|
|
|
|
_, err := w.Write([]byte(st))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
uh = true
|
|
}))
|
|
|
|
var ph bool
|
|
probeHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ph = true
|
|
}))
|
|
|
|
routingTable.Memory["keda2.sh"] = &httpsoWithPortName
|
|
|
|
r.Host = "keda2.sh"
|
|
routingMiddleware.ServeHTTP(w, r)
|
|
Expect(uh).To(BeFalse())
|
|
Expect(ph).To(BeFalse())
|
|
Expect(w.Code).To(Equal(http.StatusInternalServerError))
|
|
Expect(w.Body.String()).To(Equal("Internal Server Error"))
|
|
})
|
|
})
|
|
|
|
When("route is not found", func() {
|
|
It("routes to the probe handler", func() {
|
|
const (
|
|
uaKey = "User-Agent"
|
|
uaVal = "kube-probe/0"
|
|
)
|
|
|
|
var (
|
|
sc = http.StatusTeapot
|
|
st = http.StatusText(sc)
|
|
)
|
|
|
|
var uh bool
|
|
upstreamHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
uh = true
|
|
}))
|
|
|
|
var ph bool
|
|
probeHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusTeapot)
|
|
|
|
_, err := w.Write([]byte(st))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
ph = true
|
|
}))
|
|
|
|
r.Header.Set(uaKey, uaVal)
|
|
|
|
routingMiddleware.ServeHTTP(w, r)
|
|
|
|
Expect(uh).To(BeFalse())
|
|
Expect(ph).To(BeTrue())
|
|
Expect(w.Code).To(Equal(sc))
|
|
Expect(w.Body.String()).To(Equal(st))
|
|
})
|
|
|
|
It("serves 404", func() {
|
|
var (
|
|
sc = http.StatusNotFound
|
|
st = http.StatusText(sc)
|
|
)
|
|
|
|
var uh bool
|
|
upstreamHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
uh = true
|
|
}))
|
|
|
|
var ph bool
|
|
probeHandler.Handle(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ph = true
|
|
}))
|
|
|
|
routingMiddleware.ServeHTTP(w, r)
|
|
|
|
Expect(uh).To(BeFalse())
|
|
Expect(ph).To(BeFalse())
|
|
Expect(w.Code).To(Equal(sc))
|
|
Expect(w.Body.String()).To(Equal(st))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("isKubeProbe", func() {
|
|
const (
|
|
uaKey = "User-Agent"
|
|
)
|
|
|
|
var (
|
|
r *http.Request
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
r = httptest.NewRequest(http.MethodGet, "/", nil)
|
|
})
|
|
|
|
It("returns true if the request is from kube-probe", func() {
|
|
const (
|
|
uaVal = "Go-http-client/1.1 kube-probe/1.27.1 (linux/amd64) kubernetes/4c94112"
|
|
)
|
|
|
|
r.Header.Set(uaKey, uaVal)
|
|
|
|
var rm Routing
|
|
b := rm.isProbe(r)
|
|
Expect(b).To(BeTrue())
|
|
})
|
|
|
|
It("returns true if the request is from GoogleHC", func() {
|
|
const (
|
|
uaVal = "Go-http-client/1.1 GoogleHC/1.0 (linux/amd64) kubernetes/4c94112"
|
|
)
|
|
|
|
r.Header.Set(uaKey, uaVal)
|
|
|
|
var rm Routing
|
|
b := rm.isProbe(r)
|
|
Expect(b).To(BeTrue())
|
|
})
|
|
|
|
It("returns true if the request is from AWS ELB", func() {
|
|
const (
|
|
uaVal = "Go-http-client/1.1 ELB-HealthChecker/2.0 (linux/amd64) kubernetes/4c94112"
|
|
)
|
|
|
|
r.Header.Set(uaKey, uaVal)
|
|
|
|
var rm Routing
|
|
b := rm.isProbe(r)
|
|
Expect(b).To(BeTrue())
|
|
})
|
|
|
|
It("returns false if the request is not from kube-probe or GoogleHC or ELB-HealthChecker", func() {
|
|
const (
|
|
uaVal = "Go-http-client/1.1 kubectl/v1.27.1 (linux/amd64) kubernetes/4c94112"
|
|
)
|
|
|
|
r.Header.Set(uaKey, uaVal)
|
|
|
|
var rm Routing
|
|
b := rm.isProbe(r)
|
|
Expect(b).To(BeFalse())
|
|
})
|
|
})
|
|
})
|