Skip to content

Unable to use vendoring with golang-http #78

Closed
@alexellis

Description

@alexellis

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

  1. Create a new separate template golang-http-vendoring that only works with vendoring
  2. Stop maintaining a golang-http template at all, migrate everyone to golang-middleware
  3. 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
  4. 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
  5. 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.18orgolang-http1.18as a new template, withgolang-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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions