Tests for OpenWhisk NodeJS Runtime using Knative

Test summary

Running the Tests

This is the typical process for running each of the tests under this directory.

Pre-requisite

kubectl get buildtemplate
NAME                       CREATED AT
openwhisk-nodejs-runtime   10m

Configure and Deploy Build YAML

export DOCKER_USERNAME="myusername"
sed 's/${DOCKER_USERNAME}/'"$DOCKER_USERNAME"'/' build.yaml.tmpl > build.yaml
kubectl apply -f build.yaml

Configure and Deploy Service YAML

export DOCKER_USERNAME="myusername"
sed 's/${DOCKER_USERNAME}/'"$DOCKER_USERNAME"'/' service.yaml.tmpl > service.yaml
kubectl apply -f service.yaml

Running the Test on different platforms

Depending on the value you set in buildtemplate.yaml for the OW_RUNTIME_PLATFORM parameter, you will need to invoke different endpoints to execute the test.

Currently, the following platform (values) are supported:

  • openwhisk
  • knative

Running with OW_RUNTIME_PLATFORM set to “knative”

Under the Knative platform, the developer has 2 choices:

  1. Use the Knative “build” step to “bake the function” into the runtime resulting in a dedicated runtime (service) container for your running a specific function.
  2. Use Knative build to create a “stem cell” runtime that allows some control plane to inject the function dynamically.

The test case cases under this directory presume option 2 (“stem cells”) where both the both runtime initialization, as well as function execution (Activation) happen sequentially.

However, as OW runtimes do not allow “re-initialization” at this time, once you send the “init data” once to the runtime you cannot send it again or it will result in an error.

Below are some options for invoking the endpoint (route) manually using common developer tooling in conjunction with prepared data:

Using the ‘curl’ command

Simply send the “init-run” data to the base ‘/’ route on the runtime (service) endpoint.

If your function requires no input data on the request:

curl -H "Host: <hostname>" -X POST http://localhost/

otherwise, you can supply the request data and Content-Type on the command and pass the JSON data to your function via data file:

curl -H "Host: <hostname>" -d "@data-init-run.json" -H "Content-Type: application/json" http://localhost/

Using Http Clients

If using an IDE such as VSCode or IntelliJ you can simply “run” the HTTP payload files named ‘payload-knative-init-run.http’ which both initializes the runtime with the function and configuration and executes the function with the provided “values” data.

For example, the HelloWorld with parameters payload looks like this:

POST http://localhost:8080/ HTTP/1.1
content-type: application/json

{
  "init": {
    "name": "nodejs-helloworld",
    "main": "main",
    "binary": false,
    "code": "function main() {return {payload: 'Hello World!'};}"
  },
  "activation": {
    "namespace": "default",
    "action_name": "nodejs-helloworld",
    "api_host": "",
    "api_key": "",
    "activation_id": "",
    "deadline": "4102498800000"
  },
  "value": {
    "name": "Joe",
    "place": "TX"
  }
}

please note that the “activation” data is also provided, but defaulted in most cases as these would be provided by a control-plane which would manage pools of the runtimes and track Activations.


Running with OW_RUNTIME_PLATFORM set to “openwhisk”

The standard OW methods used to run functions is done through calls to 2 separate endpoints. In short, The control plane would:

  1. first, invoke the /init route with strictly the OW “init. data” (JSON format) including the functional code itself.
  2. then, invoke /run route which executes the function (i.e., Activates the function) with caller-provided parameters via OW “value data” (JSON format) along with per-activation information which would normally be provided and tracked by the control plane (default/dummy key-values provided for tests).

Below are some options for invoking these routes manually using common developer tooling in conjunction with prepared data:

Using the ‘curl’ command

Initialize the runtime

Initialize the runtime with the function and other configuration data using the /init endpoint.

curl -H "Host: <hostname>" -d "@data-init.json" -H "Content-Type: application/json" http://localhost/init

Run the function

Execute the function using the /run endpoint.

with no request data:

curl -H "Host: <hostname>" -X POST http://localhost/run

or with request data and its Content-Type:

curl -H "Host: <hostname>" -d "@data-run.json" -H "Content-Type: <content-type>" -X POST http://localhost/run

Troubleshooting

Pod will not Terminate

In some cases, you may need to force the pod to be deleted when the normal delete shown below does not work.

# Normal service delete
kubectl delete -f service.yaml

you will see something like the following for a long period of time:

$ kubectl get pods --namespace default

NAME                                                  READY   STATUS      RESTARTS   AGE
nodejs-helloworld-00001-deployment-78c6bfbf4c-8cgtd   2/3     Terminating  0         81s

In this case, you can force the pod with your service to delete as follows:

kubectl delete pod nodejs-helloworld-00001-deployment-78c6bfbf4c-8cgtd --grace-period=0 --force

Also, be sure your service is completely deleted from the system:

kubectl delete -f service.yaml