Description
Why do you need this?
I need to be able to use vendoring with the golang-http template because it is how I get private Go code into my functions.
Expected Behaviour
This should work without error, when using a vendor folder and any other stack.yml flags or build-args required:
faas-cli build
Current Behaviour
Step 29/42 : RUN ${GO} build --ldflags "-s -w" -a -installsuffix cgo -o handler .
---> Running in b9e5d187d314
Setting vendor mode env variables
main.go:18:2: cannot find package "github.com/openfaas/templates-sdk/go-http" in any of:
/usr/local/go/src/github.com/openfaas/templates-sdk/go-http (from $GOROOT)
/go/src/github.com/openfaas/templates-sdk/go-http (from $GOPATH)
The command '/bin/sh -c ${GO} build --ldflags "-s -w" -a -installsuffix cgo -o handler .' returned a non-zero code: 1
[0] < Building go1 done in 5.91s.
[0] Worker done.
Total build time: 5.91s
Errors received during build:
- [go1] received non-zero exit code from build, error: The command '/bin/sh -c ${GO} build --ldflags "-s -w" -a -installsuffix cgo -o handler .' returned a non-zero code: 1
List All Possible Solutions and Workarounds
- Create a new separate template
golang-http-vendoring
that only works with vendoring - Stop maintaining a golang-http template at all, migrate everyone to golang-middleware
- Use interfaces instead of structs, so that the main.go module doesn't have to reference the SDK, which seems to be the source of the problem - full example, and it's a breaking change: https://github.com/alexellis/golang-http-template
- Consider a new direction that looks like AWS Lambda's Go handler - https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html
- Use Go's plugin capability, to build the function and entry point separately, and link them after the fact. Unfortunately this seems to require CGO and breaks portability - plugin: requires CGO_ENABLED=1 golang/go#19569
For 4), the function's handler owns the main() entrypoint instead of the hidden underlying code, and calls a utility method to set up the HTTP server etc.
package main
import (
"fmt"
"context"
"github.com/openfaas/golang-http/entrypoint"
)
type MyEvent struct {
Name string `json:"name"`
}
func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
return fmt.Sprintf("Hello %s!", name.Name ), nil
}
func main() {
entrypoint.Start(HandleRequest)
}
For 3), the code would end up looking like this for a handler:
(this can be compared to the second code sample to see what's different)
package function
import (
"fmt"
"net/http"
gohttp "github.com/alexellis/templates-sdk/go-http"
logrus "github.com/sirupsen/logrus"
)
// Handle a function invocation
func Handle(req gohttp.Request) (gohttp.Response, error) {
var err error
logrus.Info("Value of body: ", string(req.GetBody()))
message := fmt.Sprintf("Body: %s", string(req.GetBody()))
return &gohttp.FunctionResponse{
Body: []byte(message),
StatusCode: http.StatusOK,
}, err
}
What is your preferred solution?
I like 3) and to lessen its impact to existing users, we could consider promoting golang-http into the primary community templates repository and deprecating the one we use here.
Alternatively, we could call it "go-http1.18or
golang-http1.18as a new template, with
golang-http1.19` and so on coming after that.
Steps to Reproduce (for bugs)
faas-cli template store pull golang-http-template
faas-cli new --lang golang-http --prefix alexellis2 withlogrus
Edit withlogrus/handler.go
:
package function
import (
"fmt"
"io"
"net/http"
"github.com/sirupsen/logrus"
)
func Handle(w http.ResponseWriter, r *http.Request) {
var input []byte
if r.Body != nil {
defer r.Body.Close()
body, _ := io.ReadAll(r.Body)
input = body
}
logrus.Debug(fmt.Sprintf("Handle; %q", input))
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("Body: %q", string(input))))
}
Then edit withlogrus.yml
, adding:
build_args:
GO111MODULE: off
GOFLAGS: "-mod=vendor"
Then try a build:
cd golang-http-template
go get
go mod vendor
cd ..
faas-cli build -f withlogrus.yml