mirror of
https://github.com/openfaas/faas.git
synced 2025-06-10 09:16:48 +00:00
This changeset enables passing the basic auth credentials to all /system/ calls to allow upstream providers to perform authorization checks independent of the gateway. This is essential for some providers, like Swarm, where the system is accessible on the same network, and not protected via the gateway Signed-off-by: Burton Rheutan <rheutan7@gmail.com>
196 lines
8.2 KiB
Go
196 lines
8.2 KiB
Go
// Copyright (c) Alex Ellis 2017. All rights reserved.
|
|
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/openfaas/faas/gateway/handlers"
|
|
|
|
"github.com/openfaas/faas/gateway/metrics"
|
|
"github.com/openfaas/faas/gateway/plugin"
|
|
"github.com/openfaas/faas/gateway/types"
|
|
natsHandler "github.com/openfaas/nats-queue-worker/handler"
|
|
)
|
|
|
|
func main() {
|
|
|
|
osEnv := types.OsEnv{}
|
|
readConfig := types.ReadConfig{}
|
|
config := readConfig.Read(osEnv)
|
|
|
|
log.Printf("HTTP Read Timeout: %s", config.ReadTimeout)
|
|
log.Printf("HTTP Write Timeout: %s", config.WriteTimeout)
|
|
|
|
if !config.UseExternalProvider() {
|
|
log.Fatalln("You must provide an external provider via 'functions_provider_url' env-var.")
|
|
}
|
|
|
|
log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
|
|
|
|
var credentials *types.BasicAuthCredentials
|
|
|
|
if config.UseBasicAuth {
|
|
var readErr error
|
|
reader := types.ReadBasicAuthFromDisk{
|
|
SecretMountPath: config.SecretMountPath,
|
|
}
|
|
credentials, readErr = reader.Read()
|
|
|
|
if readErr != nil {
|
|
log.Panicf(readErr.Error())
|
|
}
|
|
}
|
|
|
|
var faasHandlers types.HandlerSet
|
|
|
|
servicePollInterval := time.Second * 5
|
|
|
|
metricsOptions := metrics.BuildMetricsOptions()
|
|
exporter := metrics.NewExporter(metricsOptions)
|
|
exporter.StartServiceWatcher(*config.FunctionsProviderURL, metricsOptions, "func", servicePollInterval)
|
|
metrics.RegisterExporter(exporter)
|
|
|
|
reverseProxy := types.NewHTTPClientReverseProxy(config.FunctionsProviderURL, config.UpstreamTimeout)
|
|
|
|
loggingNotifier := handlers.LoggingNotifier{}
|
|
prometheusNotifier := handlers.PrometheusFunctionNotifier{
|
|
Metrics: &metricsOptions,
|
|
}
|
|
functionNotifiers := []handlers.HTTPNotifier{loggingNotifier, prometheusNotifier}
|
|
forwardingNotifiers := []handlers.HTTPNotifier{loggingNotifier}
|
|
|
|
urlResolver := handlers.SingleHostBaseURLResolver{BaseURL: config.FunctionsProviderURL.String()}
|
|
var functionURLResolver handlers.BaseURLResolver
|
|
|
|
if config.DirectFunctions {
|
|
functionURLResolver = handlers.FunctionAsHostBaseURLResolver{FunctionSuffix: config.DirectFunctionsSuffix}
|
|
} else {
|
|
functionURLResolver = urlResolver
|
|
}
|
|
|
|
nilURLTransformer := handlers.TransparentURLPathTransformer{}
|
|
functionURLTransformer := handlers.FunctionPrefixTrimmingURLPathTransformer{}
|
|
|
|
faasHandlers.Proxy = handlers.MakeForwardingProxyHandler(reverseProxy, functionNotifiers, functionURLResolver, functionURLTransformer)
|
|
|
|
faasHandlers.RoutelessProxy = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
faasHandlers.ListFunctions = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
faasHandlers.DeployFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
faasHandlers.DeleteFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
faasHandlers.UpdateFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
queryFunction := handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
|
|
alertHandler := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL)
|
|
faasHandlers.Alert = handlers.MakeAlertHandler(alertHandler)
|
|
|
|
infoHandler := handlers.MakeInfoHandler(handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer))
|
|
|
|
if config.UseNATS() {
|
|
log.Println("Async enabled: Using NATS Streaming.")
|
|
natsQueue, queueErr := natsHandler.CreateNatsQueue(*config.NATSAddress, *config.NATSPort, natsHandler.DefaultNatsConfig{})
|
|
if queueErr != nil {
|
|
log.Fatalln(queueErr)
|
|
}
|
|
|
|
faasHandlers.QueuedProxy = handlers.MakeCallIDMiddleware(handlers.MakeQueuedProxy(metricsOptions, true, natsQueue, functionURLTransformer))
|
|
faasHandlers.AsyncReport = handlers.MakeAsyncReport(metricsOptions)
|
|
}
|
|
|
|
prometheusQuery := metrics.NewPrometheusQuery(config.PrometheusHost, config.PrometheusPort, &http.Client{})
|
|
faasHandlers.ListFunctions = metrics.AddMetricsHandler(faasHandlers.ListFunctions, prometheusQuery)
|
|
faasHandlers.Proxy = handlers.MakeCallIDMiddleware(faasHandlers.Proxy)
|
|
|
|
faasHandlers.ScaleFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
|
|
|
if credentials != nil {
|
|
faasHandlers.UpdateFunction =
|
|
handlers.DecorateWithBasicAuth(faasHandlers.UpdateFunction, credentials)
|
|
faasHandlers.DeleteFunction =
|
|
handlers.DecorateWithBasicAuth(faasHandlers.DeleteFunction, credentials)
|
|
faasHandlers.DeployFunction =
|
|
handlers.DecorateWithBasicAuth(faasHandlers.DeployFunction, credentials)
|
|
faasHandlers.ListFunctions =
|
|
handlers.DecorateWithBasicAuth(faasHandlers.ListFunctions, credentials)
|
|
faasHandlers.ScaleFunction =
|
|
handlers.DecorateWithBasicAuth(faasHandlers.ScaleFunction, credentials)
|
|
infoHandler = handlers.DecorateWithBasicAuth(infoHandler, credentials)
|
|
queryFunction = handlers.DecorateWithBasicAuth(queryFunction, credentials)
|
|
}
|
|
|
|
r := mux.NewRouter()
|
|
// max wait time to start a function = maxPollCount * functionPollInterval
|
|
|
|
functionProxy := faasHandlers.Proxy
|
|
|
|
if config.ScaleFromZero {
|
|
scalingConfig := handlers.ScalingConfig{
|
|
MaxPollCount: uint(1000),
|
|
FunctionPollInterval: time.Millisecond * 10,
|
|
CacheExpiry: time.Second * 5, // freshness of replica values before going stale
|
|
ServiceQuery: alertHandler,
|
|
}
|
|
|
|
functionProxy = handlers.MakeScalingHandler(faasHandlers.Proxy, queryFunction, scalingConfig)
|
|
}
|
|
// r.StrictSlash(false) // This didn't work, so register routes twice.
|
|
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", functionProxy)
|
|
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/", functionProxy)
|
|
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/{params:.*}", functionProxy)
|
|
|
|
r.HandleFunc("/system/info", infoHandler).Methods(http.MethodGet)
|
|
r.HandleFunc("/system/alert", faasHandlers.Alert)
|
|
|
|
r.HandleFunc("/system/function/{name:[-a-zA-Z_0-9]+}", queryFunction).Methods(http.MethodGet)
|
|
r.HandleFunc("/system/functions", faasHandlers.ListFunctions).Methods(http.MethodGet)
|
|
r.HandleFunc("/system/functions", faasHandlers.DeployFunction).Methods(http.MethodPost)
|
|
r.HandleFunc("/system/functions", faasHandlers.DeleteFunction).Methods(http.MethodDelete)
|
|
r.HandleFunc("/system/functions", faasHandlers.UpdateFunction).Methods(http.MethodPut)
|
|
r.HandleFunc("/system/scale-function/{name:[-a-zA-Z_0-9]+}", faasHandlers.ScaleFunction).Methods(http.MethodPost)
|
|
|
|
if faasHandlers.QueuedProxy != nil {
|
|
r.HandleFunc("/async-function/{name:[-a-zA-Z_0-9]+}/", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
|
r.HandleFunc("/async-function/{name:[-a-zA-Z_0-9]+}", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
|
r.HandleFunc("/async-function/{name:[-a-zA-Z_0-9]+}/{params:.*}", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/system/async-report", faasHandlers.AsyncReport)
|
|
}
|
|
|
|
fs := http.FileServer(http.Dir("./assets/"))
|
|
|
|
// This URL allows access from the UI to the OpenFaaS store
|
|
allowedCORSHost := "raw.githubusercontent.com"
|
|
fsCORS := handlers.DecorateWithCORS(fs, allowedCORSHost)
|
|
|
|
uiHandler := http.StripPrefix("/ui", fsCORS)
|
|
if credentials != nil {
|
|
r.PathPrefix("/ui/").Handler(handlers.DecorateWithBasicAuth(uiHandler.ServeHTTP, credentials)).Methods(http.MethodGet)
|
|
} else {
|
|
r.PathPrefix("/ui/").Handler(uiHandler).Methods(http.MethodGet)
|
|
}
|
|
|
|
metricsHandler := metrics.PrometheusHandler()
|
|
r.Handle("/metrics", metricsHandler)
|
|
r.HandleFunc("/healthz", handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)).Methods(http.MethodGet)
|
|
|
|
r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods(http.MethodGet)
|
|
|
|
tcpPort := 8080
|
|
|
|
s := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", tcpPort),
|
|
ReadTimeout: config.ReadTimeout,
|
|
WriteTimeout: config.WriteTimeout,
|
|
MaxHeaderBytes: http.DefaultMaxHeaderBytes, // 1MB - can be overridden by setting Server.MaxHeaderBytes.
|
|
Handler: r,
|
|
}
|
|
|
|
log.Fatal(s.ListenAndServe())
|
|
}
|