Update faas-provider version

Signed-off-by: Alex Ellis <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis 2019-06-08 10:16:30 +01:00
parent 678e93599e
commit 701708fe0e
11 changed files with 167 additions and 18 deletions

6
gateway/Gopkg.lock generated
View File

@ -93,12 +93,12 @@
version = "v1.0.0"
[[projects]]
digest = "1:6349b4be853e8be701de22e7d081c433447d185c0eeb8651d67bfc03c344f3fb"
digest = "1:84708b04710afa61221f72ace164ce7fb6d26a7647b3a61d1af18d0e51f88d29"
name = "github.com/openfaas/faas-provider"
packages = ["auth"]
pruneopts = ""
revision = "220324e98f5db5aa61f02d1ab13f03e91310796c"
version = "0.8.1"
revision = "376c26ef02007abb7cadbd550bb75df166764473"
version = "0.9.1"
[[projects]]
digest = "1:c91d031a0f53699e18f204e8a8d360d400a34686a3bb34d82c63a53ff1d73cea"

View File

@ -26,4 +26,4 @@ ignored = ["github.com/openfaas/faas/gateway/queue"]
[[constraint]]
name = "github.com/openfaas/faas-provider"
version = "0.8.1"
version = "0.9.1"

View File

@ -13,4 +13,7 @@
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Goland IDE
.idea
faas-backend

View File

@ -1,23 +1,30 @@
faas-provider
==============
This is a common template or interface for you to start building your own OpenFaaS backend.
This faas-provider can be used to write your own back-end for OpenFaaS. The Golang SDK can be vendored into your project so that you can provide a provider which is compliant and compatible with the OpenFaaS gateway.
Checkout the [backends guide here](https://github.com/openfaas/faas/blob/master/guide/backends.md) before starting.
![Conceptual diagram](docs/conceptual.png)
OpenFaaS projects use the MIT License and are written in Golang. We encourage the same for external / third-party providers.
The faas-provider provides CRUD for functions and an invoke capability. If you complete the required endpoints then you will be able to use your container orchestrator or back-end system with the existing OpenFaaS ecosystem and tooling.
### How to use this code
> See also: [backends guide](https://github.com/openfaas/faas/blob/master/guide/deprecated/backends.md)
We will setup all the standard HTTP routes for you, then start listening on a given TCP port - it should be 8080.
### Recommendations
Just implement the supplied routes.
The following is used in OpenFaaS and recommended for those seeking to build their own back-ends:
For an example checkout the [server.go](https://github.com/openfaas/faas-netes/blob/master/server.go) file in the [faas-netes](https://github.com/openfaas/faas-netes) Kubernetes backend.
* License: MIT
* Language: Golang
### How to use this project
All the required HTTP routes are configured automatically including a HTTP server on port 8080. Your task is to implement the supplied HTTP handler functions.
For an example see the [server.go](https://github.com/openfaas/faas-netes/blob/master/server.go) file in the [faas-netes](https://github.com/openfaas/faas-netes) Kubernetes backend.
I.e.:
```golang
```go
bootstrapHandlers := bootTypes.FaaSHandlers{
FunctionProxy: handlers.MakeProxy(),
DeleteHandler: handlers.MakeDeleteHandler(clientset),
@ -27,6 +34,7 @@ I.e.:
ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
InfoHandler: handlers.MakeInfoHandler(),
}
var port int
port = 8080
bootstrapConfig := bootTypes.FaaSConfig{
@ -37,3 +45,7 @@ I.e.:
bootstrap.Serve(&bootstrapHandlers, &bootstrapConfig)
```
### Need help?
Join `#faas-provider` on [OpenFaaS Slack](https://docs.openfaas.com/community/)

View File

@ -22,6 +22,10 @@ type ReadBasicAuth interface {
type ReadBasicAuthFromDisk struct {
SecretMountPath string
UserFilename string
PasswordFilename string
}
func (r *ReadBasicAuthFromDisk) Read() (*BasicAuthCredentials, error) {
@ -31,13 +35,23 @@ func (r *ReadBasicAuthFromDisk) Read() (*BasicAuthCredentials, error) {
return nil, fmt.Errorf("invalid SecretMountPath specified for reading secrets")
}
userPath := path.Join(r.SecretMountPath, "basic-auth-user")
userKey := "basic-auth-user"
if len(r.UserFilename) > 0 {
userKey = r.UserFilename
}
passwordKey := "basic-auth-password"
if len(r.PasswordFilename) > 0 {
passwordKey = r.PasswordFilename
}
userPath := path.Join(r.SecretMountPath, userKey)
user, userErr := ioutil.ReadFile(userPath)
if userErr != nil {
return nil, fmt.Errorf("unable to load %s", userPath)
}
userPassword := path.Join(r.SecretMountPath, "basic-auth-password")
userPassword := path.Join(r.SecretMountPath, passwordKey)
password, passErr := ioutil.ReadFile(userPassword)
if passErr != nil {
return nil, fmt.Errorf("Unable to load %s", userPassword)

View File

@ -0,0 +1,64 @@
// 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 auth
import (
"io/ioutil"
"os"
"path"
"testing"
)
func Test_ReadFromCustomLocation_AndNames(t *testing.T) {
tmp := os.TempDir()
userWant := "admin"
ioutil.WriteFile(path.Join(tmp, "user.txt"), []byte(userWant), 0700)
passWant := "test1234"
ioutil.WriteFile(path.Join(tmp, "pass.txt"), []byte(passWant), 0700)
reader := ReadBasicAuthFromDisk{
SecretMountPath: tmp,
UserFilename: "user.txt",
PasswordFilename: "pass.txt",
}
creds, err := reader.Read()
if err != nil {
t.Errorf("can't read secrets: %s", err.Error())
}
if creds.User != userWant {
t.Errorf("user, want: %s, got %s", userWant, creds.User)
}
if creds.Password != passWant {
t.Errorf("password, want: %s, got %s", passWant, creds.Password)
}
}
func Test_ReadFromCustomLocation_DefaultNames(t *testing.T) {
tmp := os.TempDir()
userWant := "admin"
ioutil.WriteFile(path.Join(tmp, "basic-auth-user"), []byte(userWant), 0700)
passWant := "test1234"
ioutil.WriteFile(path.Join(tmp, "basic-auth-password"), []byte(passWant), 0700)
reader := ReadBasicAuthFromDisk{
SecretMountPath: tmp,
}
creds, err := reader.Read()
if err != nil {
t.Errorf("can't read secrets: %s", err.Error())
}
if creds.User != userWant {
t.Errorf("user, want: %s, got %s", userWant, creds.User)
}
if creds.Password != passWant {
t.Errorf("password, want: %s, got %s", passWant, creds.Password)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@ -129,7 +129,9 @@ func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient
writeError(w, http.StatusInternalServerError, "Failed to resolve service: %s.", functionName)
return
}
defer proxyReq.Body.Close()
if proxyReq.Body != nil {
defer proxyReq.Body.Close()
}
start := time.Now()
response, err := proxyClient.Do(proxyReq.WithContext(ctx))
@ -148,7 +150,7 @@ func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient
copyHeaders(clientHeader, &response.Header)
w.Header().Set("Content-Type", getContentType(response.Header, originalReq.Header))
w.WriteHeader(http.StatusOK)
w.WriteHeader(response.StatusCode)
io.Copy(w, response.Body)
}

View File

@ -7,7 +7,9 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/gorilla/mux"
)
@ -25,6 +27,58 @@ func testResolver(functionName string) (url.URL, error) {
}, nil
}
type mockResolver struct {
u *url.URL
err error
}
func (m mockResolver) Resolve(name string) (url.URL, error) {
if m.u != nil {
return *m.u, m.err
}
return url.URL{}, m.err
}
func Test_ProxyHandler_StatusCode(t *testing.T) {
testcases := []int{200, 204, 400, 409, 422, 500, 503}
for _, tc := range testcases {
t.Run(fmt.Sprintf("returns %d when upstream returns %d", tc, tc), func(t *testing.T) {
// upstream represents the will be resolved and the function call then sent to
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if tc > 399 {
http.Error(w, "upstream error", tc)
return
}
w.WriteHeader(tc)
}))
u, err := url.Parse(upstream.URL)
proxyHandler := NewHandlerFunc(time.Second, mockResolver{u, err})
rr := httptest.NewRecorder()
req, err := http.NewRequest("GET", "", nil)
if err != nil {
t.Fatal(err)
}
// we must set the function name URL variable to pass the validation in proxyRequest
req = mux.SetURLVars(req, map[string]string{"name": "foo"})
proxyHandler.ServeHTTP(rr, req)
if rr.Code != tc {
t.Fatalf("unexpected status code; got: %d, expected: %d", rr.Code, tc)
}
if tc > 399 && strings.TrimSpace(rr.Body.String()) != "upstream error" {
t.Fatalf("unexpected response body, got: %s", rr.Body.String())
}
})
}
}
func Test_pathParsing(t *testing.T) {
tt := []struct {
name string

View File

@ -66,7 +66,7 @@ func Serve(handlers *types.FaaSHandlers, config *types.FaaSConfig) {
r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/{params:.*}", handlers.FunctionProxy)
if config.EnableHealth {
r.HandleFunc("/healthz", handlers.Health).Methods("GET")
r.HandleFunc("/healthz", handlers.HealthHandler).Methods("GET")
}
readTimeout := config.ReadTimeout

View File

@ -19,7 +19,7 @@ type FaaSHandlers struct {
// Optional: Update an existing function
UpdateHandler http.HandlerFunc
Health http.HandlerFunc
HealthHandler http.HandlerFunc
InfoHandler http.HandlerFunc
}