diff --git a/gateway/Dockerfile b/gateway/Dockerfile index 58f912b0..b3d738a8 100644 --- a/gateway/Dockerfile +++ b/gateway/Dockerfile @@ -1,6 +1,6 @@ FROM --platform=${BUILDPLATFORM:-linux/amd64} teamserverless/license-check:0.3.9 as license-check -FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.15 as build +FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.17 as build ENV GO111MODULE=on ENV CGO_ENABLED=0 @@ -24,7 +24,6 @@ COPY go.sum go.sum COPY handlers handlers COPY metrics metrics COPY requests requests -COPY tests tests COPY types types COPY plugin plugin diff --git a/gateway/go.mod b/gateway/go.mod index e0027141..ffd14100 100644 --- a/gateway/go.mod +++ b/gateway/go.mod @@ -5,9 +5,7 @@ go 1.16 require ( github.com/docker/distribution v2.7.1+incompatible github.com/gorilla/mux v1.8.0 - github.com/nats-io/nats-server/v2 v2.3.2 // indirect - github.com/nats-io/nats-streaming-server v0.22.0 // indirect - github.com/openfaas/faas-provider v0.18.6 + github.com/openfaas/faas-provider v0.18.7 github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9 github.com/prometheus/client_golang v1.9.0 github.com/prometheus/client_model v0.2.0 diff --git a/gateway/go.sum b/gateway/go.sum index e7348855..952e2a66 100644 --- a/gateway/go.sum +++ b/gateway/go.sum @@ -71,7 +71,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -93,7 +92,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= @@ -105,8 +103,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -141,7 +139,6 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -176,12 +173,9 @@ github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -245,10 +239,9 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/openfaas/faas v0.0.0-20200422113858-a7c6c3920078/go.mod h1:E0m2rLup0Vvxg53BKxGgaYAGcZa3Xl+vvL7vSi5yQ14= -github.com/openfaas/faas-provider v0.18.6 h1:wypzvPKZqta8t4rx3W6Dm14ommBCc+rQ4DKDiBdGB7M= github.com/openfaas/faas-provider v0.18.6/go.mod h1:fq1JL0mX4rNvVVvRLaLRJ3H6o667sHuyP5p/7SZEe98= -github.com/openfaas/nats-queue-worker v0.0.0-20210726161233-3fa550b705fe/go.mod h1:njdij5dt/fm8EMrpUFiAW5u6tg7higDN+Xi+LXclDas= +github.com/openfaas/faas-provider v0.18.7 h1:Oq3N7KrlAkAZ23N5gzZfdA9F62vpUFk3ZkQpQuHeRBU= +github.com/openfaas/faas-provider v0.18.7/go.mod h1:S217qfIaMrv+XKJxgbhBzJzCfyFvoIF+BvYdDo6XIDQ= github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9 h1:dpG1UcgTesGfLetgT3ns1cAhP8XMDZqxnxTW1MlnwSc= github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9/go.mod h1:ajlN2z+D8JPBq3kWNv4WLT6mtKPqlgeE3dYEx39d1tk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= @@ -261,7 +254,6 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -378,7 +370,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -495,7 +486,6 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= @@ -503,7 +493,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/gateway/main.go b/gateway/main.go index 1c458e52..dfa883a7 100644 --- a/gateway/main.go +++ b/gateway/main.go @@ -25,6 +25,7 @@ import ( const NameExpression = "-a-zA-Z_0-9." func main() { + if len(version.GitCommitMessage) == 0 { version.GitCommitMessage = "See GitHub for latest changes" } @@ -125,7 +126,7 @@ func main() { faasHandlers.DeployFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) faasHandlers.DeleteFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) faasHandlers.UpdateFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) - faasHandlers.QueryFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) + faasHandlers.FunctionStatus = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) faasHandlers.InfoHandler = handlers.MakeInfoHandler(handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)) faasHandlers.SecretHandler = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector) @@ -198,8 +199,8 @@ func main() { decorateExternalAuth(faasHandlers.ListFunctions, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody) faasHandlers.ScaleFunction = decorateExternalAuth(faasHandlers.ScaleFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody) - faasHandlers.QueryFunction = - decorateExternalAuth(faasHandlers.QueryFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody) + faasHandlers.FunctionStatus = + decorateExternalAuth(faasHandlers.FunctionStatus, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody) faasHandlers.InfoHandler = decorateExternalAuth(faasHandlers.InfoHandler, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody) faasHandlers.AsyncReport = @@ -222,7 +223,7 @@ func main() { r.HandleFunc("/system/info", faasHandlers.InfoHandler).Methods(http.MethodGet) r.HandleFunc("/system/alert", faasHandlers.Alert).Methods(http.MethodPost) - r.HandleFunc("/system/function/{name:["+NameExpression+"]+}", faasHandlers.QueryFunction).Methods(http.MethodGet) + r.HandleFunc("/system/function/{name:["+NameExpression+"]+}", faasHandlers.FunctionStatus).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) diff --git a/gateway/metrics/add_metrics.go b/gateway/metrics/add_metrics.go index ef3b0ff5..50fab7bd 100644 --- a/gateway/metrics/add_metrics.go +++ b/gateway/metrics/add_metrics.go @@ -35,9 +35,7 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery recorder.Code, string(upstreamBody)) - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("List functions responded with code %d", recorder.Code))) + http.Error(w, "Unexpected status code retriving functions from backend", http.StatusInternalServerError) return } @@ -48,28 +46,33 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery if err != nil { log.Printf("Metrics upstream error: %s", err) - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Error parsing metrics from upstream provider/backend.")) + http.Error(w, "Error parsing metrics from upstream provider/backend", http.StatusInternalServerError) return } - expr := url.QueryEscape(`sum(gateway_function_invocation_total{function_name=~".*", code=~".*"}) by (function_name, code)`) - // expr := "sum(gateway_function_invocation_total%7Bfunction_name%3D~%22.*%22%2C+code%3D~%22.*%22%7D)+by+(function_name%2C+code)" - results, fetchErr := prometheusQuery.Fetch(expr) - if fetchErr != nil { - log.Printf("Error querying Prometheus API: %s\n", fetchErr.Error()) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(upstreamBody) - return + // Ensure values are empty first. + for i := range functions { + functions[i].InvocationCount = 0 } - mixIn(&functions, results) + if len(functions) > 0 { - bytesOut, marshalErr := json.Marshal(functions) - if marshalErr != nil { - log.Println(marshalErr) + ns := functions[0].Namespace + q := fmt.Sprintf(`sum(gateway_function_invocation_total{function_name=~".*.%s"}) by (function_name)`, ns) + // Restrict query results to only function names matching namespace suffix. + + results, err := prometheusQuery.Fetch(url.QueryEscape(q)) + if err != nil { + log.Printf("Error querying Prometheus: %s\n", err.Error()) + return + } + mixIn(&functions, results) + } + + bytesOut, err := json.Marshal(functions) + if err != nil { + log.Printf("Error serializing functions: %s", err) + http.Error(w, "error writing response after adding metrics", http.StatusInternalServerError) return } @@ -85,25 +88,19 @@ func mixIn(functions *[]types.FunctionStatus, metrics *VectorQueryResponse) { return } - // Ensure values are empty first. - for i := range *functions { - (*functions)[i].InvocationCount = 0 - } - for i, function := range *functions { for _, v := range metrics.Data.Result { if v.Metric.FunctionName == fmt.Sprintf("%s.%s", function.Name, function.Namespace) { metricValue := v.Value[1] - switch metricValue.(type) { + switch value := metricValue.(type) { case string: - f, strconvErr := strconv.ParseFloat(metricValue.(string), 64) - if strconvErr != nil { - log.Printf("Unable to convert value for metric: %s\n", strconvErr) + f, err := strconv.ParseFloat(value, 64) + if err != nil { + log.Printf("add_metrics: unable to convert value %q for metric: %s", value, err) continue } (*functions)[i].InvocationCount += f - break } } } diff --git a/gateway/metrics/add_metrics_test.go b/gateway/metrics/add_metrics_test.go index a3ebff56..5636f4a0 100644 --- a/gateway/metrics/add_metrics_test.go +++ b/gateway/metrics/add_metrics_test.go @@ -83,7 +83,7 @@ func Test_FunctionsHandler_ReturnsJSONAndOneFunction(t *testing.T) { func makeFunctionsHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { functions := []types.FunctionStatus{ - types.FunctionStatus{ + { Name: "func_echoit", Replicas: 0, Namespace: "openfaas-fn", diff --git a/gateway/metrics/exporter.go b/gateway/metrics/exporter.go index 2d35d0b8..b3cc2373 100644 --- a/gateway/metrics/exporter.go +++ b/gateway/metrics/exporter.go @@ -12,12 +12,14 @@ import ( "net/http" "net/url" "path" + "strconv" "time" "log" "github.com/openfaas/faas-provider/auth" types "github.com/openfaas/faas-provider/types" + "github.com/openfaas/faas/gateway/scaling" "github.com/prometheus/client_golang/prometheus" ) @@ -46,6 +48,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { e.metricOptions.GatewayFunctionsHistogram.Describe(ch) e.metricOptions.ServiceReplicasGauge.Describe(ch) e.metricOptions.GatewayFunctionInvocationStarted.Describe(ch) + e.metricOptions.ServiceTargetLoadGauge.Describe(ch) e.metricOptions.ServiceMetrics.Counter.Describe(ch) e.metricOptions.ServiceMetrics.Histogram.Describe(ch) @@ -59,6 +62,8 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { e.metricOptions.GatewayFunctionInvocationStarted.Collect(ch) e.metricOptions.ServiceReplicasGauge.Reset() + e.metricOptions.ServiceTargetLoadGauge.Reset() + for _, service := range e.services { var serviceName string if len(service.Namespace) > 0 { @@ -66,12 +71,54 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { } else { serviceName = service.Name } + + // Set current replica count e.metricOptions.ServiceReplicasGauge. WithLabelValues(serviceName). Set(float64(service.Replicas)) + + // Set minimum replicas + minReplicas := scaling.DefaultMinReplicas + if service.Labels != nil { + a := *service.Labels + if v, ok := a[scaling.MinScaleLabel]; ok && len(v) > 0 { + val, _ := strconv.Atoi(v) + minReplicas = val + } + } + + e.metricOptions.ServiceMinReplicasGauge. + WithLabelValues(serviceName). + Set(float64(minReplicas)) + + // Set scale type + scaleType := scaling.DefaultTypeScale + if service.Labels != nil { + a := *service.Labels + if v, ok := a[scaling.ScaleTypeLabel]; ok && len(v) > 0 { + scaleType = v + } + } + + // Set target load + targetScale := scaling.DefaultTargetLoad + if service.Labels != nil { + a := *service.Labels + if v, ok := a[scaling.TargetLoadLabel]; ok && len(v) > 0 { + val, _ := strconv.Atoi(v) + targetScale = val + } + } + + e.metricOptions.ServiceTargetLoadGauge. + WithLabelValues(serviceName, scaleType). + Set(float64(targetScale)) + } e.metricOptions.ServiceReplicasGauge.Collect(ch) + e.metricOptions.ServiceMinReplicasGauge.Collect(ch) + e.metricOptions.ServiceTargetLoadGauge.Collect(ch) e.metricOptions.ServiceMetrics.Counter.Collect(ch) e.metricOptions.ServiceMetrics.Histogram.Collect(ch) diff --git a/gateway/metrics/exporter_test.go b/gateway/metrics/exporter_test.go index 069b5b8a..36431eee 100644 --- a/gateway/metrics/exporter_test.go +++ b/gateway/metrics/exporter_test.go @@ -44,21 +44,21 @@ func Test_Describe_DescribesThePrometheusMetrics(t *testing.T) { expectedGatewayFunctionInvocationDesc := `Desc{fqName: "gateway_function_invocation_total", help: "Function metrics", constLabels: {}, variableLabels: [function_name code]}` actualGatewayFunctionInvocationDesc := d.String() if expectedGatewayFunctionInvocationDesc != actualGatewayFunctionInvocationDesc { - t.Errorf("Want %s, got: %s", expectedGatewayFunctionInvocationDesc, actualGatewayFunctionInvocationDesc) + t.Errorf("Want\n%s\ngot\n%s", expectedGatewayFunctionInvocationDesc, actualGatewayFunctionInvocationDesc) } d = <-ch expectedGatewayFunctionsHistogramDesc := `Desc{fqName: "gateway_functions_seconds", help: "Function time taken", constLabels: {}, variableLabels: [function_name]}` actualGatewayFunctionsHistogramDesc := d.String() if expectedGatewayFunctionsHistogramDesc != actualGatewayFunctionsHistogramDesc { - t.Errorf("Want %s, got: %s", expectedGatewayFunctionsHistogramDesc, actualGatewayFunctionsHistogramDesc) + t.Errorf("Want\n%s\ngot\n%s", expectedGatewayFunctionsHistogramDesc, actualGatewayFunctionsHistogramDesc) } d = <-ch - expectedServiceReplicasGaugeDesc := `Desc{fqName: "gateway_service_count", help: "Service replicas", constLabels: {}, variableLabels: [function_name]}` + expectedServiceReplicasGaugeDesc := `Desc{fqName: "gateway_service_count", help: "Current count of replicas for function", constLabels: {}, variableLabels: [function_name]}` actualServiceReplicasGaugeDesc := d.String() if expectedServiceReplicasGaugeDesc != actualServiceReplicasGaugeDesc { - t.Errorf("Want %s, got: %s", expectedServiceReplicasGaugeDesc, actualServiceReplicasGaugeDesc) + t.Errorf("Want\n%s\ngot\n%s", expectedServiceReplicasGaugeDesc, actualServiceReplicasGaugeDesc) } } diff --git a/gateway/metrics/metrics.go b/gateway/metrics/metrics.go index 2b6111b9..1a71003a 100644 --- a/gateway/metrics/metrics.go +++ b/gateway/metrics/metrics.go @@ -16,8 +16,12 @@ type MetricOptions struct { GatewayFunctionInvocation *prometheus.CounterVec GatewayFunctionsHistogram *prometheus.HistogramVec GatewayFunctionInvocationStarted *prometheus.CounterVec - ServiceReplicasGauge *prometheus.GaugeVec - ServiceMetrics *ServiceMetricOptions + + ServiceReplicasGauge *prometheus.GaugeVec + ServiceMinReplicasGauge *prometheus.GaugeVec + ServiceTargetLoadGauge *prometheus.GaugeVec + + ServiceMetrics *ServiceMetricOptions } // ServiceMetricOptions provides RED metrics @@ -62,11 +66,29 @@ func BuildMetricsOptions() MetricOptions { prometheus.GaugeOpts{ Namespace: "gateway", Name: "service_count", - Help: "Service replicas", + Help: "Current count of replicas for function", }, []string{"function_name"}, ) + serviceMinReplicas := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: "gateway", + Name: "service_min", + Help: "Minium replicas for function", + }, + []string{"function_name"}, + ) + + serviceTargetLoad := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: "gateway", + Name: "service_target_load", + Help: "Target load for function", + }, + []string{"function_name", "scaling_type"}, + ) + // For automatic monitoring and alerting (RED method) histogram := prometheus.NewHistogramVec(prometheus.HistogramOpts{ Subsystem: "http", @@ -104,6 +126,8 @@ func BuildMetricsOptions() MetricOptions { GatewayFunctionsHistogram: gatewayFunctionsHistogram, GatewayFunctionInvocation: gatewayFunctionInvocation, ServiceReplicasGauge: serviceReplicas, + ServiceMinReplicasGauge: serviceMinReplicas, + ServiceTargetLoadGauge: serviceTargetLoad, ServiceMetrics: serviceMetricOptions, GatewayFunctionInvocationStarted: gatewayFunctionInvocationStarted, } diff --git a/gateway/plugin/external.go b/gateway/plugin/external.go index 3ab61f90..872c1b71 100644 --- a/gateway/plugin/external.go +++ b/gateway/plugin/external.go @@ -100,12 +100,15 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string) scalingFactor := uint64(scaling.DefaultScalingFactor) availableReplicas := function.AvailableReplicas + targetLoad := uint64(scaling.DefaultTargetLoad) + if function.Labels != nil { labels := *function.Labels minReplicas = extractLabelValue(labels[scaling.MinScaleLabel], minReplicas) maxReplicas = extractLabelValue(labels[scaling.MaxScaleLabel], maxReplicas) extractedScalingFactor := extractLabelValue(labels[scaling.ScalingFactorLabel], scalingFactor) + targetLoad = extractLabelValue(labels[scaling.TargetLoadLabel], targetLoad) if extractedScalingFactor >= 0 && extractedScalingFactor <= 100 { scalingFactor = extractedScalingFactor @@ -113,6 +116,7 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string) log.Printf("Bad Scaling Factor: %d, is not in range of [0 - 100]. Will fallback to %d", extractedScalingFactor, scalingFactor) } } + log.Printf("GetReplicas [%s.%s] took: %fs", serviceName, serviceNamespace, time.Since(start).Seconds()) return scaling.ServiceQueryResponse{ @@ -122,6 +126,7 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string) ScalingFactor: scalingFactor, AvailableReplicas: availableReplicas, Annotations: function.Annotations, + TargetLoad: targetLoad, }, err } diff --git a/gateway/plugin/external_test.go b/gateway/plugin/external_test.go index 58ebdcf8..157559de 100644 --- a/gateway/plugin/external_test.go +++ b/gateway/plugin/external_test.go @@ -75,6 +75,7 @@ func TestGetReplicasExistentFn(t *testing.T) { MinReplicas: uint64(scaling.DefaultMinReplicas), ScalingFactor: uint64(scaling.DefaultScalingFactor), AvailableReplicas: 0, + TargetLoad: 10, } var injector middleware.AuthInjector @@ -89,7 +90,7 @@ func TestGetReplicasExistentFn(t *testing.T) { t.Fail() } if svcQryResp != expectedSvcQryResp { - t.Logf("Unexpected return values - wanted %+v, got: %+v ", expectedSvcQryResp, svcQryResp) + t.Logf("Unexpected return values - wanted\n%+v\ngot\n%+v ", expectedSvcQryResp, svcQryResp) t.Fail() } } diff --git a/gateway/scaling/ranges.go b/gateway/scaling/ranges.go index 54586583..4d86d5bc 100644 --- a/gateway/scaling/ranges.go +++ b/gateway/scaling/ranges.go @@ -10,6 +10,11 @@ const ( // DefaultScalingFactor is the defining proportion for the scaling increments. DefaultScalingFactor = 20 + // DefaultTargetLoad + DefaultTargetLoad = 10 + + DefaultTypeScale = "rps" + // MinScaleLabel label indicating min scale for a function MinScaleLabel = "com.openfaas.scale.min" @@ -18,4 +23,10 @@ const ( // ScalingFactorLabel label indicates the scaling factor for a function ScalingFactorLabel = "com.openfaas.scale.factor" + + // TargetLoadLabel see also DefaultTargetScale + TargetLoadLabel = "com.openfaas.scale.target" + + // ScaleTypeLabel see also DefaultScaleType + ScaleTypeLabel = "com.openfaas.scale.type" ) diff --git a/gateway/scaling/service_query.go b/gateway/scaling/service_query.go index 7d60e61b..0c9873c7 100644 --- a/gateway/scaling/service_query.go +++ b/gateway/scaling/service_query.go @@ -17,4 +17,5 @@ type ServiceQueryResponse struct { ScalingFactor uint64 AvailableReplicas uint64 Annotations *map[string]string + TargetLoad uint64 } diff --git a/gateway/tests/integration/README.md b/gateway/tests/integration/README.md deleted file mode 100644 index 549fc200..00000000 --- a/gateway/tests/integration/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Integration testing - -These tests should be run against the sample stack included in the repository root. - -## Deploy the stack -``` -./deploy_stack.sh -faas-cli deploy -f ./stack.yml -``` - -## Remove the stack -1. Delete all OpenFaaS deployed functions -``` -faas-cli remove -docker stack rm func -``` \ No newline at end of file diff --git a/gateway/tests/integration/createfunction_test.go b/gateway/tests/integration/createfunction_test.go deleted file mode 100644 index 64753b22..00000000 --- a/gateway/tests/integration/createfunction_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Alex Ellis 2017. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -package inttests - -import ( - "encoding/json" - "net/http" - "strings" - "testing" - - types "github.com/openfaas/faas-provider/types" - requests "github.com/openfaas/faas/gateway/requests" -) - -func createFunction(request types.FunctionDeployment) (string, int, error) { - marshalled, _ := json.Marshal(request) - return fireRequest("http://localhost:8080/system/functions", http.MethodPost, string(marshalled)) -} - -func deleteFunction(name string) (string, int, error) { - marshalled, _ := json.Marshal(requests.DeleteFunctionRequest{FunctionName: name}) - return fireRequest("http://localhost:8080/system/functions", http.MethodDelete, string(marshalled)) -} - -func TestCreate_ValidRequest(t *testing.T) { - request := types.FunctionDeployment{ - Service: "test_resizer", - Image: "functions/resizer", - EnvProcess: "", - } - - _, code, err := createFunction(request) - - if err != nil { - t.Log(err) - t.Fail() - } - - expectedErrorCode := http.StatusAccepted - if code != expectedErrorCode { - t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode) - return - } - - deleteFunction("test_resizer") -} - -func TestCreate_InvalidImage(t *testing.T) { - request := types.FunctionDeployment{ - Service: "test_resizer", - Image: "a b c", - EnvProcess: "", - } - - body, code, err := createFunction(request) - - if err != nil { - t.Log(err) - t.Fail() - } - - expectedErrorCode := http.StatusBadRequest - if code != expectedErrorCode { - t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode) - return - } - - expectedErrorSlice := "is not a valid repository/tag" - if !strings.Contains(body, expectedErrorSlice) { - t.Errorf("Error message %s does not contain: %s\n", body, expectedErrorSlice) - return - } -} - -func TestCreate_InvalidJson(t *testing.T) { - reqBody := `not json` - _, code, err := fireRequest("http://localhost:8080/system/functions", http.MethodPost, reqBody) - - if err != nil { - t.Log(err) - t.Fail() - } - - if code != http.StatusBadRequest { - t.Errorf("Got HTTP code: %d, want %d\n", code, http.StatusBadRequest) - } -} diff --git a/gateway/tests/integration/deletefunction_test.go b/gateway/tests/integration/deletefunction_test.go deleted file mode 100644 index c8343607..00000000 --- a/gateway/tests/integration/deletefunction_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Alex Ellis 2017. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -package inttests - -import ( - "net/http" - "testing" -) - -func TestDelete_EmptyFunctionGivenFails(t *testing.T) { - reqBody := `{"functionName":""}` - _, code, err := fireRequest("http://localhost:8080/system/functions", http.MethodDelete, reqBody) - - if err != nil { - t.Log(err) - t.Fail() - } - - if code != http.StatusBadRequest { - t.Errorf("Got HTTP code: %d, want %d\n", code, http.StatusBadRequest) - } -} - -func TestDelete_NonExistingFunctionGives404(t *testing.T) { - reqBody := `{"functionName":"does_not_exist"}` - _, code, err := fireRequest("http://localhost:8080/system/functions", http.MethodDelete, reqBody) - - if err != nil { - t.Log(err) - t.Fail() - } - - if code != http.StatusNotFound { - t.Errorf("Got HTTP code: %d, want %d\n", code, http.StatusNotFound) - } -} diff --git a/gateway/tests/integration/infohandler_test.go b/gateway/tests/integration/infohandler_test.go deleted file mode 100644 index 161d7a54..00000000 --- a/gateway/tests/integration/infohandler_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package inttests - -import ( - "encoding/json" - "net/http" - "testing" - - "github.com/openfaas/faas/gateway/types" -) - -func Test_InfoEndpoint_Returns_200(t *testing.T) { - _, code, err := fireRequest("http://localhost:8080/system/info", http.MethodGet, "") - - if err != nil { - t.Log(err) - t.Fail() - } - - wantCode := http.StatusOK - if code != wantCode { - t.Errorf("status code, want: %d, got: %d", wantCode, code) - t.Fail() - } -} - -func Test_InfoEndpoint_Returns_Gateway_Version_SHA_And_Message(t *testing.T) { - body, _, err := fireRequest("http://localhost:8080/system/info", http.MethodGet, "") - - if err != nil { - t.Log(err) - t.Fail() - } - - gatewayInfo := &types.GatewayInfo{} - err = json.Unmarshal([]byte(body), gatewayInfo) - if err != nil { - t.Errorf("Could not unmarshal gateway info, response body:%s, error:%s", body, err.Error()) - t.Fail() - } - - if len(gatewayInfo.Version.SHA) != 40 { - t.Errorf("length of SHA incorrect, want: %d, got: %d. Json body was %s", 40, len(gatewayInfo.Version.SHA), body) - } - - if len(gatewayInfo.Version.CommitMessage) == 0 { - t.Errorf("length of commit message should be greater than 0. Json body was %s", body) - } -} - -func Test_InfoEndpoint_Returns_Arch(t *testing.T) { - body, _, err := fireRequest("http://localhost:8080/system/info", http.MethodGet, "") - - if err != nil { - t.Log(err) - t.Fail() - } - - gatewayInfo := &types.GatewayInfo{} - err = json.Unmarshal([]byte(body), gatewayInfo) - if err != nil { - t.Errorf("Could not unmarshal gateway info, response body:%s, error:%s", body, err.Error()) - t.Fail() - } - - if len(gatewayInfo.Arch) == 0 { - t.Errorf("value of arch should be non-empty") - } -} diff --git a/gateway/tests/integration/routes_test.go b/gateway/tests/integration/routes_test.go deleted file mode 100644 index 052ed2cc..00000000 --- a/gateway/tests/integration/routes_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Alex Ellis 2017. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -package inttests - -import ( - "bytes" - "io/ioutil" - "log" - "net/http" - "testing" - "time" -) - -// Before running these tests do a Docker stack deploy. - -func fireRequest(url string, method string, reqBody string) (string, int, error) { - headers := make(map[string]string) - return fireRequestWithHeaders(url, method, reqBody, headers) -} - -func fireRequestWithHeaders(url string, method string, reqBody string, headers map[string]string) (string, int, error) { - httpClient := http.Client{ - Timeout: time.Second * 2, // Maximum of 2 secs - } - - req, err := http.NewRequest(method, url, bytes.NewBufferString(reqBody)) - if err != nil { - log.Fatal(err) - } - - req.Header.Set("User-Agent", "go-integration") - for kk, vv := range headers { - req.Header.Set(kk, vv) - } - - res, getErr := httpClient.Do(req) - if getErr != nil { - log.Fatal(getErr) - } - - body, readErr := ioutil.ReadAll(res.Body) - defer req.Body.Close() - if readErr != nil { - log.Fatal(readErr) - } - return string(body), res.StatusCode, readErr -} - -func TestGet_Rejected(t *testing.T) { - var reqBody string - unsupportedMethod := http.MethodHead - _, code, err := fireRequest("http://localhost:8080/function/echoit", unsupportedMethod, reqBody) - want := http.StatusMethodNotAllowed - if code != want { - t.Logf("Failed got: %d, wanted: %d", code, want) - t.Fail() - } - - if err != nil { - t.Log(err) - t.Fail() - } -} - -func TestEchoIt_Post_Route_Handler_ForwardsClientHeaders(t *testing.T) { - reqBody := "test message" - headers := make(map[string]string, 0) - headers["X-Api-Key"] = "123" - - body, code, err := fireRequestWithHeaders("http://localhost:8080/function/echoit", http.MethodPost, reqBody, headers) - - if err != nil { - t.Log(err) - t.Fail() - } - - if code != http.StatusOK { - t.Logf("Failed, code: %d, body:%s", code, body) - t.Fail() - } - - if body != reqBody { - t.Log("Expected body returned") - t.Fail() - } -} - -func TestEchoIt_Post_Route_Handler(t *testing.T) { - reqBody := "test message" - body, code, err := fireRequest("http://localhost:8080/function/echoit", http.MethodPost, reqBody) - - if err != nil { - t.Log(err) - t.Fail() - } - if code != http.StatusOK { - t.Log("Failed") - } - if body != reqBody { - t.Log("Expected body returned") - t.Fail() - } -} - -// Test suppressed due to X-Header deprecation. -// func TestEchoIt_Post_X_Header_Routing_Handler(t *testing.T) { -// reqBody := "test message" -// headers := make(map[string]string, 0) -// headers["X-Function"] = "func_echoit" - -// body, code, err := fireRequestWithHeaders("http://localhost:8080/", http.MethodPost, reqBody, headers) - -// if err != nil { -// t.Log(err) -// t.Fail() -// } -// if code != http.StatusOK { -// t.Logf("statusCode - want: %d, got: %d", http.StatusOK, code) -// } -// if body != reqBody { -// t.Logf("Expected body from echo function to be equal to input, but was: %s", body) -// t.Fail() -// } -// } diff --git a/gateway/types/handler_set.go b/gateway/types/handler_set.go index d45c08fa..585008e8 100644 --- a/gateway/types/handler_set.go +++ b/gateway/types/handler_set.go @@ -4,18 +4,24 @@ import "net/http" // HandlerSet can be initialized with handlers for binding to mux type HandlerSet struct { - // Proxy invokes functions upstream + // Proxy invokes a function Proxy http.HandlerFunc + // DeployFunction deploys a new function that isn't already deployed DeployFunction http.HandlerFunc - DeleteFunction http.HandlerFunc - ListFunctions http.HandlerFunc - Alert http.HandlerFunc + // DeleteFunction deletes a function that is already deployed + DeleteFunction http.HandlerFunc + + // ListFunctions lists all deployed functions in a namespace + ListFunctions http.HandlerFunc + Alert http.HandlerFunc + + // UpdateFunction updates an existing function UpdateFunction http.HandlerFunc - // QueryFunction queries the metdata for a function - QueryFunction http.HandlerFunc + // FunctionStatus returns the status of an already deployed function + FunctionStatus http.HandlerFunc // QueuedProxy queue work and return synchronous response QueuedProxy http.HandlerFunc diff --git a/gateway/vendor/github.com/openfaas/faas-provider/types/function_deployment.go b/gateway/vendor/github.com/openfaas/faas-provider/types/function_deployment.go new file mode 100644 index 00000000..22b2abde --- /dev/null +++ b/gateway/vendor/github.com/openfaas/faas-provider/types/function_deployment.go @@ -0,0 +1,51 @@ +package types + +// FunctionDeployment represents a request to create or update a Function. +type FunctionDeployment struct { + + // Service is the name of the function deployment + Service string `json:"service"` + + // Image is a fully-qualified container image + Image string `json:"image"` + + // Namespace for the function, if supported by the faas-provider + Namespace string `json:"namespace,omitempty"` + + // EnvProcess overrides the fprocess environment variable and can be used + // with the watchdog + EnvProcess string `json:"envProcess,omitempty"` + + // EnvVars can be provided to set environment variables for the function runtime. + EnvVars map[string]string `json:"envVars,omitempty"` + + // Constraints are specific to the faas-provider. + Constraints []string `json:"constraints,omitempty"` + + // Secrets list of secrets to be made available to function + Secrets []string `json:"secrets,omitempty"` + + // Labels are metadata for functions which may be used by the + // faas-provider or the gateway + Labels *map[string]string `json:"labels,omitempty"` + + // Annotations are metadata for functions which may be used by the + // faas-provider or the gateway + Annotations *map[string]string `json:"annotations,omitempty"` + + // Limits for function + Limits *FunctionResources `json:"limits,omitempty"` + + // Requests of resources requested by function + Requests *FunctionResources `json:"requests,omitempty"` + + // ReadOnlyRootFilesystem removes write-access from the root filesystem + // mount-point. + ReadOnlyRootFilesystem bool `json:"readOnlyRootFilesystem,omitempty"` +} + +// FunctionResources Memory and CPU +type FunctionResources struct { + Memory string `json:"memory,omitempty"` + CPU string `json:"cpu,omitempty"` +} diff --git a/gateway/vendor/github.com/openfaas/faas-provider/types/model.go b/gateway/vendor/github.com/openfaas/faas-provider/types/function_status.go similarity index 50% rename from gateway/vendor/github.com/openfaas/faas-provider/types/model.go rename to gateway/vendor/github.com/openfaas/faas-provider/types/function_status.go index e923e6e5..a67d8d7b 100644 --- a/gateway/vendor/github.com/openfaas/faas-provider/types/model.go +++ b/gateway/vendor/github.com/openfaas/faas-provider/types/function_status.go @@ -2,72 +2,6 @@ package types import "time" -// Secret for underlying orchestrator -type Secret struct { - // Name of the secret - Name string `json:"name"` - - // Namespace if applicable for the secret - Namespace string `json:"namespace,omitempty"` - - // Value is a string representing the string's value - Value string `json:"value,omitempty"` - - // RawValue can be used to provide binary data when - // Value is not set - RawValue []byte `json:"rawValue,omitempty"` -} - -// FunctionDeployment represents a request to create or update a Function. -type FunctionDeployment struct { - - // Service is the name of the function deployment - Service string `json:"service"` - - // Image is a fully-qualified container image - Image string `json:"image"` - - // Namespace for the function, if supported by the faas-provider - Namespace string `json:"namespace,omitempty"` - - // EnvProcess overrides the fprocess environment variable and can be used - // with the watchdog - EnvProcess string `json:"envProcess,omitempty"` - - // EnvVars can be provided to set environment variables for the function runtime. - EnvVars map[string]string `json:"envVars,omitempty"` - - // Constraints are specific to the faas-provider. - Constraints []string `json:"constraints,omitempty"` - - // Secrets list of secrets to be made available to function - Secrets []string `json:"secrets,omitempty"` - - // Labels are metadata for functions which may be used by the - // faas-provider or the gateway - Labels *map[string]string `json:"labels,omitempty"` - - // Annotations are metadata for functions which may be used by the - // faas-provider or the gateway - Annotations *map[string]string `json:"annotations,omitempty"` - - // Limits for function - Limits *FunctionResources `json:"limits,omitempty"` - - // Requests of resources requested by function - Requests *FunctionResources `json:"requests,omitempty"` - - // ReadOnlyRootFilesystem removes write-access from the root filesystem - // mount-point. - ReadOnlyRootFilesystem bool `json:"readOnlyRootFilesystem,omitempty"` -} - -// FunctionResources Memory and CPU -type FunctionResources struct { - Memory string `json:"memory,omitempty"` - CPU string `json:"cpu,omitempty"` -} - // FunctionStatus exported for system/functions endpoint type FunctionStatus struct { @@ -128,4 +62,24 @@ type FunctionStatus struct { // CreatedAt is the time read back from the faas backend's // data store for when the function or its container was created. CreatedAt time.Time `json:"createdAt,omitempty"` + + // Utilisation represents CPU and RAM used by all of the + // functions' replicas. Divide by AvailableReplicas for an + // average value per replica. + Utilisation FunctionUtilisation `json:"usage,omitempty"` +} + +// FunctionUtilisation represents CPU and RAM used by all of the +// functions' replicas. +// +// CPU is measured in seconds consumed since the last measurement +// RAM is measured in total bytes consumed +// +type FunctionUtilisation struct { + // CPU is the increase in CPU usage since the last measurement + // equivalent to Kubernetes' concept of millicores. + CPU float64 `json:"cpu,omitempty"` + + //TotalMemoryBytes is the total memory usage in bytes. + TotalMemoryBytes float64 `json:"totalMemoryBytes,omitempty"` } diff --git a/gateway/vendor/github.com/openfaas/faas-provider/types/secret.go b/gateway/vendor/github.com/openfaas/faas-provider/types/secret.go new file mode 100644 index 00000000..71f93738 --- /dev/null +++ b/gateway/vendor/github.com/openfaas/faas-provider/types/secret.go @@ -0,0 +1,17 @@ +package types + +// Secret for underlying orchestrator +type Secret struct { + // Name of the secret + Name string `json:"name"` + + // Namespace if applicable for the secret + Namespace string `json:"namespace,omitempty"` + + // Value is a string representing the string's value + Value string `json:"value,omitempty"` + + // RawValue can be used to provide binary data when + // Value is not set + RawValue []byte `json:"rawValue,omitempty"` +} diff --git a/gateway/vendor/modules.txt b/gateway/vendor/modules.txt index ea7cfc9b..88c7c66d 100644 --- a/gateway/vendor/modules.txt +++ b/gateway/vendor/modules.txt @@ -20,10 +20,6 @@ github.com/golang/protobuf/ptypes/timestamp github.com/gorilla/mux # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil -# github.com/nats-io/nats-server/v2 v2.3.2 -## explicit -# github.com/nats-io/nats-streaming-server v0.22.0 -## explicit # github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30 github.com/nats-io/nats.go github.com/nats-io/nats.go/encoders/builtin @@ -35,7 +31,7 @@ github.com/nats-io/nuid # github.com/nats-io/stan.go v0.9.0 github.com/nats-io/stan.go github.com/nats-io/stan.go/pb -# github.com/openfaas/faas-provider v0.18.6 +# github.com/openfaas/faas-provider v0.18.7 ## explicit github.com/openfaas/faas-provider/auth github.com/openfaas/faas-provider/types