openfaas / faas

OpenFaaS - Serverless Functions Made Simple
https://www.openfaas.com
MIT License
25.12k stars 1.93k forks source link

Support question - Golang usage #566

Closed losintikfos closed 6 years ago

losintikfos commented 6 years ago

The call to types.UnmarshalRequest(bytes) is returning empty struct.

Expected Behaviour

Struct object with non empty values. Including non empty HTTP header and request data.

Current Behaviour

bytes, _ := ioutil.ReadAll(os.Stdin)
fmt.Println("HELLO -> ", string(bytes))
req, err := types.UnmarshalRequest(bytes)
fmt.Println("REQ=", req)

Request:

curl -H "Content-Type: application/json" -X POST \
 -H "X-Api-Key: Wrong_Key" -d '{"msg": "Hello World"}' \
  http://localhost:8080/function/my_service

Print 1 result HELLO -> {"msg": "Hello World"}

Print 2 result: REQ= &{map[] {[]}}

Possible Solution

Steps to Reproduce (for bugs)

  1. Dockerfile
    
    FROM alpine:latest
    RUN apk --no-cache add make curl \
    && curl -sL https://github.com/openfaas/faas/releases/download/0.7.3/fwatchdog > /usr/bin/fwatchdog \
    && chmod +x /usr/bin/fwatchdog

Needed to reach the hub

RUN apk --no-cache add ca-certificates COPY manager /usr/bin/

ENV fprocess "/usr/bin/my_service"

CMD ["/usr/bin/fwatchdog"]


2. **Build script** 

faas-cli remove my_service docker rmi functions/my_service:latest

CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o my_service . echo Building functions/my_service:latest docker build --no-cache -t functions/my_service:latest .

secret_env="secret_api_key" docker secret remove "${secret_env}" echo "R^YqzKzSJw51K9zPpQ3R3N" | docker secret create ${secret_env} - faas-cli deploy -f ./my_service.yml --secret ${secret_env}

rm my_service



## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->

## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* Docker version `docker version` (e.g. Docker 17.0.05 ):
--- `Docker version 17.12.1-ce, build 7390fc6`

* Are you using Docker Swarm or Kubernetes (FaaS-netes)?
--- `Docker Swarm`

* Operating System and version (e.g. Linux, Windows, MacOS):
--- `Linux`

* Link to your project or a code example to reproduce issue:

* Please also follow the [troubleshooting guide](https://github.com/openfaas/faas/blob/master/guide/troubleshooting.md) and paste in any other diagnostic information you have:
alexellis commented 6 years ago

Hi thanks for logging an issue.

I'm not sure what the problem is here. Can you summarize?

What is this line supposed to be doing and where is it being saved?

CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o my_service .

When you say:

The call to types.UnmarshalRequest(bytes) is returning empty struct.

What call, where? How are you invoking it?

Are you using a sample function or your own code? Do you have the code available on GitHub so we can try to reproduce the error?

losintikfos commented 6 years ago

The call:

 CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o my_service .

builds my_service to local machine and then copies the built my_service app onto the container due to other dependent local modules I do not want to recursively copy onto the container before building.

The example handler I am using is as shown below taken from ApiKeyProtected:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "github.com/openfaas/faas/watchdog/types"
)

func handle(header http.Header, body []byte) {
    key := header.Get("X-Api-Key")
    fmt.Println("KEY --> ", key)
    fmt.Println(header)
    if (len(key) > 0) && (key == os.Getenv("secret_api_key")) {
        fmt.Println("Unlocked the function!")
    } else {
        fmt.Println("Access denied!")
    }
}

func main() {
    bytes, _ := ioutil.ReadAll(os.Stdin)
    fmt.Println("HELLO -> ", string(bytes))
    req, err := types.UnmarshalRequest(bytes)
    fmt.Println(req)
    if err != nil {
        fmt.Println(err)
        log.Fatal(err)
    }

    handle(req.Header, req.Body.Raw)
}

The call to req, err := types.UnmarshalRequest(bytes) returns a struct with empty Map and Header data.

alexellis commented 6 years ago

To write a Golang function please follow the official method:

faas new --lang go <function_name>

To access HTTP headers look at os.Getenv("Http_X_Key_Here") where that represents a header such as X-Key-Here in `curl localhost:8080/function/ -H "X-Key-Here: value".

For more on how to read headers from the watchdog see the documentation here

For a detailed tutorial / blog post on how to create a function in Go using the CLI see here:

https://blog.alexellis.io/serverless-golang-with-openfaas/

On the sample / example

I'd like to understand why you don't want to use the faas-cli to create / build / manage your functions.

I've converted the ApiKeyProtected-Secrets to use the faas-cli template system, the result is below:

https://github.com/openfaas/faas/tree/master/sample-functions/apikey-secret

losintikfos commented 6 years ago

@alexellis let me take this opportunity to thank you and the major contributors for the good work.

I am following the example project apikey-secret to adapt to my requirement which is to pre-build my app on local machine and export the built app to the container to be invoke by watchdog.

So far I am getting somewhere following your guide. My question here though is - will the call below (note the flag --secret):

   faas-cli deploy --filter apikey-secret --secret secret_api_key

Ensure that the container already has the file /run/secrets/secret_api_key available or do I need to force create this?

I have looked at the Secrets Management Guide and doesn't hint on this much.

Many thanks.

alexellis commented 6 years ago

You don't need to force anything but you do need to create your secrets inside the cluster before you can reference them.

The example has been updated to make things clearer - https://github.com/openfaas/faas/tree/master/sample-functions/apikey-secret#trying-the-sample

Hope this helps?

I'll close the issue but you can keep commenting as you need.