From 62fa9bad6444ce6f1b03170bc9b81d5d788e5f5e Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Fri, 24 Jan 2020 11:03:27 +0000 Subject: [PATCH 1/3] Workaround for #33 - go sub-modules Fixes: #33 Go sub-modules do not work with this template, because the of limitations on how local imports and the "replace" word works in Go modules. You can only use "replace" in the root-level module i.e. "main.go" https://github.com/golang/go/wiki/Modules#gomod This patch was tested with the following repo: git@github.com:alexellis/golang-middleware-relative-import.git * Documentation in the README has been updated * Tested e2e and with a local "go test" in GOPATH with modules turned on and Go 1.13 * Updated copy commands in Dockerfile so that they use a faster mechanism, vs creating a new container step to chown (must be tested with buildkit before merging, since buildkit did not like this approach in the past when running as a restricted user at runtime) Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- README.md | 50 +++++++++++++++++++++++++++ template/golang-middleware/Dockerfile | 17 +++++---- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 90a39eb..183c449 100644 --- a/README.md +++ b/README.md @@ -299,3 +299,53 @@ func Handle(w http.ResponseWriter, r *http.Request) { w.Write([]byte(result)) } ``` + +#### Advanced usage - Go sub-modules via `GO_REPLACE.txt` + +For this example you will need to be using Go 1.13 or newer and Go modules, enable this via `faas-cli build --build-arg GO111MODULE=on`. + +Imagine you have a package which you want to store outside of the `handler.go` file, it's another middleware which can perform an echo. + +```Golang +package handlers + +import ( + "io/ioutil" + "net/http" +) + +func Echo(w http.ResponseWriter, r *http.Request) { + + if r.Body != nil { + defer r.Body.Close() + b, _ := ioutil.ReadAll(r.Body) + w.Write(b) + } + +} +``` + +To include a relative module such as this new `handlers` package, you should create a `GO_REPLACE.txt` file as follows. + +Let's say your GOPATH for your GitHub repo is: `github.com/alexellis/vault/` and your function is called `purchase`, this makes a total path of: `github.com/alexellis/vault/purchase/` + +``` +replace github.com/alexellis/vault/purchase/handlers => ./function/handlers +``` + +Now if you want to reference the handlers package from within your `handler.go` write the following: + +```golang +package function + +import ( + "net/http" + + "github.com/alexellis/vault/purchase/handlers" +) + +func Handle(w http.ResponseWriter, r *http.Request) { + + handlers.Echo(w, r) +} +``` diff --git a/template/golang-middleware/Dockerfile b/template/golang-middleware/Dockerfile index d0b2234..18f67b4 100644 --- a/template/golang-middleware/Dockerfile +++ b/template/golang-middleware/Dockerfile @@ -12,14 +12,21 @@ RUN mkdir -p /go/src/handler WORKDIR /go/src/handler COPY . . +RUN $(cat function/GO_REPLACE.txt >> ./go.mod || exit 0) && cat go.mod + # Run a gofmt and exclude all vendored code. RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./function/vendor/*"))" || { echo "Run \"gofmt -s -w\" on your Golang code"; exit 1; } ARG GO111MODULE="off" ARG GOPROXY="" +ARG GOFLAGS="" + +WORKDIR /go/src/handler/function + +RUN go test ./... -cover +WORKDIR /go/src/handler RUN go build --ldflags "-s -w" -a -installsuffix cgo -o handler . -RUN go test handler/function/... -cover FROM alpine:3.11 # Add non root user and certs @@ -30,11 +37,9 @@ RUN apk --no-cache add ca-certificates \ WORKDIR /home/app -COPY --from=build /go/src/handler/handler . -COPY --from=build /usr/bin/fwatchdog . -COPY --from=build /go/src/handler/function/ . - -RUN chown -R app /home/app +COPY --from=build --chown=app /go/src/handler/handler . +COPY --from=build --chown=app /usr/bin/fwatchdog . +COPY --from=build --chown=app /go/src/handler/function/ . USER app From dbd7189b2dc6ebc7cc01cd4a1f3a5a17b03b6293 Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Fri, 24 Jan 2020 11:22:07 +0000 Subject: [PATCH 2/3] Remove verbose statement Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- README.md | 4 +++- template/golang-middleware/Dockerfile | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 183c449..8ebe885 100644 --- a/README.md +++ b/README.md @@ -327,7 +327,9 @@ func Echo(w http.ResponseWriter, r *http.Request) { To include a relative module such as this new `handlers` package, you should create a `GO_REPLACE.txt` file as follows. -Let's say your GOPATH for your GitHub repo is: `github.com/alexellis/vault/` and your function is called `purchase`, this makes a total path of: `github.com/alexellis/vault/purchase/` +Let's say your GOPATH for your GitHub repo is: `github.com/alexellis/vault/` and your OpenFaaS function is `purchase` generated by `faas-cli new purchase --lang golang-middleware`. + +Your relative GOPATH is: `github.com/alexellis/vault/purchase`, so add a redirect as per below to redirect the "handlers" package to where it exists in the build container. ``` replace github.com/alexellis/vault/purchase/handlers => ./function/handlers diff --git a/template/golang-middleware/Dockerfile b/template/golang-middleware/Dockerfile index 18f67b4..694be1d 100644 --- a/template/golang-middleware/Dockerfile +++ b/template/golang-middleware/Dockerfile @@ -12,7 +12,8 @@ RUN mkdir -p /go/src/handler WORKDIR /go/src/handler COPY . . -RUN $(cat function/GO_REPLACE.txt >> ./go.mod || exit 0) && cat go.mod +# Add user overrides to the root go.mod, which is the only place "replace" can be used +RUN cat function/GO_REPLACE.txt >> ./go.mod || exit 0 # Run a gofmt and exclude all vendored code. RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./function/vendor/*"))" || { echo "Run \"gofmt -s -w\" on your Golang code"; exit 1; } From c199c1a6a5da6e49cd38982fa464edf93b7305ea Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Fri, 24 Jan 2020 11:35:03 +0000 Subject: [PATCH 3/3] Update ordering of GO_REPLACE statements Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8ebe885..a5dd6d3 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ func Handle(w http.ResponseWriter, r *http.Request) { For this example you will need to be using Go 1.13 or newer and Go modules, enable this via `faas-cli build --build-arg GO111MODULE=on`. -Imagine you have a package which you want to store outside of the `handler.go` file, it's another middleware which can perform an echo. +Imagine you have a package which you want to store outside of the `handler.go` file, it's another middleware which can perform an echo of the user's input. ```Golang package handlers @@ -315,26 +315,25 @@ import ( ) func Echo(w http.ResponseWriter, r *http.Request) { - if r.Body != nil { defer r.Body.Close() b, _ := ioutil.ReadAll(r.Body) w.Write(b) } - } ``` -To include a relative module such as this new `handlers` package, you should create a `GO_REPLACE.txt` file as follows. - -Let's say your GOPATH for your GitHub repo is: `github.com/alexellis/vault/` and your OpenFaaS function is `purchase` generated by `faas-cli new purchase --lang golang-middleware`. - -Your relative GOPATH is: `github.com/alexellis/vault/purchase`, so add a redirect as per below to redirect the "handlers" package to where it exists in the build container. +To include a relative module such as this new `handlers` package, you should create a `GO_REPLACE.txt` file as follows: ``` replace github.com/alexellis/vault/purchase/handlers => ./function/handlers ``` +How did we get to that? Let's say your GOPATH for your GitHub repo is: `github.com/alexellis/vault/` and your OpenFaaS function is `purchase` generated by `faas-cli new purchase --lang golang-middleware`. + +Your relative GOPATH is: `github.com/alexellis/vault/purchase`, so add a redirect as per below to redirect the "handlers" package to where it exists in the build container. + + Now if you want to reference the handlers package from within your `handler.go` write the following: ```golang