A function as a Glue

Besides writing a simple processor, the technique in this section is one of the simplest forms of using functions. We have a bank backend with REST APIs exposed. So we write a function as a Glue to hide the complex interface of the backend. In this example, we use Go as the language to implement the function.

The scenario is that we have a REST API server and we want to unify it with another similar service. In the example in this chapter, we have two banking backends with different ways of interaction. The first one is a web-based UI without a REST interface, another one is the REST API in this section:

func main() {
input := os.Args[1]

// OpenWhisk params are key/value paris
params := map[string]interface{}{}
err := json.Unmarshal([]byte(input), params)
if err != nil {
fmt.Printf(`{"error":"%s", "input": "%s"}`, err.Error(), string(input))
os.Exit(-1)
}

entry := Entry{
Account: Account{
Id: params["accountId"].(string),
},
Amount: params["amount"].(float64),
}

jsonValue, err := json.Marshal(entry)
if err != nil {
fmt.Printf(`{"error":"%s"}`, err.Error())
os.Exit(-1)
}

accountService := os.Getenv("ACCOUNT_SERVICE")
if accountService == "" {
accountService = "http://accounting:8080/entries"
}

resp, err := http.Post(accountService,
"application/json",
bytes.NewBuffer(jsonValue))

if err != nil {
fmt.Printf(`{"error":"%s"}`, err.Error())
os.Exit(-1)
}

if resp.StatusCode >= 200 resp.StatusCode <= 299 {
fmt.Println(`{"success": "ok"}`)
os.Exit(0)
}

fmt.Printf(`{"error": "%s"}`, resp.Status)
}

We use the multi-stage build. The go build command used here in the first stage is to produce static binary. Then we copy it to the second stage, /action/exec:

# Stage 0
FROM golang:1.8.5-alpine3.6

WORKDIR /go/src/app
COPY account_ctl.go .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-extldflags "-static"' -o exec account_ctl.go

# Stage 1
FROM openwhisk/dockerskeleton

ENV FLASK_PROXY_PORT 8080

COPY --from=0 /go/src/app/exec /action/
RUN chmod +x /action/exec

CMD ["/bin/bash", "-c", "cd actionProxy python -u actionproxy.py"]
Do not forget to push the image onto Docker Hub before proceeding to the next step.

Then we define the function using wsk CLI commands:

$ docker build -t chanwit/account_ctl:v1 .
$ docker push chanwit/account_ctl:v1

$ wsk -i action delete account_ctl
$ wsk -i action create --docker=chanwit/account_ctl:v1 account_ctl

To make a container able to talk to other FaaS platform gateways, we need to change the OpenWhisk invoker's configuration to start every container inside the parse_net network. The invoker image is fixed to 3a7dce and the OpenWhisk network configuration in the environment variable section of the invoker service, CONFIG_whisk_containerFactory_containerArgs_network, is set to parse_net:

invoker:
image: openwhisk/invoker@sha256:3a7dcee078905b47306f3f06c78eee53372a4a9bf47cdd8eafe0194745a9b8d6
command: /bin/sh -c "exec /init.sh 0 >> /logs/invoker-local_logs.log 2> 1"
privileged: true
pid: "host"
userns_mode: "host"
links:
- db:db.docker
- kafka:kafka.docker
- zookeeper:zookeeper.docker
depends_on:
- db
- kafka
env_file:
- ./docker-whisk-controller.env # env vars shared
- ~/tmp/openwhisk/local.env # generated during make setup
environment:
COMPONENT_NAME: invoker
SERVICE_NAME: invoker0
PORT: 8085

KAFKA_HOSTS: kafka.docker:9092
ZOOKEEPER_HOSTS: zookeeper.docker:2181

DB_PROVIDER: CouchDB
DB_PROTOCOL: http
DB_PORT: 5984
DB_HOST: db.docker
DB_USERNAME: whisk_admin
DB_PASSWORD: some_passw0rd

EDGE_HOST: ${DOCKER_COMPOSE_HOST}
EDGE_HOST_APIPORT: 443

CONFIG_whisk_containerFactory_containerArgs_network: parse_net

WHISK_API_HOST_NAME: ${DOCKER_COMPOSE_HOST}
volumes:
- ~/tmp/openwhisk/invoker/logs:/logs
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/containers:/containers
- /sys/fs/cgroup:/sys/fs/cgroup
ports:
- "8085:8085"

To unify them, we create a function to wrap around the REST API and make both of the interfaces as similar as possible.

To start the REST API server, we use the docker run command and attach it to the parse_net with the accounting alias. Port 18080 is published for debugging purposes only:

docker run -p 18080:8080 -d 
--network=parse_net
--network-alias=accounting
--name accounting
chanwit/accounting:0.1
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset