Initial merge of faas-containerd

This patch completes part of the work in #20 by porting the code
for faas-containerd in-tree. When tested, I was able to deploy
and then remove figlet from the store on `x86_64`.

In a follow-up PR, duplication will be removed where possible
and consolidated with updated documentation.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis (OpenFaaS Ltd)
2020-01-21 13:12:44 +00:00
committed by Alex Ellis
parent cda1fe78b1
commit 42e9c91ee9
52 changed files with 5260 additions and 3 deletions

1
vendor/github.com/openfaas/faas-provider/.DEREK.yml generated vendored Normal file
View File

@ -0,0 +1 @@
redirect: https://raw.githubusercontent.com/openfaas/faas/master/.DEREK.yml

19
vendor/github.com/openfaas/faas-provider/.gitignore generated vendored Normal file
View File

@ -0,0 +1,19 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Goland IDE
.idea
faas-backend

4
vendor/github.com/openfaas/faas-provider/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,4 @@
language: go
go_import_path: github.com/openfaas/faas-provider
script:
- make test

27
vendor/github.com/openfaas/faas-provider/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,27 @@
FROM golang:1.11-alpine3.10
ENV CGO_ENABLED=0
RUN mkdir -p /go/src/github.com/openfaas/faas-provider/
WORKDIR /go/src/github.com/openfaas/faas-provider
COPY vendor vendor
COPY types types
COPY auth auth
COPY serve.go .
RUN go test ./auth/ -v \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o faas-provider .
FROM alpine:3.8
RUN apk --no-cache add ca-certificates
WORKDIR /root/
EXPOSE 8080
ENV http_proxy ""
ENV https_proxy ""
COPY --from=0 /go/src/github.com/openfaas/faas-provider/faas-provider .
CMD ["./faas-provider]

39
vendor/github.com/openfaas/faas-provider/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,39 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:160eabf7a69910fd74f29c692718bc2437c1c1c7d4c9dea9712357752a70e5df"
name = "github.com/gorilla/context"
packages = ["."]
pruneopts = "UT"
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
[[projects]]
digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
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]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/gorilla/mux",
"go.uber.org/goleak",
]
solver-name = "gps-cdcl"
solver-version = 1

7
vendor/github.com/openfaas/faas-provider/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,7 @@
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.2"

21
vendor/github.com/openfaas/faas-provider/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Alex Ellis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
vendor/github.com/openfaas/faas-provider/Makefile generated vendored Normal file
View File

@ -0,0 +1,6 @@
build:
docker build -t faas-provider .
test :
go test -cover ./...

53
vendor/github.com/openfaas/faas-provider/README.md generated vendored Normal file
View File

@ -0,0 +1,53 @@
faas-provider
==============
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.
![Conceptual diagram](docs/conceptual.png)
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.
> See also: [backends guide](https://github.com/openfaas/faas/blob/master/guide/deprecated/backends.md)
### Recommendations
The following is used in OpenFaaS and recommended for those seeking to build their own back-ends:
* 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.:
```go
timeout := 8 * time.Second
bootstrapHandlers := bootTypes.FaaSHandlers{
FunctionProxy: handlers.MakeProxy(),
DeleteHandler: handlers.MakeDeleteHandler(clientset),
DeployHandler: handlers.MakeDeployHandler(clientset),
FunctionReader: handlers.MakeFunctionReader(clientset),
ReplicaReader: handlers.MakeReplicaReader(clientset),
ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
InfoHandler: handlers.MakeInfoHandler(),
LogHandler: logs.NewLogHandlerFunc(requestor,timeout),
}
var port int
port = 8080
bootstrapConfig := bootTypes.FaaSConfig{
ReadTimeout: timeout,
WriteTimeout: timeout,
TCPPort: &port,
}
bootstrap.Serve(&bootstrapHandlers, &bootstrapConfig)
```
### Need help?
Join `#faas-provider` on [OpenFaaS Slack](https://docs.openfaas.com/community/)

View File

@ -0,0 +1,30 @@
// 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 (
"crypto/subtle"
"net/http"
)
// DecorateWithBasicAuth enforces basic auth as a middleware with given credentials
func DecorateWithBasicAuth(next http.HandlerFunc, credentials *BasicAuthCredentials) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, password, ok := r.BasicAuth()
const noMatch = 0
if !ok ||
user != credentials.User ||
subtle.ConstantTimeCompare([]byte(credentials.Password), []byte(password)) == noMatch {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("invalid credentials"))
return
}
next.ServeHTTP(w, r)
}
}

View File

@ -0,0 +1,66 @@
// 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 (
"fmt"
"io/ioutil"
"path"
"strings"
)
// BasicAuthCredentials for credentials
type BasicAuthCredentials struct {
User string
Password string
}
type ReadBasicAuth interface {
Read() (*BasicAuthCredentials, error)
}
type ReadBasicAuthFromDisk struct {
SecretMountPath string
UserFilename string
PasswordFilename string
}
func (r *ReadBasicAuthFromDisk) Read() (*BasicAuthCredentials, error) {
var credentials *BasicAuthCredentials
if len(r.SecretMountPath) == 0 {
return nil, fmt.Errorf("invalid SecretMountPath specified for reading secrets")
}
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, passwordKey)
password, passErr := ioutil.ReadFile(userPassword)
if passErr != nil {
return nil, fmt.Errorf("Unable to load %s", userPassword)
}
credentials = &BasicAuthCredentials{
User: strings.TrimSpace(string(user)),
Password: strings.TrimSpace(string(password)),
}
return credentials, nil
}

View 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)
}

241
vendor/github.com/openfaas/faas-provider/proxy/proxy.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
// Package proxy provides a default function invocation proxy method for OpenFaaS providers.
//
// The function proxy logic is used by the Gateway when `direct_functions` is set to false.
// This means that the provider will direct call the function and return the results. This
// involves resolving the function by name and then copying the result into the original HTTP
// request.
//
// openfaas-provider has implemented a standard HTTP HandlerFunc that will handle setting
// timeout values, parsing the request path, and copying the request/response correctly.
// bootstrapHandlers := bootTypes.FaaSHandlers{
// FunctionProxy: proxy.NewHandlerFunc(timeout, resolver),
// DeleteHandler: handlers.MakeDeleteHandler(clientset),
// DeployHandler: handlers.MakeDeployHandler(clientset),
// FunctionReader: handlers.MakeFunctionReader(clientset),
// ReplicaReader: handlers.MakeReplicaReader(clientset),
// ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
// InfoHandler: handlers.MakeInfoHandler(),
// }
//
// proxy.NewHandlerFunc is optional, but does simplify the logic of your provider.
package proxy
import (
"io"
"log"
"net"
"net/http"
"net/url"
"time"
"github.com/gorilla/mux"
"github.com/openfaas/faas-provider/httputil"
"github.com/openfaas/faas-provider/types"
)
const (
watchdogPort = "8080"
defaultContentType = "text/plain"
errMissingFunctionName = "Please provide a valid route /function/function_name."
)
// BaseURLResolver URL resolver for proxy requests
//
// The FaaS provider implementation is responsible for providing the resolver function implementation.
// BaseURLResolver.Resolve will receive the function name and should return the URL of the
// function service.
type BaseURLResolver interface {
Resolve(functionName string) (url.URL, error)
}
// NewHandlerFunc creates a standard http.HandlerFunc to proxy function requests.
// The returned http.HandlerFunc will ensure:
//
// - proper proxy request timeouts
// - proxy requests for GET, POST, PATCH, PUT, and DELETE
// - path parsing including support for extracing the function name, sub-paths, and query paremeters
// - passing and setting the `X-Forwarded-Host` and `X-Forwarded-For` headers
// - logging errors and proxy request timing to stdout
//
// Note that this will panic if `resolver` is nil.
func NewHandlerFunc(config types.FaaSConfig, resolver BaseURLResolver) http.HandlerFunc {
if resolver == nil {
panic("NewHandlerFunc: empty proxy handler resolver, cannot be nil")
}
proxyClient := NewProxyClientFromConfig(config)
return func(w http.ResponseWriter, r *http.Request) {
if r.Body != nil {
defer r.Body.Close()
}
switch r.Method {
case http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodGet:
proxyRequest(w, r, proxyClient, resolver)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
}
// NewProxyClientFromConfig creates a new http.Client designed for proxying requests and enforcing
// certain minimum configuration values.
func NewProxyClientFromConfig(config types.FaaSConfig) *http.Client {
return NewProxyClient(config.GetReadTimeout(), config.GetMaxIdleConns(), config.GetMaxIdleConnsPerHost())
}
// NewProxyClient creates a new http.Client designed for proxying requests, this is exposed as a
// convenience method for internal or advanced uses. Most people should use NewProxyClientFromConfig.
func NewProxyClient(timeout time.Duration, maxIdleConns int, maxIdleConnsPerHost int) *http.Client {
return &http.Client{
// these Transport values ensure that the http Client will eventually timeout and prevents
// infinite retries. The default http.Client configure these timeouts. The specific
// values tuned via performance testing/benchmarking
//
// Additional context can be found at
// - https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779
// - https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/
//
// Additionally, these overrides for the default client enable re-use of connections and prevent
// CoreDNS from rate limiting under high traffic
//
// See also two similar projects where this value was updated:
// https://github.com/prometheus/prometheus/pull/3592
// https://github.com/minio/minio/pull/5860
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: timeout,
KeepAlive: 1 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: maxIdleConns,
MaxIdleConnsPerHost: maxIdleConnsPerHost,
IdleConnTimeout: 120 * time.Millisecond,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1500 * time.Millisecond,
},
Timeout: timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
}
// proxyRequest handles the actual resolution of and then request to the function service.
func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient *http.Client, resolver BaseURLResolver) {
ctx := originalReq.Context()
pathVars := mux.Vars(originalReq)
functionName := pathVars["name"]
if functionName == "" {
httputil.Errorf(w, http.StatusBadRequest, errMissingFunctionName)
return
}
functionAddr, resolveErr := resolver.Resolve(functionName)
if resolveErr != nil {
// TODO: Should record the 404/not found error in Prometheus.
log.Printf("resolver error: cannot find %s: %s\n", functionName, resolveErr.Error())
httputil.Errorf(w, http.StatusNotFound, "Cannot find service: %s.", functionName)
return
}
proxyReq, err := buildProxyRequest(originalReq, functionAddr, pathVars["params"])
if err != nil {
httputil.Errorf(w, http.StatusInternalServerError, "Failed to resolve service: %s.", functionName)
return
}
if proxyReq.Body != nil {
defer proxyReq.Body.Close()
}
start := time.Now()
response, err := proxyClient.Do(proxyReq.WithContext(ctx))
seconds := time.Since(start)
if err != nil {
log.Printf("error with proxy request to: %s, %s\n", proxyReq.URL.String(), err.Error())
httputil.Errorf(w, http.StatusInternalServerError, "Can't reach service for: %s.", functionName)
return
}
defer response.Body.Close()
log.Printf("%s took %f seconds\n", functionName, seconds.Seconds())
clientHeader := w.Header()
copyHeaders(clientHeader, &response.Header)
w.Header().Set("Content-Type", getContentType(response.Header, originalReq.Header))
w.WriteHeader(response.StatusCode)
io.Copy(w, response.Body)
}
// buildProxyRequest creates a request object for the proxy request, it will ensure that
// the original request headers are preserved as well as setting openfaas system headers
func buildProxyRequest(originalReq *http.Request, baseURL url.URL, extraPath string) (*http.Request, error) {
host := baseURL.Host
if baseURL.Port() == "" {
host = baseURL.Host + ":" + watchdogPort
}
url := url.URL{
Scheme: baseURL.Scheme,
Host: host,
Path: extraPath,
RawQuery: originalReq.URL.RawQuery,
}
upstreamReq, err := http.NewRequest(originalReq.Method, url.String(), nil)
if err != nil {
return nil, err
}
copyHeaders(upstreamReq.Header, &originalReq.Header)
if len(originalReq.Host) > 0 && upstreamReq.Header.Get("X-Forwarded-Host") == "" {
upstreamReq.Header["X-Forwarded-Host"] = []string{originalReq.Host}
}
if upstreamReq.Header.Get("X-Forwarded-For") == "" {
upstreamReq.Header["X-Forwarded-For"] = []string{originalReq.RemoteAddr}
}
if originalReq.Body != nil {
upstreamReq.Body = originalReq.Body
}
return upstreamReq, nil
}
// copyHeaders clones the header values from the source into the destination.
func copyHeaders(destination http.Header, source *http.Header) {
for k, v := range *source {
vClone := make([]string, len(v))
copy(vClone, v)
destination[k] = vClone
}
}
// getContentType resolves the correct Content-Type for a proxied function.
func getContentType(request http.Header, proxyResponse http.Header) (headerContentType string) {
responseHeader := proxyResponse.Get("Content-Type")
requestHeader := request.Get("Content-Type")
if len(responseHeader) > 0 {
headerContentType = responseHeader
} else if len(requestHeader) > 0 {
headerContentType = requestHeader
} else {
headerContentType = defaultContentType
}
return headerContentType
}

96
vendor/github.com/openfaas/faas-provider/serve.go generated vendored Normal file
View File

@ -0,0 +1,96 @@
// 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 bootstrap
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/openfaas/faas-provider/auth"
"github.com/openfaas/faas-provider/types"
)
// NameExpression for a function / service
const NameExpression = "-a-zA-Z_0-9."
var r *mux.Router
// Mark this as a Golang "package"
func init() {
r = mux.NewRouter()
}
// Router gives access to the underlying router for when new routes need to be added.
func Router() *mux.Router {
return r
}
// Serve load your handlers into the correct OpenFaaS route spec. This function is blocking.
func Serve(handlers *types.FaaSHandlers, config *types.FaaSConfig) {
if config.EnableBasicAuth {
reader := auth.ReadBasicAuthFromDisk{
SecretMountPath: config.SecretMountPath,
}
credentials, err := reader.Read()
if err != nil {
log.Fatal(err)
}
handlers.FunctionReader = auth.DecorateWithBasicAuth(handlers.FunctionReader, credentials)
handlers.DeployHandler = auth.DecorateWithBasicAuth(handlers.DeployHandler, credentials)
handlers.DeleteHandler = auth.DecorateWithBasicAuth(handlers.DeleteHandler, credentials)
handlers.UpdateHandler = auth.DecorateWithBasicAuth(handlers.UpdateHandler, credentials)
handlers.ReplicaReader = auth.DecorateWithBasicAuth(handlers.ReplicaReader, credentials)
handlers.ReplicaUpdater = auth.DecorateWithBasicAuth(handlers.ReplicaUpdater, credentials)
handlers.InfoHandler = auth.DecorateWithBasicAuth(handlers.InfoHandler, credentials)
handlers.SecretHandler = auth.DecorateWithBasicAuth(handlers.SecretHandler, credentials)
handlers.LogHandler = auth.DecorateWithBasicAuth(handlers.LogHandler, credentials)
}
// System (auth) endpoints
r.HandleFunc("/system/functions", handlers.FunctionReader).Methods("GET")
r.HandleFunc("/system/functions", handlers.DeployHandler).Methods("POST")
r.HandleFunc("/system/functions", handlers.DeleteHandler).Methods("DELETE")
r.HandleFunc("/system/functions", handlers.UpdateHandler).Methods("PUT")
r.HandleFunc("/system/function/{name:["+NameExpression+"]+}", handlers.ReplicaReader).Methods("GET")
r.HandleFunc("/system/scale-function/{name:["+NameExpression+"]+}", handlers.ReplicaUpdater).Methods("POST")
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/logs", handlers.LogHandler).Methods(http.MethodGet)
r.HandleFunc("/system/namespaces", handlers.ListNamespaceHandler).Methods("GET")
// Open endpoints
r.HandleFunc("/function/{name:["+NameExpression+"]+}", handlers.FunctionProxy)
r.HandleFunc("/function/{name:["+NameExpression+"]+}/", handlers.FunctionProxy)
r.HandleFunc("/function/{name:["+NameExpression+"]+}/{params:.*}", handlers.FunctionProxy)
if handlers.HealthHandler != nil {
r.HandleFunc("/healthz", handlers.HealthHandler).Methods("GET")
}
readTimeout := config.ReadTimeout
writeTimeout := config.WriteTimeout
tcpPort := 8080
if config.TCPPort != nil {
tcpPort = *config.TCPPort
}
s := &http.Server{
Addr: fmt.Sprintf(":%d", tcpPort),
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
MaxHeaderBytes: http.DefaultMaxHeaderBytes, // 1MB - can be overridden by setting Server.MaxHeaderBytes.
Handler: r,
}
log.Fatal(s.ListenAndServe())
}

View File

@ -0,0 +1,87 @@
package types
import (
"net/http"
"time"
)
const (
defaultReadTimeout = 10 * time.Second
defaultMaxIdleConns = 1024
)
// FaaSHandlers provide handlers for OpenFaaS
type FaaSHandlers struct {
// FunctionProxy provides the function invocation proxy logic. Use proxy.NewHandlerFunc to
// use the standard OpenFaaS proxy implementation or provide completely custom proxy logic.
FunctionProxy http.HandlerFunc
FunctionReader http.HandlerFunc
DeployHandler http.HandlerFunc
DeleteHandler http.HandlerFunc
ReplicaReader http.HandlerFunc
ReplicaUpdater http.HandlerFunc
SecretHandler http.HandlerFunc
// LogHandler provides streaming json logs of functions
LogHandler http.HandlerFunc
// UpdateHandler an existing function/service
UpdateHandler http.HandlerFunc
// HealthHandler defines the default health endpoint bound to "/healthz
// If the handler is not set, then the "/healthz" path will not be configured
HealthHandler http.HandlerFunc
InfoHandler http.HandlerFunc
ListNamespaceHandler http.HandlerFunc
}
// FaaSConfig set config for HTTP handlers
type FaaSConfig struct {
// TCPPort is the public port for the API.
TCPPort *int
// HTTP timeout for reading a request from clients.
ReadTimeout time.Duration
// HTTP timeout for writing a response from functions.
WriteTimeout time.Duration
// EnableHealth enables/disables the default health endpoint bound to "/healthz".
//
// Deprecated: basic auth is enabled automatcally by setting the HealthHandler in the FaaSHandlers
// struct. This value is not longer read or used.
EnableHealth bool
// EnableBasicAuth enforces basic auth on the API. If set, reads secrets from file-system
// location specificed in `SecretMountPath`.
EnableBasicAuth bool
// SecretMountPath specifies where to read secrets from for embedded basic auth.
SecretMountPath string
// MaxIdleConns with a default value of 1024, can be used for tuning HTTP proxy performance.
MaxIdleConns int
// MaxIdleConnsPerHost with a default value of 1024, can be used for tuning HTTP proxy performance.
MaxIdleConnsPerHost int
}
// GetReadTimeout is a helper to safely return the configured ReadTimeout or the default value of 10s
func (c *FaaSConfig) GetReadTimeout() time.Duration {
if c.ReadTimeout <= 0*time.Second {
return defaultReadTimeout
}
return c.ReadTimeout
}
// GetMaxIdleConns is a helper to safely return the configured MaxIdleConns or the default value of 1024
func (c *FaaSConfig) GetMaxIdleConns() int {
if c.MaxIdleConns < 1 {
return defaultMaxIdleConns
}
return c.MaxIdleConns
}
// GetMaxIdleConns is a helper to safely return the configured MaxIdleConns or the default value which
// should then match the MaxIdleConns
func (c *FaaSConfig) GetMaxIdleConnsPerHost() int {
if c.MaxIdleConnsPerHost < 1 {
return c.GetMaxIdleConns()
}
return c.MaxIdleConnsPerHost
}

View File

@ -0,0 +1,99 @@
package types
// FunctionDeployment represents a request to create or update a Function.
type FunctionDeployment struct {
// Service corresponds to a Service
Service string `json:"service"`
// Image corresponds to a Docker image
Image string `json:"image"`
// Network is specific to Docker Swarm - default overlay network is: func_functions
Network string `json:"network"`
// EnvProcess corresponds to the fprocess variable for your container watchdog.
EnvProcess string `json:"envProcess"`
// EnvVars provides overrides for functions.
EnvVars map[string]string `json:"envVars"`
// RegistryAuth is the registry authentication (optional)
// in the same encoded format as Docker native credentials
// (see ~/.docker/config.json)
RegistryAuth string `json:"registryAuth,omitempty"`
// Constraints are specific to back-end orchestration platform
Constraints []string `json:"constraints"`
// Secrets list of secrets to be made available to function
Secrets []string `json:"secrets"`
// Labels are metadata for functions which may be used by the
// back-end for making scheduling or routing decisions
Labels *map[string]string `json:"labels"`
// Annotations are metadata for functions which may be used by the
// back-end for management, orchestration, events and build tasks
Annotations *map[string]string `json:"annotations"`
// Limits for function
Limits *FunctionResources `json:"limits"`
// Requests of resources requested by function
Requests *FunctionResources `json:"requests"`
// ReadOnlyRootFilesystem removes write-access from the root filesystem
// mount-point.
ReadOnlyRootFilesystem bool `json:"readOnlyRootFilesystem"`
// Namespace for the function to be deployed into
Namespace string `json:"namespace,omitempty"`
}
// FunctionResources Memory and CPU
type FunctionResources struct {
Memory string `json:"memory"`
CPU string `json:"cpu"`
}
// FunctionStatus exported for system/functions endpoint
type FunctionStatus struct {
// Name corresponds to a Service
Name string `json:"name"`
// Image corresponds to a Docker image
Image string `json:"image"`
// InvocationCount count of invocations
InvocationCount float64 `json:"invocationCount"`
// Replicas desired within the cluster
Replicas uint64 `json:"replicas"`
// EnvProcess is the process to pass to the watchdog, if in use
EnvProcess string `json:"envProcess"`
// AvailableReplicas is the count of replicas ready to receive
// invocations as reported by the backend
AvailableReplicas uint64 `json:"availableReplicas"`
// Labels are metadata for functions which may be used by the
// backend for making scheduling or routing decisions
Labels *map[string]string `json:"labels"`
// Annotations are metadata for functions which may be used by the
// backend for management, orchestration, events and build tasks
Annotations *map[string]string `json:"annotations"`
// Namespace where the function can be accessed
Namespace string `json:"namespace,omitempty"`
}
// Secret for underlying orchestrator
type Secret struct {
Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
Value string `json:"value,omitempty"`
}

View File

@ -0,0 +1,112 @@
package types
import (
"fmt"
"os"
"strconv"
"time"
)
// OsEnv implements interface to wrap os.Getenv
type OsEnv struct {
}
// Getenv wraps os.Getenv
func (OsEnv) Getenv(key string) string {
return os.Getenv(key)
}
// HasEnv provides interface for os.Getenv
type HasEnv interface {
Getenv(key string) string
}
// ReadConfig constitutes config from env variables
type ReadConfig struct {
}
// ParseIntValue parses the the int in val or, if there is an error, returns the
// specified default value
func ParseIntValue(val string, fallback int) int {
if len(val) > 0 {
parsedVal, parseErr := strconv.Atoi(val)
if parseErr == nil && parsedVal >= 0 {
return parsedVal
}
}
return fallback
}
// ParseIntOrDurationValue parses the the duration in val or, if there is an error, returns the
// specified default value
func ParseIntOrDurationValue(val string, fallback time.Duration) time.Duration {
if len(val) > 0 {
parsedVal, parseErr := strconv.Atoi(val)
if parseErr == nil && parsedVal >= 0 {
return time.Duration(parsedVal) * time.Second
}
}
duration, durationErr := time.ParseDuration(val)
if durationErr != nil {
return fallback
}
return duration
}
// ParseBoolValue parses the the boolean in val or, if there is an error, returns the
// specified default value
func ParseBoolValue(val string, fallback bool) bool {
if len(val) > 0 {
return val == "true"
}
return fallback
}
// ParseString verifies the string in val is not empty. When empty, it returns the
// specified default value
func ParseString(val string, fallback string) string {
if len(val) > 0 {
return val
}
return fallback
}
// Read fetches config from environmental variables.
func (ReadConfig) Read(hasEnv HasEnv) (*FaaSConfig, error) {
cfg := &FaaSConfig{
ReadTimeout: ParseIntOrDurationValue(hasEnv.Getenv("read_timeout"), time.Second*10),
WriteTimeout: ParseIntOrDurationValue(hasEnv.Getenv("write_timeout"), time.Second*10),
EnableBasicAuth: ParseBoolValue(hasEnv.Getenv("basic_auth"), false),
// default value from Gateway
SecretMountPath: ParseString(hasEnv.Getenv("secret_mount_path"), "/run/secrets/"),
}
port := ParseIntValue(hasEnv.Getenv("port"), 8080)
cfg.TCPPort = &port
cfg.MaxIdleConns = 1024
maxIdleConns := hasEnv.Getenv("max_idle_conns")
if len(maxIdleConns) > 0 {
val, err := strconv.Atoi(maxIdleConns)
if err != nil {
return nil, fmt.Errorf("invalid value for max_idle_conns: %s", maxIdleConns)
}
cfg.MaxIdleConns = val
}
cfg.MaxIdleConnsPerHost = 1024
maxIdleConnsPerHost := hasEnv.Getenv("max_idle_conns_per_host")
if len(maxIdleConnsPerHost) > 0 {
val, err := strconv.Atoi(maxIdleConnsPerHost)
if err != nil {
return nil, fmt.Errorf("invalid value for max_idle_conns_per_host: %s", maxIdleConnsPerHost)
}
cfg.MaxIdleConnsPerHost = val
}
return cfg, nil
}

View File

@ -0,0 +1,22 @@
// 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 types
type ScaleServiceRequest struct {
ServiceName string `json:"serviceName"`
Replicas uint64 `json:"replicas"`
}
// InfoResponse provides information about the underlying provider
type InfoResponse struct {
Provider string `json:"provider"`
Version ProviderVersion `json:"version"`
Orchestration string `json:"orchestration"`
}
// ProviderVersion provides the commit sha and release version number of the underlying provider
type ProviderVersion struct {
SHA string `json:"sha"`
Release string `json:"release"`
}

23
vendor/github.com/openfaas/faas/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
MIT License
Copyright (c) 2016-2018 Alex Ellis
Copyright (c) 2018 OpenFaaS Author(s)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,29 @@
package requests
import "fmt"
import "net/url"
// ForwardRequest for proxying incoming requests
type ForwardRequest struct {
RawPath string
RawQuery string
Method string
}
// NewForwardRequest create a ForwardRequest
func NewForwardRequest(method string, url url.URL) ForwardRequest {
return ForwardRequest{
Method: method,
RawQuery: url.RawQuery,
RawPath: url.Path,
}
}
// ToURL create formatted URL
func (f *ForwardRequest) ToURL(addr string, watchdogPort int) string {
if len(f.RawQuery) > 0 {
return fmt.Sprintf("http://%s:%d%s?%s", addr, watchdogPort, f.RawPath, f.RawQuery)
}
return fmt.Sprintf("http://%s:%d%s", addr, watchdogPort, f.RawPath)
}

View File

@ -0,0 +1,23 @@
// 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 requests
// PrometheusInnerAlertLabel PrometheusInnerAlertLabel
type PrometheusInnerAlertLabel struct {
AlertName string `json:"alertname"`
FunctionName string `json:"function_name"`
}
// PrometheusInnerAlert PrometheusInnerAlert
type PrometheusInnerAlert struct {
Status string `json:"status"`
Labels PrometheusInnerAlertLabel `json:"labels"`
}
// PrometheusAlert as produced by AlertManager
type PrometheusAlert struct {
Status string `json:"status"`
Receiver string `json:"receiver"`
Alerts []PrometheusInnerAlert `json:"alerts"`
}

View File

@ -0,0 +1,18 @@
// 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 requests package provides a client SDK or library for
// the OpenFaaS gateway REST API
package requests
// AsyncReport is the report from a function executed on a queue worker.
type AsyncReport struct {
FunctionName string `json:"name"`
StatusCode int `json:"statusCode"`
TimeTaken float64 `json:"timeTaken"`
}
// DeleteFunctionRequest delete a deployed function
type DeleteFunctionRequest struct {
FunctionName string `json:"functionName"`
}