Create Function

Create a function with fission fn create, route HTTP traffic to it, test it, and update its code through the everyday function workflow.

This page walks you through the everyday function workflow: create a function, route HTTP traffic to it, test it, update its code, and inspect it. To choose how a function runs and scales, see Controlling Function Execution.

Create a function

Before creating a function, you’ll need an environment; read environments if you haven’t already.

Let’s create an environment for our function.

$ fission env create --name node --image ghcr.io/fission/node-env

Let’s create a simple code snippet in NodeJS which will output the string "Hello, world!":

module.exports = async function(context) {
    return {
        status: 200,
        body: "Hello, world!\n"
    };
}

Let’s create this function on the cluster. This only registers the function with Fission, it doesn’t run it yet.

$ fission fn create --name hello --code hello.js --env node

Next, let’s create a route for the function which can be used for making HTTP requests:

$ fission route create --function hello --url /hello --name hello

trigger '5327e9a7-6d87-4533-a4fb-c67f55b1e492' created

Setup FISSION_ROUTER environment variable if you haven’t already.

When you hit this function’s URL, you get the expected response:

$ curl http://${FISSION_ROUTER}/hello

Hello, world!
To add authentication to your function calls, refer to the Fission Authentication guide.

You can also create a function with the newdeploy executor type and set the minimum and maximum number of function instances. See Controlling Function Execution for how each executor type scales.

$ fission fn create --name hello2 --code hello.js --env node --minscale 1 --maxscale 5  --executortype newdeploy

View & update function source code

You can look at the source code associated with given function:

$ fission fn get --name hello
module.exports = async function(context) {
    return {
        status: 200,
        body: "Hello, world!\n"
    };
}

Let’s say you want to update the function to output “Hello Fission” instead of “Hello world”.

module.exports = async function(context) {
    return {
        status: 200,
        body: "Hello, Fission!\n"
    };
}

You can update the source file and update the source code for function:

$ fission fn update --name hello --code hello.js

package 'hello-js-ku9s' updated
function 'hello' updated

Let’s verify that the function now responds with a different output than it did earlier:

$ curl http://${FISSION_ROUTER}/hello

Hello, Fission!

Test and debug function

You can run a function using the test command. If the function call succeeds, it will output the function’s response:

$ fission fn test --name hello

Hello, Fission!

But if there is an error in the function’s execution (it returns HTTP >= 300), then the logs of function execution are displayed:

$ fission fn test --name hello

Error calling function hello: 500 Internal server error (fission)

> fission-nodejs-runtime@0.1.0 start /usr/src/app
> node server.js

Codepath defaulting to  /userfunc/user
Port defaulting to 8888
user code load error: SyntaxError: Unexpected token function
::ffff:10.8.1.181 - - [16/Feb/2018:08:44:33 +0000] "POST /specialize HTTP/1.1" 500 2 "-" "Go-http-client/1.1"

You can also look at function execution logs explicitly:

$ fission fn logs --name hello

[2018-02-16 08:41:43 +0000 UTC] 2018/02/16 08:41:43 fetcher received fetch request and started downloading: {1 {hello-js-rqew  default    0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] nil [] }   user [] []}
[2018-02-16 08:41:43 +0000 UTC] 2018/02/16 08:41:43 Successfully placed at /userfunc/user
[2018-02-16 08:41:43 +0000 UTC] 2018/02/16 08:41:43 Checking secrets/cfgmaps
[2018-02-16 08:41:43 +0000 UTC] 2018/02/16 08:41:43 Completed fetch request
[2018-02-16 08:41:43 +0000 UTC] 2018/02/16 08:41:43 elapsed time in fetch request = 89.844653ms
[2018-02-16 08:41:43 +0000 UTC] user code loaded in 0sec 4.235593ms
[2018-02-16 08:41:43 +0000 UTC] ::ffff:10.8.1.181 - - [16/Feb/2018:08:41:43 +0000] "POST /specialize HTTP/1.1" 202 - "-" "Go-http-client/1.1"
[2018-02-16 08:41:43 +0000 UTC] ::ffff:10.8.1.182 - - [16/Feb/2018:08:41:43 +0000] "GET / HTTP/1.1" 200 16 "-" "curl/7.54.0"

Fission builds & compiled artifacts

Most real-world functions span more than one source file. Fission provides first-class support for building from source, so you can hand it source files directly instead of precompiling a deployment artifact yourself. It also supports using compiled artifacts to create functions.

You can attach the source/deployment packages to a function or explicitly create packages and use them across functions. Check documentation for package for more information.

Building functions from source

Let’s take a simple python function which has dependency on a python pyyaml module. We can specify the dependencies in requirements.txt and a simple command to build from source. The tree structure of directory looks like:

sourcepkg/
├── __init__.py
├── build.sh
├── requirements.txt
└── user.py

And the file contents:

$ cat user.py

import sys
import yaml

document = """
  a: 1
  b:
    c: 3
    d: 4
"""

def main():
    return yaml.dump(yaml.load(document))

$ cat requirements.txt
pyyaml

$ cat build.sh
#!/bin/sh
pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG}

Make sure the build.sh file is executable:

$ chmod +x build.sh

You first need to create an environment with environment image and python-builder image specified:

$ fission env create --name python --image ghcr.io/fission/python-env \
                     --builder ghcr.io/fission/python-builder \
                     --mincpu 40 --maxcpu 80 \
                     --minmemory 64 --maxmemory 128 \
                     --version 3 --poolsize 2

Now let’s zip the directory containing the source files and create a function with source package:

$ zip -jr demo-src-pkg.zip sourcepkg/
  adding: __init__.py (stored 0%)
  adding: build.sh (deflated 24%)
  adding: requirements.txt (stored 0%)
  adding: user.py (deflated 25%)

$ fission fn create --name hellopy --env python --src demo-src-pkg.zip  --entrypoint "user.main" --buildcmd "./build.sh"
function 'hellopy' created

$ fission route create --function hellopy --url /hellopy

Once we create the function, the build process is started. You can check logs of the builder in default namespace:

$ kubectl logs -f py3-4214348-59555d9bd8-ks7m4 builder

2018/02/16 11:44:21 Builder received request: {demo-src-pkg-zip-ninf-djtswo ./build.sh}
2018/02/16 11:44:21 Starting build...

=== Build Logs ===command=./build.sh
env=[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=py3-4214348-59555d9bd8-ks7m4 PYTHON_4212095_PORT_8000_TCP_PROTO=tcp PY3_4214348_SERVICE_HOST=10.11.250.161 KUBERNETES_PORT=tcp://10.11.240.1:443 PYTHON_4212095_PORT=tcp://10.11.244.134:8000 PYTHON_4212095_PORT_8000_TCP=tcp://10.11.244.134:8000 PYTHON_4212095_PORT_8001_TCP_PROTO=tcp PYTHON_4212095_PORT_8001_TCP_ADDR=10.11.244.134 PY3_4214348_SERVICE_PORT=8000 PY3_4214348_SERVICE_PORT_BUILDER_PORT=8001 PY3_4214348_PORT_8001_TCP=tcp://10.11.250.161:8001 KUBERNETES_PORT_443_TCP_PORT=443 KUBERNETES_PORT_443_TCP_ADDR=10.11.240.1 PY3_4214348_SERVICE_PORT_FETCHER_PORT=8000 PY3_4214348_PORT_8000_TCP=tcp://10.11.250.161:8000 PY3_4214348_PORT_8001_TCP_PORT=8001 PYTHON_4212095_SERVICE_PORT_FETCHER_PORT=8000 PYTHON_4212095_PORT_8000_TCP_ADDR=10.11.244.134 KUBERNETES_SERVICE_HOST=10.11.240.1 PY3_4214348_PORT=tcp://10.11.250.161:8000 PYTHON_4212095_SERVICE_PORT_BUILDER_PORT=8001 PYTHON_4212095_PORT_8001_TCP=tcp://10.11.244.134:8001 PY3_4214348_PORT_8000_TCP_PROTO=tcp PY3_4214348_PORT_8000_TCP_PORT=8000 KUBERNETES_SERVICE_PORT_HTTPS=443 KUBERNETES_PORT_443_TCP=tcp://10.11.240.1:443 PYTHON_4212095_PORT_8001_TCP_PORT=8001 PY3_4214348_PORT_8000_TCP_ADDR=10.11.250.161 PY3_4214348_PORT_8001_TCP_PROTO=tcp KUBERNETES_SERVICE_PORT=443 PYTHON_4212095_SERVICE_PORT=8000 PYTHON_4212095_PORT_8000_TCP_PORT=8000 PY3_4214348_PORT_8001_TCP_ADDR=10.11.250.161 KUBERNETES_PORT_443_TCP_PROTO=tcp PYTHON_4212095_SERVICE_HOST=10.11.244.134 HOME=/root SRC_PKG=/packages/demo-src-pkg-zip-ninf-djtswo DEPLOY_PKG=/packages/demo-src-pkg-zip-ninf-djtswo-c40gfu]
Collecting pyyaml (from -r /packages/demo-src-pkg-zip-ninf-djtswo/requirements.txt (line 1))
  Downloading PyYAML-3.12.tar.gz (253kB)
Installing collected packages: pyyaml
  Running setup.py install for pyyaml: started
    Running setup.py install for pyyaml: finished with status 'done'
Successfully installed pyyaml-3.12
==================
2018/02/16 11:44:24 elapsed time in build request = 3.460498847s

Once the build has succeeded, you can hit the function URL to test the function:

$ curl http://$FISSION_ROUTER/hellopy

a: 1
b: {c: 3, d: 4}

If you’re using Fission with source code, be sure to read about the recommended development workflow.

Using compiled artifacts with Fission

In some cases you have a pre-built deployment package which you need to deploy to Fission. For this example let’s use a simple python file as a deployment package but in practice it can be any other compiled package.

We will use a simple python file in a directory and turn it into a deployment package:

$ cat testDir/hello.py

def main():
    return "Hello, world!"

$ zip -jr demo-deploy-pkg.zip testDir/

Let’s use the deployment package to create a function and route and then test it.

$ fission fn create --name hellopy --env python --deploy demo-deploy-pkg.zip --entrypoint "hello.main"

function 'hellopy' created

$ fission route create --function hellopy --url /hellopy

$ curl http://$FISSION_ROUTER/hellopy

Hello, world!

View function information

You can retrieve metadata for a single function, or list all functions to see their basic information:

$ fission fn getmeta --name hello

NAME  UID                                  ENV
hello 34234b50-12f5-11e8-85c9-42010aa00010 node

$ fission fn list

NAME   UID                                  ENV  EXECUTORTYPE MINSCALE MAXSCALE TARGETCPU
hello  34234b50-12f5-11e8-85c9-42010aa00010 node poolmgr      1        1        80
hello2 e37a46e3-12f4-11e8-85c9-42010aa00010 node newdeploy    1        5        80