mirror of
https://github.com/openfaas/faas.git
synced 2025-06-20 13:06:40 +00:00
Upgrade faas-provider to 0.9.2
Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
This commit is contained in:
committed by
Alex Ellis
parent
6868d8a3ce
commit
d8a5952cfe
6
gateway/Gopkg.lock
generated
6
gateway/Gopkg.lock
generated
@ -93,12 +93,12 @@
|
|||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:84708b04710afa61221f72ace164ce7fb6d26a7647b3a61d1af18d0e51f88d29"
|
digest = "1:d30085f782a2785c72cd5d4dda822aa615070ba745ea25e5a8a3661faa0ad980"
|
||||||
name = "github.com/openfaas/faas-provider"
|
name = "github.com/openfaas/faas-provider"
|
||||||
packages = ["auth"]
|
packages = ["auth"]
|
||||||
pruneopts = ""
|
pruneopts = ""
|
||||||
revision = "376c26ef02007abb7cadbd550bb75df166764473"
|
revision = "0ca8ae603fee9736e011b81fbf02777d89a4ea85"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c91d031a0f53699e18f204e8a8d360d400a34686a3bb34d82c63a53ff1d73cea"
|
digest = "1:c91d031a0f53699e18f204e8a8d360d400a34686a3bb34d82c63a53ff1d73cea"
|
||||||
|
16
gateway/vendor/github.com/openfaas/faas-provider/Gopkg.lock
generated
vendored
16
gateway/vendor/github.com/openfaas/faas-provider/Gopkg.lock
generated
vendored
@ -17,9 +17,23 @@
|
|||||||
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
||||||
version = "v1.6.2"
|
version = "v1.6.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:9a1bb99a85e2ccddbc593aa0af084cdf6ea18ed081469eb90e7f6d0d303af6cd"
|
||||||
|
name = "go.uber.org/goleak"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal/stack",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "1ac8aeca0a53163331564467638f6ffb639636bf"
|
||||||
|
version = "v0.10.0"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = ["github.com/gorilla/mux"]
|
input-imports = [
|
||||||
|
"github.com/gorilla/mux",
|
||||||
|
"go.uber.org/goleak",
|
||||||
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
8
gateway/vendor/github.com/openfaas/faas-provider/README.md
generated
vendored
8
gateway/vendor/github.com/openfaas/faas-provider/README.md
generated
vendored
@ -14,7 +14,7 @@ The faas-provider provides CRUD for functions and an invoke capability. If you c
|
|||||||
The following is used in OpenFaaS and recommended for those seeking to build their own back-ends:
|
The following is used in OpenFaaS and recommended for those seeking to build their own back-ends:
|
||||||
|
|
||||||
* License: MIT
|
* License: MIT
|
||||||
* Language: Golang
|
* Language: Golang
|
||||||
|
|
||||||
### How to use this project
|
### How to use this project
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ For an example see the [server.go](https://github.com/openfaas/faas-netes/blob/m
|
|||||||
I.e.:
|
I.e.:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
timeout := 8 * time.Second
|
||||||
bootstrapHandlers := bootTypes.FaaSHandlers{
|
bootstrapHandlers := bootTypes.FaaSHandlers{
|
||||||
FunctionProxy: handlers.MakeProxy(),
|
FunctionProxy: handlers.MakeProxy(),
|
||||||
DeleteHandler: handlers.MakeDeleteHandler(clientset),
|
DeleteHandler: handlers.MakeDeleteHandler(clientset),
|
||||||
@ -33,13 +34,14 @@ I.e.:
|
|||||||
ReplicaReader: handlers.MakeReplicaReader(clientset),
|
ReplicaReader: handlers.MakeReplicaReader(clientset),
|
||||||
ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
|
ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
|
||||||
InfoHandler: handlers.MakeInfoHandler(),
|
InfoHandler: handlers.MakeInfoHandler(),
|
||||||
|
LogHandler: logs.NewLogHandlerFunc(requestor,timeout),
|
||||||
}
|
}
|
||||||
|
|
||||||
var port int
|
var port int
|
||||||
port = 8080
|
port = 8080
|
||||||
bootstrapConfig := bootTypes.FaaSConfig{
|
bootstrapConfig := bootTypes.FaaSConfig{
|
||||||
ReadTimeout: time.Second * 8,
|
ReadTimeout: timeout,
|
||||||
WriteTimeout: time.Second * 8,
|
WriteTimeout: timeout,
|
||||||
TCPPort: &port,
|
TCPPort: &port,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
gateway/vendor/github.com/openfaas/faas-provider/httputil/writers.go
generated
vendored
Normal file
12
gateway/vendor/github.com/openfaas/faas-provider/httputil/writers.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package httputil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errorf sets the response status code and write formats the provided message as the
|
||||||
|
// response body
|
||||||
|
func Errorf(w http.ResponseWriter, statusCode int, msg string, args ...interface{}) {
|
||||||
|
http.Error(w, fmt.Sprintf(msg, args...), statusCode)
|
||||||
|
}
|
2
gateway/vendor/github.com/openfaas/faas-provider/logs/example/README.md
generated
vendored
Normal file
2
gateway/vendor/github.com/openfaas/faas-provider/logs/example/README.md
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Static Log Server Example
|
||||||
|
This example shows a very basic static log server. It will return the same 3 log messages for every request.
|
47
gateway/vendor/github.com/openfaas/faas-provider/logs/example/main.go
generated
vendored
Normal file
47
gateway/vendor/github.com/openfaas/faas-provider/logs/example/main.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/openfaas/faas-provider/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// staticLogRequestor implements the logs Requestor returning a static stream of logs
|
||||||
|
type staticLogRequestor struct {
|
||||||
|
logs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s staticLogRequestor) Query(ctx context.Context, r logs.Request) (<-chan logs.Message, error) {
|
||||||
|
resp := make(chan logs.Message, len(s.logs))
|
||||||
|
|
||||||
|
// A real implementation would possibly run a query to their log storage here, if it returns a
|
||||||
|
// channel, and pass that channel to the go routine below instead of ranging over `s.logs`
|
||||||
|
// If the log storage backend client does not return a channel, the query would need to
|
||||||
|
// occur at the beginning of the goroutine below ... or a separate goroutine
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, m := range s.logs {
|
||||||
|
// always watch the ctx to timeout/cancel/finish
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp <- logs.Message{
|
||||||
|
Name: r.Name,
|
||||||
|
Instance: "fake",
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Text: m,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
requestor := staticLogRequestor{logs: []string{"msg1", "msg2", "something interesting"}}
|
||||||
|
http.HandleFunc("/system/logs", logs.NewLogHandlerFunc(requestor, 10*time.Second))
|
||||||
|
http.ListenAndServe(":80", nil)
|
||||||
|
}
|
142
gateway/vendor/github.com/openfaas/faas-provider/logs/handler.go
generated
vendored
Normal file
142
gateway/vendor/github.com/openfaas/faas-provider/logs/handler.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/openfaas/faas-provider/httputil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Requester submits queries the logging system.
|
||||||
|
// This will be passed to the log handler constructor.
|
||||||
|
type Requester interface {
|
||||||
|
// Query submits a log request to the actual logging system.
|
||||||
|
Query(context.Context, Request) (<-chan Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLogHandlerFunc creates an http HandlerFunc from the supplied log Requestor.
|
||||||
|
func NewLogHandlerFunc(requestor Requester, timeout time.Duration) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Body != nil {
|
||||||
|
defer r.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
cn, ok := w.(http.CloseNotifier)
|
||||||
|
if !ok {
|
||||||
|
log.Println("LogHandler: response is not a CloseNotifier, required for streaming response")
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
flusher, ok := w.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
log.Println("LogHandler: response is not a Flusher, required for streaming response")
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logRequest, err := parseRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("LogHandler: could not parse request %s", err)
|
||||||
|
httputil.Errorf(w, http.StatusUnprocessableEntity, "could not parse the log request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancelQuery := context.WithTimeout(r.Context(), timeout)
|
||||||
|
defer cancelQuery()
|
||||||
|
messages, err := requestor.Query(ctx, logRequest)
|
||||||
|
if err != nil {
|
||||||
|
// add smarter error handling here
|
||||||
|
httputil.Errorf(w, http.StatusInternalServerError, "function log request failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the initial headers saying we're gonna stream the response.
|
||||||
|
w.Header().Set("Connection", "Keep-Alive")
|
||||||
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
|
w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/x-ndjson")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
flusher.Flush()
|
||||||
|
|
||||||
|
// ensure that we always try to send the closing chunk, not the inverted order due to how
|
||||||
|
// the defer stack works. We need two flush statements to ensure that the empty slice is
|
||||||
|
// sent as its own chunk
|
||||||
|
defer flusher.Flush()
|
||||||
|
defer w.Write([]byte{})
|
||||||
|
defer flusher.Flush()
|
||||||
|
|
||||||
|
jsonEncoder := json.NewEncoder(w)
|
||||||
|
for messages != nil {
|
||||||
|
select {
|
||||||
|
case <-cn.CloseNotify():
|
||||||
|
log.Println("LogHandler: client stopped listening")
|
||||||
|
return
|
||||||
|
case msg, ok := <-messages:
|
||||||
|
if !ok {
|
||||||
|
log.Println("LogHandler: end of log stream")
|
||||||
|
messages = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize and write the msg to the http ResponseWriter
|
||||||
|
err := jsonEncoder.Encode(msg)
|
||||||
|
if err != nil {
|
||||||
|
// can't actually write the status header here so we should json serialize an error
|
||||||
|
// and return that because we have already sent the content type and status code
|
||||||
|
log.Printf("LogHandler: failed to serialize log message: '%s'\n", msg.String())
|
||||||
|
log.Println(err.Error())
|
||||||
|
// write json error message here ?
|
||||||
|
jsonEncoder.Encode(Message{Text: "failed to serialize log message"})
|
||||||
|
flusher.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRequest extracts the logRequest from the GET variables or from the POST body
|
||||||
|
func parseRequest(r *http.Request) (logRequest Request, err error) {
|
||||||
|
query := r.URL.Query()
|
||||||
|
logRequest.Name = getValue(query, "name")
|
||||||
|
logRequest.Instance = getValue(query, "instance")
|
||||||
|
tailStr := getValue(query, "tail")
|
||||||
|
if tailStr != "" {
|
||||||
|
logRequest.Tail, err = strconv.Atoi(tailStr)
|
||||||
|
if err != nil {
|
||||||
|
return logRequest, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ignore error because it will default to false if we can't parse it
|
||||||
|
logRequest.Follow, _ = strconv.ParseBool(getValue(query, "follow"))
|
||||||
|
|
||||||
|
sinceStr := getValue(query, "since")
|
||||||
|
if sinceStr != "" {
|
||||||
|
since, err := time.Parse(time.RFC3339, sinceStr)
|
||||||
|
logRequest.Since = &since
|
||||||
|
if err != nil {
|
||||||
|
return logRequest, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getValue returns the value for the given key. If the key has more than one value, it returns the
|
||||||
|
// last value. if the value does not exist, it returns the empty string.
|
||||||
|
func getValue(queryValues url.Values, name string) string {
|
||||||
|
values := queryValues[name]
|
||||||
|
if len(values) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return values[len(values)-1]
|
||||||
|
}
|
191
gateway/vendor/github.com/openfaas/faas-provider/logs/handler_test.go
generated
vendored
Normal file
191
gateway/vendor/github.com/openfaas/faas-provider/logs/handler_test.go
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/goleak"
|
||||||
|
)
|
||||||
|
|
||||||
|
var queryTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
func Test_logsHandlerDoesNotLeakGoroutinesWhenProviderClosesStream(t *testing.T) {
|
||||||
|
defer goleak.VerifyNoLeaks(t)
|
||||||
|
|
||||||
|
msgs := []Message{
|
||||||
|
Message{Name: "funcFoo", Text: "msg 0"},
|
||||||
|
Message{Name: "funcFoo", Text: "msg 1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected bytes.Buffer
|
||||||
|
json.NewEncoder(&expected).Encode(msgs[0])
|
||||||
|
json.NewEncoder(&expected).Encode(msgs[1])
|
||||||
|
|
||||||
|
querier := newFakeQueryRequester(msgs, nil)
|
||||||
|
logHandler := NewLogHandlerFunc(querier, queryTimeout)
|
||||||
|
testSrv := httptest.NewServer(http.HandlerFunc(logHandler))
|
||||||
|
defer testSrv.Close()
|
||||||
|
|
||||||
|
resp, err := http.Get(testSrv.URL + "?name=funcFoo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error sending log request: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
querier.Close()
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error reading log response: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(body) != expected.String() {
|
||||||
|
t.Fatalf("expected log message %s, got: %s", expected.String(), body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_logsHandlerDoesNotLeakGoroutinesWhenClientClosesConnection(t *testing.T) {
|
||||||
|
defer goleak.VerifyNoLeaks(t)
|
||||||
|
|
||||||
|
msgs := []Message{
|
||||||
|
Message{Name: "funcFoo", Text: "msg 0"},
|
||||||
|
Message{Name: "funcFoo", Text: "msg 1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
querier := newFakeQueryRequester(msgs, nil)
|
||||||
|
logHandler := NewLogHandlerFunc(querier, queryTimeout)
|
||||||
|
testSrv := httptest.NewServer(http.HandlerFunc(logHandler))
|
||||||
|
defer testSrv.Close()
|
||||||
|
|
||||||
|
reqContext, cancel := context.WithCancel(context.Background())
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, testSrv.URL+"?name=funcFoo", nil)
|
||||||
|
|
||||||
|
req = req.WithContext(reqContext)
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error sending log request: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
_, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != context.Canceled {
|
||||||
|
t.Fatalf("unexpected error reading log response: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_GETRequestParsing(t *testing.T) {
|
||||||
|
sinceTime, _ := time.Parse(time.RFC3339, "2019-02-16T09:10:06+00:00")
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
rawQueryStr string
|
||||||
|
err string
|
||||||
|
expectedRequest Request
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty query creates an empty request",
|
||||||
|
rawQueryStr: "",
|
||||||
|
err: "",
|
||||||
|
expectedRequest: Request{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name only query",
|
||||||
|
rawQueryStr: "name=foobar",
|
||||||
|
err: "",
|
||||||
|
expectedRequest: Request{Name: "foobar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name only query",
|
||||||
|
rawQueryStr: "name=foobar",
|
||||||
|
err: "",
|
||||||
|
expectedRequest: Request{Name: "foobar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple name values selects the last value",
|
||||||
|
rawQueryStr: "name=foobar&name=theactual name",
|
||||||
|
err: "",
|
||||||
|
expectedRequest: Request{Name: "theactual name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid request with every parameter",
|
||||||
|
rawQueryStr: "name=foobar&since=2019-02-16T09%3A10%3A06%2B00%3A00&tail=5&follow=true",
|
||||||
|
err: "",
|
||||||
|
expectedRequest: Request{
|
||||||
|
Name: "foobar",
|
||||||
|
Since: &sinceTime,
|
||||||
|
Tail: 5,
|
||||||
|
Follow: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
req.URL.RawQuery = s.rawQueryStr
|
||||||
|
logRequest, err := parseRequest(req)
|
||||||
|
equalError(t, s.err, err)
|
||||||
|
|
||||||
|
if logRequest.String() != s.expectedRequest.String() {
|
||||||
|
t.Errorf("expected log request: %s, got: %s", s.expectedRequest, logRequest)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalError(t *testing.T, expected string, actual error) {
|
||||||
|
if expected == "" && actual == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected == "" && actual != nil {
|
||||||
|
t.Errorf("unexpected error: %s", actual.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual.Error() != expected {
|
||||||
|
t.Errorf("expected error: %s got: %s", expected, actual.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeQueryRequester struct {
|
||||||
|
Logs []Message
|
||||||
|
err error
|
||||||
|
stream chan Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r fakeQueryRequester) Close() {
|
||||||
|
close(r.stream)
|
||||||
|
r.stream = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r fakeQueryRequester) Query(context.Context, Request) (<-chan Message, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range r.Logs {
|
||||||
|
r.stream <- m
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.stream, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeQueryRequester(l []Message, err error) fakeQueryRequester {
|
||||||
|
return fakeQueryRequester{
|
||||||
|
Logs: l,
|
||||||
|
err: err,
|
||||||
|
stream: make(chan Message, len(l)),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
gateway/vendor/github.com/openfaas/faas-provider/logs/logs.go
generated
vendored
Normal file
50
gateway/vendor/github.com/openfaas/faas-provider/logs/logs.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Package logs provides the standard interface and handler for OpenFaaS providers to expose function logs.
|
||||||
|
//
|
||||||
|
// The package defines the Requester interface that OpenFaaS providers should implement and then expose using
|
||||||
|
// the predefined NewLogHandlerFunc. See the example folder for a minimal log provider implementation.
|
||||||
|
//
|
||||||
|
// The Requester is where the actual specific logic for connecting to and querying the log system should be implemented.
|
||||||
|
//
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Request is the query to return the function logs.
|
||||||
|
type Request struct {
|
||||||
|
// Name is the function name and is required
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Instance is the optional container name, that allows you to request logs from a specific function instance
|
||||||
|
Instance string `json:"instance"`
|
||||||
|
// Since is the optional datetime value to start the logs from
|
||||||
|
Since *time.Time `json:"since"`
|
||||||
|
// Tail sets the maximum number of log messages to return, <=0 means unlimited
|
||||||
|
Tail int `json:"tail"`
|
||||||
|
// Follow is allows the user to request a stream of logs until the timeout
|
||||||
|
Follow bool `json:"follow"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements that Stringer interface and prints the log Request in a consistent way that
|
||||||
|
// allows you to safely compare if two requests have the same value.
|
||||||
|
func (r Request) String() string {
|
||||||
|
return fmt.Sprintf("name:%s instance:%s since:%v tail:%d follow:%v", r.Name, r.Instance, r.Since, r.Tail, r.Follow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is a specific log message from a function container log stream
|
||||||
|
type Message struct {
|
||||||
|
// Name is the function name
|
||||||
|
Name string `json:"name"`
|
||||||
|
// instance is the name/id of the specific function instance
|
||||||
|
Instance string `json:"instance"`
|
||||||
|
// Timestamp is the timestamp of when the log message was recorded
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
// Text is the raw log message content
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface and allows for nice and simple string formatting of a log Message.
|
||||||
|
func (m Message) String() string {
|
||||||
|
return fmt.Sprintf("%s %s (%s) %s", m.Timestamp.String(), m.Name, m.Instance, m.Text)
|
||||||
|
}
|
4
gateway/vendor/github.com/openfaas/faas-provider/proxy/handler_test.go
generated
vendored
4
gateway/vendor/github.com/openfaas/faas-provider/proxy/handler_test.go
generated
vendored
@ -86,7 +86,7 @@ func Test_ProxyHandler_MissingFunctionNameError(t *testing.T) {
|
|||||||
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
respBody := w.Body.String()
|
respBody := strings.TrimSpace(w.Body.String())
|
||||||
if respBody != errMissingFunctionName {
|
if respBody != errMissingFunctionName {
|
||||||
t.Errorf("expected error message `%s`, got `%s`", errMissingFunctionName, respBody)
|
t.Errorf("expected error message `%s`, got `%s`", errMissingFunctionName, respBody)
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ func Test_ProxyHandler_ResolveError(t *testing.T) {
|
|||||||
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
respBody := w.Body.String()
|
respBody := strings.TrimSpace(w.Body.String())
|
||||||
if respBody != "Cannot find service: foo." {
|
if respBody != "Cannot find service: foo." {
|
||||||
t.Errorf("expected error message `%s`, got `%s`", "Cannot find service: foo.", respBody)
|
t.Errorf("expected error message `%s`, got `%s`", "Cannot find service: foo.", respBody)
|
||||||
}
|
}
|
||||||
|
17
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy.go
generated
vendored
17
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy.go
generated
vendored
@ -21,7 +21,6 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -30,6 +29,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/openfaas/faas-provider/httputils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -112,7 +112,7 @@ func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient
|
|||||||
pathVars := mux.Vars(originalReq)
|
pathVars := mux.Vars(originalReq)
|
||||||
functionName := pathVars["name"]
|
functionName := pathVars["name"]
|
||||||
if functionName == "" {
|
if functionName == "" {
|
||||||
writeError(w, http.StatusBadRequest, errMissingFunctionName)
|
httputils.Errorf(w, http.StatusBadRequest, errMissingFunctionName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,13 +120,13 @@ func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient
|
|||||||
if resolveErr != nil {
|
if resolveErr != nil {
|
||||||
// TODO: Should record the 404/not found error in Prometheus.
|
// TODO: Should record the 404/not found error in Prometheus.
|
||||||
log.Printf("resolver error: cannot find %s: %s\n", functionName, resolveErr.Error())
|
log.Printf("resolver error: cannot find %s: %s\n", functionName, resolveErr.Error())
|
||||||
writeError(w, http.StatusNotFound, "Cannot find service: %s.", functionName)
|
httputils.Errorf(w, http.StatusNotFound, "Cannot find service: %s.", functionName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyReq, err := buildProxyRequest(originalReq, functionAddr, pathVars["params"])
|
proxyReq, err := buildProxyRequest(originalReq, functionAddr, pathVars["params"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, "Failed to resolve service: %s.", functionName)
|
httputils.Errorf(w, http.StatusInternalServerError, "Failed to resolve service: %s.", functionName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if proxyReq.Body != nil {
|
if proxyReq.Body != nil {
|
||||||
@ -140,7 +140,7 @@ func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error with proxy request to: %s, %s\n", proxyReq.URL.String(), err.Error())
|
log.Printf("error with proxy request to: %s, %s\n", proxyReq.URL.String(), err.Error())
|
||||||
|
|
||||||
writeError(w, http.StatusInternalServerError, "Can't reach service for: %s.", functionName)
|
httputils.Errorf(w, http.StatusInternalServerError, "Can't reach service for: %s.", functionName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,10 +214,3 @@ func getContentType(request http.Header, proxyResponse http.Header) (headerConte
|
|||||||
|
|
||||||
return headerContentType
|
return headerContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeError sets the response status code and write formats the provided message as the
|
|
||||||
// response body
|
|
||||||
func writeError(w http.ResponseWriter, statusCode int, msg string, args ...interface{}) {
|
|
||||||
w.WriteHeader(statusCode)
|
|
||||||
w.Write([]byte(fmt.Sprintf(msg, args...)))
|
|
||||||
}
|
|
||||||
|
2
gateway/vendor/github.com/openfaas/faas-provider/serve.go
generated
vendored
2
gateway/vendor/github.com/openfaas/faas-provider/serve.go
generated
vendored
@ -46,6 +46,7 @@ func Serve(handlers *types.FaaSHandlers, config *types.FaaSConfig) {
|
|||||||
handlers.ReplicaUpdater = auth.DecorateWithBasicAuth(handlers.ReplicaUpdater, credentials)
|
handlers.ReplicaUpdater = auth.DecorateWithBasicAuth(handlers.ReplicaUpdater, credentials)
|
||||||
handlers.InfoHandler = auth.DecorateWithBasicAuth(handlers.InfoHandler, credentials)
|
handlers.InfoHandler = auth.DecorateWithBasicAuth(handlers.InfoHandler, credentials)
|
||||||
handlers.SecretHandler = auth.DecorateWithBasicAuth(handlers.SecretHandler, credentials)
|
handlers.SecretHandler = auth.DecorateWithBasicAuth(handlers.SecretHandler, credentials)
|
||||||
|
handlers.LogHandler = auth.DecorateWithBasicAuth(handlers.LogHandler, credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
// System (auth) endpoints
|
// System (auth) endpoints
|
||||||
@ -59,6 +60,7 @@ func Serve(handlers *types.FaaSHandlers, config *types.FaaSConfig) {
|
|||||||
r.HandleFunc("/system/info", handlers.InfoHandler).Methods("GET")
|
r.HandleFunc("/system/info", handlers.InfoHandler).Methods("GET")
|
||||||
|
|
||||||
r.HandleFunc("/system/secrets", handlers.SecretHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete)
|
r.HandleFunc("/system/secrets", handlers.SecretHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete)
|
||||||
|
r.HandleFunc("/system/logs", handlers.LogHandler).Methods(http.MethodGet)
|
||||||
|
|
||||||
// Open endpoints
|
// Open endpoints
|
||||||
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", handlers.FunctionProxy)
|
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", handlers.FunctionProxy)
|
||||||
|
2
gateway/vendor/github.com/openfaas/faas-provider/types/config.go
generated
vendored
2
gateway/vendor/github.com/openfaas/faas-provider/types/config.go
generated
vendored
@ -16,6 +16,8 @@ type FaaSHandlers struct {
|
|||||||
ReplicaReader http.HandlerFunc
|
ReplicaReader http.HandlerFunc
|
||||||
ReplicaUpdater http.HandlerFunc
|
ReplicaUpdater http.HandlerFunc
|
||||||
SecretHandler http.HandlerFunc
|
SecretHandler http.HandlerFunc
|
||||||
|
// LogHandler provides streaming json logs of functions
|
||||||
|
LogHandler http.HandlerFunc
|
||||||
|
|
||||||
// Optional: Update an existing function
|
// Optional: Update an existing function
|
||||||
UpdateHandler http.HandlerFunc
|
UpdateHandler http.HandlerFunc
|
||||||
|
Reference in New Issue
Block a user