From 7fc17fb7a0e3b3ac3c51404a912811303cdae263 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Tue, 15 Jan 2019 13:09:25 +0530 Subject: [PATCH 1/5] Connector sdk example Signed-off-by: Rishabh Gupta --- cmd/tester/.gitignore | 1 + cmd/tester/Dockerfile | 16 ++++++++ cmd/tester/Dockerfile.armhf | 16 ++++++++ cmd/tester/main.go | 2 +- cmd/tester/yaml/docker-compose.yml | 26 +++++++++++++ cmd/tester/yaml/kubernetes/connector-dep.yml | 39 ++++++++++++++++++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 cmd/tester/Dockerfile create mode 100644 cmd/tester/Dockerfile.armhf create mode 100644 cmd/tester/yaml/docker-compose.yml create mode 100644 cmd/tester/yaml/kubernetes/connector-dep.yml diff --git a/cmd/tester/.gitignore b/cmd/tester/.gitignore index 05fb88f..9d62593 100644 --- a/cmd/tester/.gitignore +++ b/cmd/tester/.gitignore @@ -1 +1,2 @@ tester +tester.exe \ No newline at end of file diff --git a/cmd/tester/Dockerfile b/cmd/tester/Dockerfile new file mode 100644 index 0000000..3a2c1a6 --- /dev/null +++ b/cmd/tester/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:1.9.2 as builder +RUN mkdir -p /go/src/github.com/openfaas-incubator/connector +WORKDIR /go/src/github.com/openfaas-incubator/connector + +COPY main.go . + +RUN go get -d -v ./... + +# Stripping via -ldflags "-s -w" +RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-s -w" -installsuffix cgo -o ./connector + +FROM alpine + +COPY --from=builder /go/src/github.com/openfaas-incubator/connector/connector /bin/connector + +CMD ["/bin/connector"] \ No newline at end of file diff --git a/cmd/tester/Dockerfile.armhf b/cmd/tester/Dockerfile.armhf new file mode 100644 index 0000000..3a2c1a6 --- /dev/null +++ b/cmd/tester/Dockerfile.armhf @@ -0,0 +1,16 @@ +FROM golang:1.9.2 as builder +RUN mkdir -p /go/src/github.com/openfaas-incubator/connector +WORKDIR /go/src/github.com/openfaas-incubator/connector + +COPY main.go . + +RUN go get -d -v ./... + +# Stripping via -ldflags "-s -w" +RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-s -w" -installsuffix cgo -o ./connector + +FROM alpine + +COPY --from=builder /go/src/github.com/openfaas-incubator/connector/connector /bin/connector + +CMD ["/bin/connector"] \ No newline at end of file diff --git a/cmd/tester/main.go b/cmd/tester/main.go index 23b7202..bb8b65e 100644 --- a/cmd/tester/main.go +++ b/cmd/tester/main.go @@ -49,4 +49,4 @@ func (ResponseReceiver) Response(res types.InvokerResponse) { } else { log.Printf("tester got result: [%d] %s => %s (%d) bytes", res.Status, res.Topic, res.Function, len(*res.Body)) } -} +} \ No newline at end of file diff --git a/cmd/tester/yaml/docker-compose.yml b/cmd/tester/yaml/docker-compose.yml new file mode 100644 index 0000000..d2bacc2 --- /dev/null +++ b/cmd/tester/yaml/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.2' +services: + connector: + image: 192.168.1.9:5000/connector-sample + hostname: sample-connector + environment: + gateway_url: http://gateway:8080 + topics: "faas-request" + print_response: "true" + basic_auth: "true" + secret_mount_path: "/run/secrets/" + secrets: + - basic-auth-password + - basic-auth-user + networks: + - func_functions + +networks: + func_functions: + external: true + +secrets: + basic-auth-user: + external: true + basic-auth-password: + external: true diff --git a/cmd/tester/yaml/kubernetes/connector-dep.yml b/cmd/tester/yaml/kubernetes/connector-dep.yml new file mode 100644 index 0000000..9614dc4 --- /dev/null +++ b/cmd/tester/yaml/kubernetes/connector-dep.yml @@ -0,0 +1,39 @@ + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: connector + component: sample-connector + name: sample-connector + namespace: openfaas +spec: + replicas: 1 + template: + metadata: + labels: + app: connector + component: sample-connector + spec: + containers: + - name: sample-connector + image: 192.168.1.9:5000/connector-sample + env: + - name: gateway_url + value: "http://gateway.openfaas:8080" + - name: topics + value: "faas-request" + - name: print_response + value: "true" + - name: basic_auth + value: "false" + # - name: secret_mount_path + # value: "/var/secrets/" + # volumeMounts: + # - name: auth + # readOnly: true + # mountPath: "/var/secrets/" + # volumes: + # - name: auth + # secret: + # secretName: basic-auth From ac979d45dcac04a947b7913b6640760413c8fa29 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Tue, 15 Jan 2019 13:36:37 +0530 Subject: [PATCH 2/5] Referencing dockerhub image zeerorg/connector-sample Signed-off-by: Rishabh Gupta --- cmd/tester/yaml/docker-compose.yml | 2 +- cmd/tester/yaml/kubernetes/connector-dep.yml | 22 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/tester/yaml/docker-compose.yml b/cmd/tester/yaml/docker-compose.yml index d2bacc2..7afd1c7 100644 --- a/cmd/tester/yaml/docker-compose.yml +++ b/cmd/tester/yaml/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.2' services: connector: - image: 192.168.1.9:5000/connector-sample + image: zeerorg/connector-sample hostname: sample-connector environment: gateway_url: http://gateway:8080 diff --git a/cmd/tester/yaml/kubernetes/connector-dep.yml b/cmd/tester/yaml/kubernetes/connector-dep.yml index 9614dc4..6bb8513 100644 --- a/cmd/tester/yaml/kubernetes/connector-dep.yml +++ b/cmd/tester/yaml/kubernetes/connector-dep.yml @@ -17,7 +17,7 @@ spec: spec: containers: - name: sample-connector - image: 192.168.1.9:5000/connector-sample + image: zeerorg/connector-sample env: - name: gateway_url value: "http://gateway.openfaas:8080" @@ -27,13 +27,13 @@ spec: value: "true" - name: basic_auth value: "false" - # - name: secret_mount_path - # value: "/var/secrets/" - # volumeMounts: - # - name: auth - # readOnly: true - # mountPath: "/var/secrets/" - # volumes: - # - name: auth - # secret: - # secretName: basic-auth + - name: secret_mount_path + value: "/var/secrets/" + volumeMounts: + - name: auth + readOnly: true + mountPath: "/var/secrets/" + volumes: + - name: auth + secret: + secretName: basic-auth From c8a09b15c1b3d19fe5dbd6c680d68c480f7f8881 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Tue, 15 Jan 2019 13:53:37 +0530 Subject: [PATCH 3/5] Added README for sample connector Signed-off-by: Rishabh Gupta --- cmd/tester/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 cmd/tester/README.md diff --git a/cmd/tester/README.md b/cmd/tester/README.md new file mode 100644 index 0000000..9982fdb --- /dev/null +++ b/cmd/tester/README.md @@ -0,0 +1,18 @@ +# Openfaas Sample Connector + +This folder contains a sample openfaas connector. You can use this as a base for creating your own connectors. +For a more complex example checkout [kafka-connector](https://github.com/openfaas-incubator/kafka-connector) + +## How to Use + +1. Clone this repository: `git clone https://github.com/openfaas-incubator/connector-sdk.git` +2. Go into the directory: `cd ./connector-sdk/cmd/tester/yaml` +3. For openfaas deployed on docker swarm do: `docker stack deploy func -c ./docker-compose.yml` +4. For openfaas deployed on kubernetes do: `kubectl create -f ./kubernetes --namespace openfaas` + +To check if it actually works and triggers a function, deploy any function with annotation `topic=faas-request`. +You can also run this command to deploy a sample function and see `trigger-func` invocation count growing in ui. + +```bash +faas-cli deploy --image=functions/nodeinfo --name=trigger-func --annotation topic=faas-request +``` \ No newline at end of file From 8987d860a5f349db15c0bbfe72df7dc8b52de42a Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Tue, 15 Jan 2019 21:25:36 +0530 Subject: [PATCH 4/5] Added vendor folder and suggested fixes Signed-off-by: Rishabh Gupta --- cmd/tester/Dockerfile | 27 +++-- cmd/tester/Dockerfile.armhf | 20 ++-- cmd/tester/Gopkg.lock | 33 +++++++ cmd/tester/Gopkg.toml | 34 +++++++ cmd/tester/README.md | 8 +- .../openfaas-incubator/connector-sdk/LICENSE | 22 +++++ .../connector-sdk/types/controller.go | 78 +++++++++++++++ .../connector-sdk/types/credentials.go | 29 ++++++ .../types/function_list_builder.go | 69 +++++++++++++ .../connector-sdk/types/invoker.go | 82 ++++++++++++++++ .../connector-sdk/types/make_client.go | 22 +++++ .../connector-sdk/types/topic_map.go | 42 ++++++++ .../github.com/openfaas/faas-provider/LICENSE | 21 ++++ .../openfaas/faas-provider/auth/basic_auth.go | 26 +++++ .../faas-provider/auth/credentials.go | 52 ++++++++++ .../vendor/github.com/openfaas/faas/LICENSE | 23 +++++ .../faas/gateway/requests/forward_request.go | 29 ++++++ .../faas/gateway/requests/prometheus.go | 23 +++++ .../faas/gateway/requests/requests.go | 98 +++++++++++++++++++ cmd/tester/yaml/docker-compose.yml | 4 +- cmd/tester/yaml/kubernetes/connector-dep.yml | 8 +- 21 files changed, 722 insertions(+), 28 deletions(-) create mode 100644 cmd/tester/Gopkg.lock create mode 100644 cmd/tester/Gopkg.toml create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/LICENSE create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/credentials.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/function_list_builder.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/make_client.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/topic_map.go create mode 100644 cmd/tester/vendor/github.com/openfaas/faas-provider/LICENSE create mode 100644 cmd/tester/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go create mode 100644 cmd/tester/vendor/github.com/openfaas/faas-provider/auth/credentials.go create mode 100644 cmd/tester/vendor/github.com/openfaas/faas/LICENSE create mode 100644 cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/forward_request.go create mode 100644 cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/prometheus.go create mode 100644 cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/requests.go diff --git a/cmd/tester/Dockerfile b/cmd/tester/Dockerfile index 3a2c1a6..525a26b 100644 --- a/cmd/tester/Dockerfile +++ b/cmd/tester/Dockerfile @@ -1,16 +1,29 @@ -FROM golang:1.9.2 as builder -RUN mkdir -p /go/src/github.com/openfaas-incubator/connector -WORKDIR /go/src/github.com/openfaas-incubator/connector +FROM golang:1.10.4 as builder +RUN mkdir -p /go/src/github.com/openfaas-incubator/connector-sdk +WORKDIR /go/src/github.com/openfaas-incubator/connector-sdk +COPY vendor vendor COPY main.go . -RUN go get -d -v ./... +# Run a gofmt and exclude all vendored code. +RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*"))" + +RUN go test -v ./... # Stripping via -ldflags "-s -w" RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-s -w" -installsuffix cgo -o ./connector -FROM alpine +FROM alpine:3.8 + +RUN addgroup -S app \ + && adduser -S -g app app + +WORKDIR /home/app + +COPY --from=builder /go/src/github.com/openfaas-incubator/connector-sdk/ . + +RUN chown -R app:app ./ -COPY --from=builder /go/src/github.com/openfaas-incubator/connector/connector /bin/connector +USER app -CMD ["/bin/connector"] \ No newline at end of file +CMD ["./connector"] \ No newline at end of file diff --git a/cmd/tester/Dockerfile.armhf b/cmd/tester/Dockerfile.armhf index 3a2c1a6..42ad4d0 100644 --- a/cmd/tester/Dockerfile.armhf +++ b/cmd/tester/Dockerfile.armhf @@ -1,16 +1,20 @@ -FROM golang:1.9.2 as builder -RUN mkdir -p /go/src/github.com/openfaas-incubator/connector -WORKDIR /go/src/github.com/openfaas-incubator/connector +FROM golang:1.10.4 as builder +RUN mkdir -p /go/src/github.com/openfaas-incubator/connector-sdk +WORKDIR /go/src/github.com/openfaas-incubator/connector-sdk +COPY vendor vendor COPY main.go . -RUN go get -d -v ./... +# Run a gofmt and exclude all vendored code. +RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*"))" + +RUN go test -v ./... # Stripping via -ldflags "-s -w" -RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-s -w" -installsuffix cgo -o ./connector +RUN GOARM=7 CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-s -w" -installsuffix cgo -o ./connector -FROM alpine +FROM alpine:3.8 -COPY --from=builder /go/src/github.com/openfaas-incubator/connector/connector /bin/connector +COPY --from=builder /go/src/github.com/openfaas-incubator/connector-sdk/ . -CMD ["/bin/connector"] \ No newline at end of file +CMD ["./connector"] \ No newline at end of file diff --git a/cmd/tester/Gopkg.lock b/cmd/tester/Gopkg.lock new file mode 100644 index 0000000..543bf49 --- /dev/null +++ b/cmd/tester/Gopkg.lock @@ -0,0 +1,33 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:2a7750103f5ea9a84634dbb554672ce8b11c762281ec1318038cbec14a470241" + name = "github.com/openfaas-incubator/connector-sdk" + packages = ["types"] + pruneopts = "UT" + revision = "2db120a2ec4b544bae7ee306975b70c1dc9adcf4" + version = "0.2.0" + +[[projects]] + digest = "1:3f69624cb4ae8ab815a672f7d169d64786ee027a9d42eefab3c9d4e9debe0750" + name = "github.com/openfaas/faas" + packages = ["gateway/requests"] + pruneopts = "UT" + revision = "a65df4795bc66147c41161c48bfd4c72f60c7434" + version = "0.9.14" + +[[projects]] + digest = "1:deb76da5396c9f641ddea9ca79e31a14bdb09c787cdfda90488768b7539b1fd6" + name = "github.com/openfaas/faas-provider" + packages = ["auth"] + pruneopts = "UT" + revision = "220324e98f5db5aa61f02d1ab13f03e91310796c" + version = "0.8.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = ["github.com/openfaas-incubator/connector-sdk/types"] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/cmd/tester/Gopkg.toml b/cmd/tester/Gopkg.toml new file mode 100644 index 0000000..b3bdd28 --- /dev/null +++ b/cmd/tester/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/openfaas-incubator/connector-sdk" + version = "0.2.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/cmd/tester/README.md b/cmd/tester/README.md index 9982fdb..5b13907 100644 --- a/cmd/tester/README.md +++ b/cmd/tester/README.md @@ -1,14 +1,14 @@ -# Openfaas Sample Connector +# OpenFaas Sample Connector -This folder contains a sample openfaas connector. You can use this as a base for creating your own connectors. +This folder contains a sample OpenFaas connector. You can use this as a base for creating your own connectors. For a more complex example checkout [kafka-connector](https://github.com/openfaas-incubator/kafka-connector) ## How to Use 1. Clone this repository: `git clone https://github.com/openfaas-incubator/connector-sdk.git` 2. Go into the directory: `cd ./connector-sdk/cmd/tester/yaml` -3. For openfaas deployed on docker swarm do: `docker stack deploy func -c ./docker-compose.yml` -4. For openfaas deployed on kubernetes do: `kubectl create -f ./kubernetes --namespace openfaas` +3. For OpenFaas deployed on Docker Swarm do: `docker stack deploy func -c ./docker-compose.yml` +4. For OpenFaas deployed on kubernetes do: `kubectl create -f ./kubernetes --namespace openfaas` To check if it actually works and triggers a function, deploy any function with annotation `topic=faas-request`. You can also run this command to deploy a sample function and see `trigger-func` invocation count growing in ui. diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/LICENSE b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/LICENSE new file mode 100644 index 0000000..08c5fb7 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2017-2018 Alex Ellis +Copyright (c) 2017-2018 OpenFaaS Project + +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. diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go new file mode 100644 index 0000000..4b6fa96 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go @@ -0,0 +1,78 @@ +package types + +import ( + "log" + "time" + + "github.com/openfaas/faas-provider/auth" +) + +// ControllerConfig configures a connector SDK controller +type ControllerConfig struct { + UpstreamTimeout time.Duration + GatewayURL string + PrintResponse bool + RebuildInterval time.Duration +} + +// Controller for the connector SDK +type Controller struct { + Config *ControllerConfig + Invoker *Invoker + TopicMap *TopicMap + Credentials *auth.BasicAuthCredentials +} + +// NewController create a new connector SDK controller +func NewController(credentials *auth.BasicAuthCredentials, config *ControllerConfig) *Controller { + + invoker := Invoker{ + PrintResponse: config.PrintResponse, + Client: MakeClient(config.UpstreamTimeout), + GatewayURL: config.GatewayURL, + } + topicMap := NewTopicMap() + + return &Controller{ + Config: config, + Invoker: &invoker, + TopicMap: &topicMap, + Credentials: credentials, + } +} + +// Invoke attempts to invoke any functions which match the +// topic the incoming message was published on. +func (c *Controller) Invoke(topic string, message *[]byte) { + c.Invoker.Invoke(c.TopicMap, topic, message) +} + +// BeginMapBuilder begins to build a map of function->topic by +// querying the API gateway. +func (c *Controller) BeginMapBuilder() { + + lookupBuilder := FunctionLookupBuilder{ + GatewayURL: c.Config.GatewayURL, + Client: MakeClient(c.Config.UpstreamTimeout), + Credentials: c.Credentials, + } + + ticker := time.NewTicker(c.Config.RebuildInterval) + go synchronizeLookups(ticker, &lookupBuilder, c.TopicMap) +} + +func synchronizeLookups(ticker *time.Ticker, + lookupBuilder *FunctionLookupBuilder, + topicMap *TopicMap) { + + for { + <-ticker.C + lookups, err := lookupBuilder.Build() + if err != nil { + log.Fatalln(err) + } + + log.Println("Syncing topic map") + topicMap.Sync(&lookups) + } +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/credentials.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/credentials.go new file mode 100644 index 0000000..bf4684d --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/credentials.go @@ -0,0 +1,29 @@ +package types + +import ( + "os" + + "github.com/openfaas/faas-provider/auth" +) + +func GetCredentials() *auth.BasicAuthCredentials { + var credentials *auth.BasicAuthCredentials + + if val, ok := os.LookupEnv("basic_auth"); ok && len(val) > 0 { + if val == "true" || val == "1" { + + reader := auth.ReadBasicAuthFromDisk{} + + if val, ok := os.LookupEnv("secret_mount_path"); ok && len(val) > 0 { + reader.SecretMountPath = os.Getenv("secret_mount_path") + } + + res, err := reader.Read() + if err != nil { + panic(err) + } + credentials = res + } + } + return credentials +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/function_list_builder.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/function_list_builder.go new file mode 100644 index 0000000..0f4ffc1 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/function_list_builder.go @@ -0,0 +1,69 @@ +// Copyright (c) OpenFaaS Project 2018. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +package types + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/openfaas/faas-provider/auth" + "github.com/openfaas/faas/gateway/requests" +) + +// FunctionLookupBuilder builds a list of OpenFaaS functions +type FunctionLookupBuilder struct { + GatewayURL string + Client *http.Client + Credentials *auth.BasicAuthCredentials +} + +// Build compiles a map of topic names and functions that have +// advertised to receive messages on said topic +func (s *FunctionLookupBuilder) Build() (map[string][]string, error) { + var err error + serviceMap := make(map[string][]string) + + req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/system/functions", s.GatewayURL), nil) + + if s.Credentials != nil { + req.SetBasicAuth(s.Credentials.User, s.Credentials.Password) + } + + res, reqErr := s.Client.Do(req) + + if reqErr != nil { + return serviceMap, reqErr + } + + if res.Body != nil { + defer res.Body.Close() + } + + bytesOut, _ := ioutil.ReadAll(res.Body) + + functions := []requests.Function{} + marshalErr := json.Unmarshal(bytesOut, &functions) + + if marshalErr != nil { + return serviceMap, marshalErr + } + + for _, function := range functions { + if function.Annotations != nil { + annotations := *function.Annotations + + if topic, pass := annotations["topic"]; pass { + + if serviceMap[topic] == nil { + serviceMap[topic] = []string{} + } + serviceMap[topic] = append(serviceMap[topic], function.Name) + } + } + } + + return serviceMap, err +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go new file mode 100644 index 0000000..1170972 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go @@ -0,0 +1,82 @@ +package types + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" +) + +type Invoker struct { + PrintResponse bool + Client *http.Client + GatewayURL string +} + +func (i *Invoker) Invoke(topicMap *TopicMap, topic string, message *[]byte) { + if len(*message) > 0 { + + matchedFunctions := topicMap.Match(topic) + for _, matchedFunction := range matchedFunctions { + + log.Printf("Invoke function: %s", matchedFunction) + + gwURL := fmt.Sprintf("%s/function/%s", i.GatewayURL, matchedFunction) + reader := bytes.NewReader(*message) + + body, statusCode, doErr := invokefunction(i.Client, gwURL, reader) + + if doErr != nil { + log.Printf("Unable to invoke from %s, error: %s\n", matchedFunction, doErr) + return + } + + printBody := false + stringOutput := "" + + if body != nil && i.PrintResponse { + stringOutput = string(*body) + printBody = true + } + + if printBody { + log.Printf("Response [%d] from %s %s", statusCode, matchedFunction, stringOutput) + + } else { + log.Printf("Response [%d] from %s", statusCode, matchedFunction) + } + } + } +} + +func invokefunction(c *http.Client, gwURL string, reader io.Reader) (*[]byte, int, error) { + + httpReq, _ := http.NewRequest(http.MethodPost, gwURL, reader) + + if httpReq.Body != nil { + defer httpReq.Body.Close() + } + + var body *[]byte + + res, doErr := c.Do(httpReq) + if doErr != nil { + return nil, http.StatusServiceUnavailable, doErr + } + + if res.Body != nil { + defer res.Body.Close() + + bytesOut, readErr := ioutil.ReadAll(res.Body) + if readErr != nil { + log.Printf("Error reading body") + return nil, http.StatusServiceUnavailable, doErr + + } + body = &bytesOut + } + + return body, res.StatusCode, doErr +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/make_client.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/make_client.go new file mode 100644 index 0000000..a380f80 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/make_client.go @@ -0,0 +1,22 @@ +package types + +import ( + "net" + "net/http" + "time" +) + +func MakeClient(timeout time.Duration) *http.Client { + return &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: timeout, + KeepAlive: 10 * time.Second, + }).DialContext, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 120 * time.Millisecond, + }, + } +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/topic_map.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/topic_map.go new file mode 100644 index 0000000..684d928 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/topic_map.go @@ -0,0 +1,42 @@ +// Copyright (c) OpenFaaS Project 2018. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +package types + +import "sync" + +func NewTopicMap() TopicMap { + lookup := make(map[string][]string) + return TopicMap{ + lookup: &lookup, + lock: sync.Mutex{}, + } +} + +type TopicMap struct { + lookup *map[string][]string + lock sync.Mutex +} + +func (t *TopicMap) Match(topicName string) []string { + t.lock.Lock() + defer t.lock.Unlock() + + var values []string + + for key, val := range *t.lookup { + if key == topicName { + values = val + break + } + } + + return values +} + +func (t *TopicMap) Sync(updated *map[string][]string) { + t.lock.Lock() + defer t.lock.Unlock() + + t.lookup = updated +} diff --git a/cmd/tester/vendor/github.com/openfaas/faas-provider/LICENSE b/cmd/tester/vendor/github.com/openfaas/faas-provider/LICENSE new file mode 100644 index 0000000..e547e74 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas-provider/LICENSE @@ -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. diff --git a/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go b/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go new file mode 100644 index 0000000..3fd7d75 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go @@ -0,0 +1,26 @@ +// 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 ( + "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() + w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) + + if !ok || !(credentials.Password == password && user == credentials.User) { + + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("invalid credentials")) + return + } + + next.ServeHTTP(w, r) + } +} diff --git a/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/credentials.go b/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/credentials.go new file mode 100644 index 0000000..4f2ca34 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas-provider/auth/credentials.go @@ -0,0 +1,52 @@ +// 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() (error, *BasicAuthCredentials) +} + +type ReadBasicAuthFromDisk struct { + SecretMountPath 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") + } + + userPath := path.Join(r.SecretMountPath, "basic-auth-user") + 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") + 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 +} diff --git a/cmd/tester/vendor/github.com/openfaas/faas/LICENSE b/cmd/tester/vendor/github.com/openfaas/faas/LICENSE new file mode 100644 index 0000000..fc538a1 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas/LICENSE @@ -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. + diff --git a/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/forward_request.go b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/forward_request.go new file mode 100644 index 0000000..adc573c --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/forward_request.go @@ -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) + +} diff --git a/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/prometheus.go b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/prometheus.go new file mode 100644 index 0000000..1bb41f7 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/prometheus.go @@ -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"` +} diff --git a/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/requests.go b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/requests.go new file mode 100644 index 0000000..5c8f174 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas/faas/gateway/requests/requests.go @@ -0,0 +1,98 @@ +// 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 + +// CreateFunctionRequest create a function in the swarm. +type CreateFunctionRequest struct { + + // Service corresponds to a Docker 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"` +} + +// FunctionResources Memory and CPU +type FunctionResources struct { + Memory string `json:"memory"` + CPU string `json:"cpu"` +} + +// Function exported for system/functions endpoint +type Function struct { + Name string `json:"name"` + Image string `json:"image"` + InvocationCount float64 `json:"invocationCount"` // TODO: shouldn't this be int64? + Replicas uint64 `json:"replicas"` + EnvProcess string `json:"envProcess"` + + // AvailableReplicas is the count of replicas ready to receive invocations as reported by the back-end + AvailableReplicas uint64 `json:"availableReplicas"` + + // 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"` +} + +// 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"` +} + +// Secret for underlying orchestrator +type Secret struct { + Name string `json:"name"` + Value string `json:"value,omitempty"` +} diff --git a/cmd/tester/yaml/docker-compose.yml b/cmd/tester/yaml/docker-compose.yml index 7afd1c7..4ab6a50 100644 --- a/cmd/tester/yaml/docker-compose.yml +++ b/cmd/tester/yaml/docker-compose.yml @@ -1,12 +1,10 @@ version: '3.2' services: connector: - image: zeerorg/connector-sample + image: zeerorg/connector-sample:1.0 hostname: sample-connector environment: gateway_url: http://gateway:8080 - topics: "faas-request" - print_response: "true" basic_auth: "true" secret_mount_path: "/run/secrets/" secrets: diff --git a/cmd/tester/yaml/kubernetes/connector-dep.yml b/cmd/tester/yaml/kubernetes/connector-dep.yml index 6bb8513..adaf450 100644 --- a/cmd/tester/yaml/kubernetes/connector-dep.yml +++ b/cmd/tester/yaml/kubernetes/connector-dep.yml @@ -17,16 +17,12 @@ spec: spec: containers: - name: sample-connector - image: zeerorg/connector-sample + image: zeerorg/connector-sample:1.0 env: - name: gateway_url value: "http://gateway.openfaas:8080" - - name: topics - value: "faas-request" - - name: print_response - value: "true" - name: basic_auth - value: "false" + value: "true" - name: secret_mount_path value: "/var/secrets/" volumeMounts: From 52e384f1d7c9155a21b3511e89dfea3111f095b4 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Mon, 28 Jan 2019 14:13:46 +0530 Subject: [PATCH 5/5] Rebase with upstream. Added topic environment variable. Signed-off-by: Rishabh Gupta --- cmd/tester/Gopkg.lock | 14 +- cmd/tester/Gopkg.toml | 2 +- cmd/tester/README.md | 2 +- cmd/tester/main.go | 42 ++- .../connector-sdk/types/controller.go | 82 ++++- .../connector-sdk/types/invoker.go | 75 +++-- .../connector-sdk/types/response_printer.go | 24 ++ .../types/response_subscriber.go | 12 + .../vendor/github.com/pkg/errors/.gitignore | 24 ++ .../vendor/github.com/pkg/errors/.travis.yml | 15 + .../vendor/github.com/pkg/errors/LICENSE | 23 ++ .../vendor/github.com/pkg/errors/README.md | 52 ++++ .../vendor/github.com/pkg/errors/appveyor.yml | 32 ++ .../vendor/github.com/pkg/errors/errors.go | 282 ++++++++++++++++++ .../vendor/github.com/pkg/errors/stack.go | 147 +++++++++ cmd/tester/yaml/docker-compose.yml | 3 +- cmd/tester/yaml/kubernetes/connector-dep.yml | 4 +- 17 files changed, 781 insertions(+), 54 deletions(-) create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_printer.go create mode 100644 cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_subscriber.go create mode 100644 cmd/tester/vendor/github.com/pkg/errors/.gitignore create mode 100644 cmd/tester/vendor/github.com/pkg/errors/.travis.yml create mode 100644 cmd/tester/vendor/github.com/pkg/errors/LICENSE create mode 100644 cmd/tester/vendor/github.com/pkg/errors/README.md create mode 100644 cmd/tester/vendor/github.com/pkg/errors/appveyor.yml create mode 100644 cmd/tester/vendor/github.com/pkg/errors/errors.go create mode 100644 cmd/tester/vendor/github.com/pkg/errors/stack.go diff --git a/cmd/tester/Gopkg.lock b/cmd/tester/Gopkg.lock index 543bf49..72e20df 100644 --- a/cmd/tester/Gopkg.lock +++ b/cmd/tester/Gopkg.lock @@ -2,12 +2,12 @@ [[projects]] - digest = "1:2a7750103f5ea9a84634dbb554672ce8b11c762281ec1318038cbec14a470241" + digest = "1:82fd6a659744e68edc4de79a304f4e4c1262d6c83d38e30e25b764fc19746883" name = "github.com/openfaas-incubator/connector-sdk" packages = ["types"] pruneopts = "UT" - revision = "2db120a2ec4b544bae7ee306975b70c1dc9adcf4" - version = "0.2.0" + revision = "d722c9f72ad06903f416d1bc89878ba5a824b227" + version = "0.3.1" [[projects]] digest = "1:3f69624cb4ae8ab815a672f7d169d64786ee027a9d42eefab3c9d4e9debe0750" @@ -25,6 +25,14 @@ revision = "220324e98f5db5aa61f02d1ab13f03e91310796c" version = "0.8.1" +[[projects]] + digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "UT" + revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" + version = "v0.8.1" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 diff --git a/cmd/tester/Gopkg.toml b/cmd/tester/Gopkg.toml index b3bdd28..3aa056f 100644 --- a/cmd/tester/Gopkg.toml +++ b/cmd/tester/Gopkg.toml @@ -27,7 +27,7 @@ [[constraint]] name = "github.com/openfaas-incubator/connector-sdk" - version = "0.2.0" + version = "0.3.1" [prune] go-tests = true diff --git a/cmd/tester/README.md b/cmd/tester/README.md index 5b13907..e6f8050 100644 --- a/cmd/tester/README.md +++ b/cmd/tester/README.md @@ -14,5 +14,5 @@ To check if it actually works and triggers a function, deploy any function with You can also run this command to deploy a sample function and see `trigger-func` invocation count growing in ui. ```bash -faas-cli deploy --image=functions/nodeinfo --name=trigger-func --annotation topic=faas-request +faas-cli deploy --image=functions/nodeinfo --name=trigger-func --annotation topic=vm.powered.on ``` \ No newline at end of file diff --git a/cmd/tester/main.go b/cmd/tester/main.go index bb8b65e..b319cdc 100644 --- a/cmd/tester/main.go +++ b/cmd/tester/main.go @@ -5,7 +5,9 @@ package main import ( + "errors" "log" + "os" "time" "github.com/openfaas-incubator/connector-sdk/types" @@ -13,11 +15,9 @@ import ( func main() { creds := types.GetCredentials() - config := &types.ControllerConfig{ - RebuildInterval: time.Millisecond * 1000, - GatewayURL: "http://127.0.0.1:8080", - PrintResponse: true, - PrintResponseBody: true, + config, err := getControllerConfig() + if err != nil { + panic(err) } controller := types.NewController(creds, config) @@ -27,11 +27,16 @@ func main() { controller.BeginMapBuilder() + topic, err := getTopic() + if err != nil { + panic(err) + } + // Simulate events emitting from queue/pub-sub for { time.Sleep(2 * time.Second) data := []byte("test " + time.Now().String()) - controller.Invoke("vm.powered.on", &data) + controller.Invoke(topic, &data) } } @@ -49,4 +54,27 @@ func (ResponseReceiver) Response(res types.InvokerResponse) { } else { log.Printf("tester got result: [%d] %s => %s (%d) bytes", res.Status, res.Topic, res.Function, len(*res.Body)) } -} \ No newline at end of file +} + +func getControllerConfig() (*types.ControllerConfig, error) { + gatewayURL, ok := os.LookupEnv("gateway_url") + if !ok { + return nil, errors.New("Gateway URL not set") + } + + return &types.ControllerConfig{ + RebuildInterval: time.Millisecond * 1000, + GatewayURL: gatewayURL, + PrintResponse: true, + PrintResponseBody: true, + }, nil +} + +func getTopic() (string, error) { + topic, ok := os.LookupEnv("topic") + if !ok { + return "", errors.New("topic not provided") + } + + return topic, nil +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go index 4b6fa96..4bd8533 100644 --- a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/controller.go @@ -2,6 +2,7 @@ package types import ( "log" + "sync" "time" "github.com/openfaas/faas-provider/auth" @@ -9,36 +10,93 @@ import ( // ControllerConfig configures a connector SDK controller type ControllerConfig struct { + // UpstreamTimeout controls maximum timeout invoking a function via the gateway UpstreamTimeout time.Duration - GatewayURL string - PrintResponse bool + + // GatewayURL is the remote OpenFaaS gateway + GatewayURL string + + // PrintResponse if true prints the function responses + PrintResponse bool + + // PrintResponseBody if true prints the function response body to stdout + PrintResponseBody bool + + // RebuildInterval the interval at which the topic map is rebuilt RebuildInterval time.Duration } // Controller for the connector SDK type Controller struct { - Config *ControllerConfig - Invoker *Invoker - TopicMap *TopicMap + // Config for the Controller + Config *ControllerConfig + + // Invoker to invoke functions via HTTP(s) + Invoker *Invoker + + // Map of which functions subscribe to which topics + TopicMap *TopicMap + + // Credentials to access gateway Credentials *auth.BasicAuthCredentials + + // Subscribers which can receive messages from invocations. + // See note on ResponseSubscriber interface about blocking/long-running + // operations + Subscribers []ResponseSubscriber + + // Lock used for synchronizing subscribers + Lock *sync.RWMutex } // NewController create a new connector SDK controller func NewController(credentials *auth.BasicAuthCredentials, config *ControllerConfig) *Controller { - invoker := Invoker{ - PrintResponse: config.PrintResponse, - Client: MakeClient(config.UpstreamTimeout), - GatewayURL: config.GatewayURL, - } + invoker := NewInvoker(config.GatewayURL, + MakeClient(config.UpstreamTimeout), + config.PrintResponse) + + subs := []ResponseSubscriber{} + topicMap := NewTopicMap() - return &Controller{ + controller := Controller{ Config: config, - Invoker: &invoker, + Invoker: invoker, TopicMap: &topicMap, Credentials: credentials, + Subscribers: subs, + Lock: &sync.RWMutex{}, } + + if config.PrintResponse { + // printer := &{} + controller.Subscribe(&ResponsePrinter{config.PrintResponseBody}) + } + + go func(ch *chan InvokerResponse, controller *Controller) { + for { + res := <-*ch + + controller.Lock.RLock() + for _, sub := range controller.Subscribers { + sub.Response(res) + } + controller.Lock.RUnlock() + } + }(&invoker.Responses, &controller) + + return &controller +} + +// Subscribe adds a ResponseSubscriber to the list of subscribers +// which receive messages upon function invocation or error +// Note: it is not possible to Unsubscribe at this point using +// the API of the Controller +func (c *Controller) Subscribe(subscriber ResponseSubscriber) { + c.Lock.Lock() + defer c.Lock.Unlock() + c.Subscribers = append(c.Subscribers, subscriber) } // Invoke attempts to invoke any functions which match the diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go index 1170972..135f625 100644 --- a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/invoker.go @@ -7,51 +7,70 @@ import ( "io/ioutil" "log" "net/http" + + "github.com/pkg/errors" ) type Invoker struct { PrintResponse bool Client *http.Client GatewayURL string + Responses chan InvokerResponse } -func (i *Invoker) Invoke(topicMap *TopicMap, topic string, message *[]byte) { - if len(*message) > 0 { - - matchedFunctions := topicMap.Match(topic) - for _, matchedFunction := range matchedFunctions { +type InvokerResponse struct { + Body *[]byte + Header *http.Header + Status int + Error error + Topic string + Function string +} - log.Printf("Invoke function: %s", matchedFunction) +func NewInvoker(gatewayURL string, client *http.Client, printResponse bool) *Invoker { + return &Invoker{ + PrintResponse: printResponse, + Client: client, + GatewayURL: gatewayURL, + Responses: make(chan InvokerResponse), + } +} - gwURL := fmt.Sprintf("%s/function/%s", i.GatewayURL, matchedFunction) - reader := bytes.NewReader(*message) +// Invoke triggers a function by accessing the API Gateway +func (i *Invoker) Invoke(topicMap *TopicMap, topic string, message *[]byte) { + if len(*message) == 0 { + i.Responses <- InvokerResponse{ + Error: fmt.Errorf("no message to send"), + } + } - body, statusCode, doErr := invokefunction(i.Client, gwURL, reader) + matchedFunctions := topicMap.Match(topic) + for _, matchedFunction := range matchedFunctions { + log.Printf("Invoke function: %s", matchedFunction) - if doErr != nil { - log.Printf("Unable to invoke from %s, error: %s\n", matchedFunction, doErr) - return - } + gwURL := fmt.Sprintf("%s/function/%s", i.GatewayURL, matchedFunction) + reader := bytes.NewReader(*message) - printBody := false - stringOutput := "" + body, statusCode, header, doErr := invokefunction(i.Client, gwURL, reader) - if body != nil && i.PrintResponse { - stringOutput = string(*body) - printBody = true + if doErr != nil { + i.Responses <- InvokerResponse{ + Error: errors.Wrap(doErr, fmt.Sprintf("unable to invoke %s", matchedFunction)), } + continue + } - if printBody { - log.Printf("Response [%d] from %s %s", statusCode, matchedFunction, stringOutput) - - } else { - log.Printf("Response [%d] from %s", statusCode, matchedFunction) - } + i.Responses <- InvokerResponse{ + Body: body, + Status: statusCode, + Header: header, + Function: matchedFunction, + Topic: topic, } } } -func invokefunction(c *http.Client, gwURL string, reader io.Reader) (*[]byte, int, error) { +func invokefunction(c *http.Client, gwURL string, reader io.Reader) (*[]byte, int, *http.Header, error) { httpReq, _ := http.NewRequest(http.MethodPost, gwURL, reader) @@ -63,7 +82,7 @@ func invokefunction(c *http.Client, gwURL string, reader io.Reader) (*[]byte, in res, doErr := c.Do(httpReq) if doErr != nil { - return nil, http.StatusServiceUnavailable, doErr + return nil, http.StatusServiceUnavailable, nil, doErr } if res.Body != nil { @@ -72,11 +91,11 @@ func invokefunction(c *http.Client, gwURL string, reader io.Reader) (*[]byte, in bytesOut, readErr := ioutil.ReadAll(res.Body) if readErr != nil { log.Printf("Error reading body") - return nil, http.StatusServiceUnavailable, doErr + return nil, http.StatusServiceUnavailable, nil, doErr } body = &bytesOut } - return body, res.StatusCode, doErr + return body, res.StatusCode, &res.Header, doErr } diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_printer.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_printer.go new file mode 100644 index 0000000..2889ad6 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_printer.go @@ -0,0 +1,24 @@ +package types + +import ( + "fmt" + "log" +) + +// ResponsePrinter prints function results +type ResponsePrinter struct { + PrintResponseBody bool +} + +// Response is triggered by the controller when a message is +// received from the function invocation +func (rp *ResponsePrinter) Response(res InvokerResponse) { + if res.Error != nil { + log.Printf("connector-sdk got error: %s", res.Error.Error()) + } else { + log.Printf("connector-sdk got result: [%d] %s => %s (%d) bytes", res.Status, res.Topic, res.Function, len(*res.Body)) + if rp.PrintResponseBody { + fmt.Printf("[%d] %s => %s\n%q", res.Status, res.Topic, res.Function, string(*res.Body)) + } + } +} diff --git a/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_subscriber.go b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_subscriber.go new file mode 100644 index 0000000..c313701 --- /dev/null +++ b/cmd/tester/vendor/github.com/openfaas-incubator/connector-sdk/types/response_subscriber.go @@ -0,0 +1,12 @@ +package types + +// ResponseSubscriber enables connector or another client in connector +// to receive results from the function invocation. +// Note: when implementing this interface, you must not perform any +// costly or high-latency operations, or should off-load them to another +// go-routine to prevent blocking. +type ResponseSubscriber interface { + // Response is triggered by the controller when a message is + // received from the function invocation + Response(InvokerResponse) +} diff --git a/cmd/tester/vendor/github.com/pkg/errors/.gitignore b/cmd/tester/vendor/github.com/pkg/errors/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/cmd/tester/vendor/github.com/pkg/errors/.travis.yml b/cmd/tester/vendor/github.com/pkg/errors/.travis.yml new file mode 100644 index 0000000..d4b9266 --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/.travis.yml @@ -0,0 +1,15 @@ +language: go +go_import_path: github.com/pkg/errors +go: + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x + - tip + +script: + - go test -v ./... diff --git a/cmd/tester/vendor/github.com/pkg/errors/LICENSE b/cmd/tester/vendor/github.com/pkg/errors/LICENSE new file mode 100644 index 0000000..835ba3e --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmd/tester/vendor/github.com/pkg/errors/README.md b/cmd/tester/vendor/github.com/pkg/errors/README.md new file mode 100644 index 0000000..6483ba2 --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/README.md @@ -0,0 +1,52 @@ +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) + +Package errors provides simple error handling primitives. + +`go get github.com/pkg/errors` + +The traditional error handling idiom in Go is roughly akin to +```go +if err != nil { + return err +} +``` +which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. + +## Adding context to an error + +The errors.Wrap function returns a new error that adds context to the original error. For example +```go +_, err := ioutil.ReadAll(r) +if err != nil { + return errors.Wrap(err, "read failed") +} +``` +## Retrieving the cause of an error + +Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. +```go +type causer interface { + Cause() error +} +``` +`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: +```go +switch err := errors.Cause(err).(type) { +case *MyError: + // handle specifically +default: + // unknown error +} +``` + +[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). + +## Contributing + +We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. + +Before proposing a change, please discuss your change by raising an issue. + +## License + +BSD-2-Clause diff --git a/cmd/tester/vendor/github.com/pkg/errors/appveyor.yml b/cmd/tester/vendor/github.com/pkg/errors/appveyor.yml new file mode 100644 index 0000000..a932ead --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/appveyor.yml @@ -0,0 +1,32 @@ +version: build-{build}.{branch} + +clone_folder: C:\gopath\src\github.com\pkg\errors +shallow_clone: true # for startup speed + +environment: + GOPATH: C:\gopath + +platform: + - x64 + +# http://www.appveyor.com/docs/installed-software +install: + # some helpful output for debugging builds + - go version + - go env + # pre-installed MinGW at C:\MinGW is 32bit only + # but MSYS2 at C:\msys64 has mingw64 + - set PATH=C:\msys64\mingw64\bin;%PATH% + - gcc --version + - g++ --version + +build_script: + - go install -v ./... + +test_script: + - set PATH=C:\gopath\bin;%PATH% + - go test -v ./... + +#artifacts: +# - path: '%GOPATH%\bin\*.exe' +deploy: off diff --git a/cmd/tester/vendor/github.com/pkg/errors/errors.go b/cmd/tester/vendor/github.com/pkg/errors/errors.go new file mode 100644 index 0000000..7421f32 --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/errors.go @@ -0,0 +1,282 @@ +// Package errors provides simple error handling primitives. +// +// The traditional error handling idiom in Go is roughly akin to +// +// if err != nil { +// return err +// } +// +// which when applied recursively up the call stack results in error reports +// without context or debugging information. The errors package allows +// programmers to add context to the failure path in their code in a way +// that does not destroy the original value of the error. +// +// Adding context to an error +// +// The errors.Wrap function returns a new error that adds context to the +// original error by recording a stack trace at the point Wrap is called, +// together with the supplied message. For example +// +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } +// +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. +// +// Retrieving the cause of an error +// +// Using errors.Wrap constructs a stack of errors, adding context to the +// preceding error. Depending on the nature of the error it may be necessary +// to reverse the operation of errors.Wrap to retrieve the original error +// for inspection. Any error value which implements this interface +// +// type causer interface { +// Cause() error +// } +// +// can be inspected by errors.Cause. errors.Cause will recursively retrieve +// the topmost error that does not implement causer, which is assumed to be +// the original cause. For example: +// +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } +// +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// Formatted printing of errors +// +// All error values returned from this package implement fmt.Formatter and can +// be formatted by the fmt package. The following verbs are supported: +// +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. +// +// Retrieving the stack trace of an error or wrapper +// +// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are +// invoked. This information can be retrieved with the following interface: +// +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } +// +// The returned errors.StackTrace type is defined as +// +// type StackTrace []Frame +// +// The Frame type represents a call site in the stack trace. Frame supports +// the fmt.Formatter interface that can be used for printing information about +// the stack trace of this error. For example: +// +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d", f) +// } +// } +// +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// See the documentation for Frame.Format for more details. +package errors + +import ( + "fmt" + "io" +) + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &fundamental{ + msg: message, + stack: callers(), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, + callers(), + } +} + +type withStack struct { + error + *stack +} + +func (w *withStack) Cause() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) + } +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} diff --git a/cmd/tester/vendor/github.com/pkg/errors/stack.go b/cmd/tester/vendor/github.com/pkg/errors/stack.go new file mode 100644 index 0000000..2874a04 --- /dev/null +++ b/cmd/tester/vendor/github.com/pkg/errors/stack.go @@ -0,0 +1,147 @@ +package errors + +import ( + "fmt" + "io" + "path" + "runtime" + "strings" +) + +// Frame represents a program counter inside a stack frame. +type Frame uintptr + +// pc returns the program counter for this frame; +// multiple frames may have the same PC value. +func (f Frame) pc() uintptr { return uintptr(f) - 1 } + +// file returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) file() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + file, _ := fn.FileLine(f.pc()) + return file +} + +// line returns the line number of source code of the +// function for this Frame's pc. +func (f Frame) line() int { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return 0 + } + _, line := fn.FileLine(f.pc()) + return line +} + +// Format formats the frame according to the fmt.Formatter interface. +// +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d +func (f Frame) Format(s fmt.State, verb rune) { + switch verb { + case 's': + switch { + case s.Flag('+'): + pc := f.pc() + fn := runtime.FuncForPC(pc) + if fn == nil { + io.WriteString(s, "unknown") + } else { + file, _ := fn.FileLine(pc) + fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) + } + default: + io.WriteString(s, path.Base(f.file())) + } + case 'd': + fmt.Fprintf(s, "%d", f.line()) + case 'n': + name := runtime.FuncForPC(f.pc()).Name() + io.WriteString(s, funcname(name)) + case 'v': + f.Format(s, 's') + io.WriteString(s, ":") + f.Format(s, 'd') + } +} + +// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). +type StackTrace []Frame + +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. +func (st StackTrace) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case s.Flag('+'): + for _, f := range st { + fmt.Fprintf(s, "\n%+v", f) + } + case s.Flag('#'): + fmt.Fprintf(s, "%#v", []Frame(st)) + default: + fmt.Fprintf(s, "%v", []Frame(st)) + } + case 's': + fmt.Fprintf(s, "%s", []Frame(st)) + } +} + +// stack represents a stack of program counters. +type stack []uintptr + +func (s *stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + +func (s *stack) StackTrace() StackTrace { + f := make([]Frame, len(*s)) + for i := 0; i < len(f); i++ { + f[i] = Frame((*s)[i]) + } + return f +} + +func callers() *stack { + const depth = 32 + var pcs [depth]uintptr + n := runtime.Callers(3, pcs[:]) + var st stack = pcs[0:n] + return &st +} + +// funcname removes the path prefix component of a function's name reported by func.Name(). +func funcname(name string) string { + i := strings.LastIndex(name, "/") + name = name[i+1:] + i = strings.Index(name, ".") + return name[i+1:] +} diff --git a/cmd/tester/yaml/docker-compose.yml b/cmd/tester/yaml/docker-compose.yml index 4ab6a50..27e1344 100644 --- a/cmd/tester/yaml/docker-compose.yml +++ b/cmd/tester/yaml/docker-compose.yml @@ -4,9 +4,10 @@ services: image: zeerorg/connector-sample:1.0 hostname: sample-connector environment: - gateway_url: http://gateway:8080 basic_auth: "true" secret_mount_path: "/run/secrets/" + gateway_url: "http://gateway:8080/" + topic: "faas-request" secrets: - basic-auth-password - basic-auth-user diff --git a/cmd/tester/yaml/kubernetes/connector-dep.yml b/cmd/tester/yaml/kubernetes/connector-dep.yml index adaf450..7665407 100644 --- a/cmd/tester/yaml/kubernetes/connector-dep.yml +++ b/cmd/tester/yaml/kubernetes/connector-dep.yml @@ -20,7 +20,9 @@ spec: image: zeerorg/connector-sample:1.0 env: - name: gateway_url - value: "http://gateway.openfaas:8080" + value: "http://gateway.openfaas:8080/" + - name: topic + value: "faas-request" - name: basic_auth value: "true" - name: secret_mount_path