mirror of
https://github.com/openfaas/faas.git
synced 2025-06-22 06:43:23 +00:00
Feature for probing functions
Introduces a single-flight call to a function's health endpoint to verify that it is registered with an Istio sidecar (Envoy) before letting the invocation through. Results are cached for 5 seconds, before a probe is required again. Tested without Istio, with probe_functions environment variable set to true, I saw a probe execute in the logs. Fixes: #1721 for Istio users. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alex@openfaas.com>
This commit is contained in:
committed by
Alex Ellis
parent
01841f605c
commit
88eea5f62e
@ -10,40 +10,17 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"github.com/openfaas/faas/gateway/types"
|
||||
)
|
||||
|
||||
// functionMatcher parses out the service name (group 1) and rest of path (group 2).
|
||||
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")
|
||||
|
||||
// Indices and meta-data for functionMatcher regex parts
|
||||
const (
|
||||
hasPathCount = 3
|
||||
routeIndex = 0 // routeIndex corresponds to /function/ or /async-function/
|
||||
nameIndex = 1 // nameIndex is the function name
|
||||
pathIndex = 2 // pathIndex is the path i.e. /employee/:id/
|
||||
)
|
||||
|
||||
// BaseURLResolver URL resolver for upstream requests
|
||||
type BaseURLResolver interface {
|
||||
Resolve(r *http.Request) string
|
||||
}
|
||||
|
||||
// URLPathTransformer Transform the incoming URL path for upstream requests
|
||||
type URLPathTransformer interface {
|
||||
Transform(r *http.Request) string
|
||||
}
|
||||
|
||||
// MakeForwardingProxyHandler create a handler which forwards HTTP requests
|
||||
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy,
|
||||
notifiers []HTTPNotifier,
|
||||
baseURLResolver BaseURLResolver,
|
||||
urlPathTransformer URLPathTransformer,
|
||||
baseURLResolver middleware.BaseURLResolver,
|
||||
urlPathTransformer middleware.URLPathTransformer,
|
||||
serviceAuthInjector middleware.AuthInjector) http.HandlerFunc {
|
||||
|
||||
writeRequestURI := false
|
||||
@ -165,80 +142,6 @@ func deleteHeaders(target *http.Header, exclude *[]string) {
|
||||
}
|
||||
}
|
||||
|
||||
// SingleHostBaseURLResolver resolves URLs against a single BaseURL
|
||||
type SingleHostBaseURLResolver struct {
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (s SingleHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
|
||||
baseURL := s.BaseURL
|
||||
|
||||
if strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = baseURL[0 : len(baseURL)-1]
|
||||
}
|
||||
return baseURL
|
||||
}
|
||||
|
||||
// FunctionAsHostBaseURLResolver resolves URLs using a function from the URL as a host
|
||||
type FunctionAsHostBaseURLResolver struct {
|
||||
FunctionSuffix string
|
||||
FunctionNamespace string
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (f FunctionAsHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
svcName := getServiceName(r.URL.Path)
|
||||
|
||||
const watchdogPort = 8080
|
||||
var suffix string
|
||||
|
||||
if len(f.FunctionSuffix) > 0 {
|
||||
if index := strings.LastIndex(svcName, "."); index > -1 && len(svcName) > index+1 {
|
||||
suffix = strings.Replace(f.FunctionSuffix, f.FunctionNamespace, "", -1)
|
||||
} else {
|
||||
suffix = "." + f.FunctionSuffix
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("http://%s%s:%d", svcName, suffix, watchdogPort)
|
||||
}
|
||||
|
||||
// TransparentURLPathTransformer passes the requested URL path through untouched.
|
||||
type TransparentURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform returns the URL path unchanged.
|
||||
func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
|
||||
return r.URL.Path
|
||||
}
|
||||
|
||||
// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
|
||||
type FunctionPrefixTrimmingURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform removes the "/function/servicename/" prefix from the URL path.
|
||||
func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) string {
|
||||
ret := r.URL.Path
|
||||
|
||||
if ret != "" {
|
||||
// When forwarding to a function, since the `/function/xyz` portion
|
||||
// of a path like `/function/xyz/rest/of/path` is only used or needed
|
||||
// by the Gateway, we want to trim it down to `/rest/of/path` for the
|
||||
// upstream request. In the following regex, in the case of a match
|
||||
// the r.URL.Path will be at `0`, the function name at `1` and the
|
||||
// rest of the path (the part we are interested in) at `2`.
|
||||
matcher := functionMatcher.Copy()
|
||||
parts := matcher.FindStringSubmatch(ret)
|
||||
if len(parts) == hasPathCount {
|
||||
ret = parts[pathIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Hop-by-hop headers. These are removed when sent to the backend.
|
||||
// As of RFC 7230, hop-by-hop headers are required to appear in the
|
||||
// Connection header field. These are the headers defined by the
|
||||
|
Reference in New Issue
Block a user